]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.12-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 20 Aug 2017 18:33:04 +0000 (11:33 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 20 Aug 2017 18:33:04 +0000 (11:33 -0700)
added patches:
alsa-seq-2nd-attempt-at-fixing-race-creating-a-queue.patch
alsa-usb-audio-add-dsd-support-for-new-amanero-pid.patch
alsa-usb-audio-add-mute-tlv-for-playback-volumes-on-c-media-devices.patch
alsa-usb-audio-apply-sample-rate-quirk-to-sennheiser-headset.patch
mm-discard-memblock-data-later.patch
slub-fix-per-memcg-cache-leak-on-css-offline.patch

queue-4.12/alsa-seq-2nd-attempt-at-fixing-race-creating-a-queue.patch [new file with mode: 0644]
queue-4.12/alsa-usb-audio-add-dsd-support-for-new-amanero-pid.patch [new file with mode: 0644]
queue-4.12/alsa-usb-audio-add-mute-tlv-for-playback-volumes-on-c-media-devices.patch [new file with mode: 0644]
queue-4.12/alsa-usb-audio-apply-sample-rate-quirk-to-sennheiser-headset.patch [new file with mode: 0644]
queue-4.12/mm-discard-memblock-data-later.patch [new file with mode: 0644]
queue-4.12/series
queue-4.12/slub-fix-per-memcg-cache-leak-on-css-offline.patch [new file with mode: 0644]

diff --git a/queue-4.12/alsa-seq-2nd-attempt-at-fixing-race-creating-a-queue.patch b/queue-4.12/alsa-seq-2nd-attempt-at-fixing-race-creating-a-queue.patch
new file mode 100644 (file)
index 0000000..8482ed3
--- /dev/null
@@ -0,0 +1,127 @@
+From 7e1d90f60a0d501c8503e636942ca704a454d910 Mon Sep 17 00:00:00 2001
+From: Daniel Mentz <danielmentz@google.com>
+Date: Mon, 14 Aug 2017 14:46:01 -0700
+Subject: ALSA: seq: 2nd attempt at fixing race creating a queue
+
+From: Daniel Mentz <danielmentz@google.com>
+
+commit 7e1d90f60a0d501c8503e636942ca704a454d910 upstream.
+
+commit 4842e98f26dd80be3623c4714a244ba52ea096a8 ("ALSA: seq: Fix race at
+creating a queue") attempted to fix a race reported by syzkaller. That
+fix has been described as follows:
+
+"
+When a sequencer queue is created in snd_seq_queue_alloc(),it adds the
+new queue element to the public list before referencing it.  Thus the
+queue might be deleted before the call of snd_seq_queue_use(), and it
+results in the use-after-free error, as spotted by syzkaller.
+
+The fix is to reference the queue object at the right time.
+"
+
+Even with that fix in place, syzkaller reported a use-after-free error.
+It specifically pointed to the last instruction "return q->queue" in
+snd_seq_queue_alloc(). The pointer q is being used after kfree() has
+been called on it.
+
+It turned out that there is still a small window where a race can
+happen. The window opens at
+snd_seq_ioctl_create_queue()->snd_seq_queue_alloc()->queue_list_add()
+and closes at
+snd_seq_ioctl_create_queue()->queueptr()->snd_use_lock_use(). Between
+these two calls, a different thread could delete the queue and possibly
+re-create a different queue in the same location in queue_list.
+
+This change prevents this situation by calling snd_use_lock_use() from
+snd_seq_queue_alloc() prior to calling queue_list_add(). It is then the
+caller's responsibility to call snd_use_lock_free(&q->use_lock).
+
+Fixes: 4842e98f26dd ("ALSA: seq: Fix race at creating a queue")
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Daniel Mentz <danielmentz@google.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/seq/seq_clientmgr.c |   13 ++++---------
+ sound/core/seq/seq_queue.c     |   14 +++++++++-----
+ sound/core/seq/seq_queue.h     |    2 +-
+ 3 files changed, 14 insertions(+), 15 deletions(-)
+
+--- a/sound/core/seq/seq_clientmgr.c
++++ b/sound/core/seq/seq_clientmgr.c
+@@ -1502,16 +1502,11 @@ static int snd_seq_ioctl_unsubscribe_por
+ static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg)
+ {
+       struct snd_seq_queue_info *info = arg;
+-      int result;
+       struct snd_seq_queue *q;
+-      result = snd_seq_queue_alloc(client->number, info->locked, info->flags);
+-      if (result < 0)
+-              return result;
+-
+-      q = queueptr(result);
+-      if (q == NULL)
+-              return -EINVAL;
++      q = snd_seq_queue_alloc(client->number, info->locked, info->flags);
++      if (IS_ERR(q))
++              return PTR_ERR(q);
+       info->queue = q->queue;
+       info->locked = q->locked;
+@@ -1521,7 +1516,7 @@ static int snd_seq_ioctl_create_queue(st
+       if (!info->name[0])
+               snprintf(info->name, sizeof(info->name), "Queue-%d", q->queue);
+       strlcpy(q->name, info->name, sizeof(q->name));
+-      queuefree(q);
++      snd_use_lock_free(&q->use_lock);
+       return 0;
+ }
+--- a/sound/core/seq/seq_queue.c
++++ b/sound/core/seq/seq_queue.c
+@@ -184,22 +184,26 @@ void __exit snd_seq_queues_delete(void)
+ static void queue_use(struct snd_seq_queue *queue, int client, int use);
+ /* allocate a new queue -
+- * return queue index value or negative value for error
++ * return pointer to new queue or ERR_PTR(-errno) for error
++ * The new queue's use_lock is set to 1. It is the caller's responsibility to
++ * call snd_use_lock_free(&q->use_lock).
+  */
+-int snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
++struct snd_seq_queue *snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
+ {
+       struct snd_seq_queue *q;
+       q = queue_new(client, locked);
+       if (q == NULL)
+-              return -ENOMEM;
++              return ERR_PTR(-ENOMEM);
+       q->info_flags = info_flags;
+       queue_use(q, client, 1);
++      snd_use_lock_use(&q->use_lock);
+       if (queue_list_add(q) < 0) {
++              snd_use_lock_free(&q->use_lock);
+               queue_delete(q);
+-              return -ENOMEM;
++              return ERR_PTR(-ENOMEM);
+       }
+-      return q->queue;
++      return q;
+ }
+ /* delete a queue - queue must be owned by the client */
+--- a/sound/core/seq/seq_queue.h
++++ b/sound/core/seq/seq_queue.h
+@@ -71,7 +71,7 @@ void snd_seq_queues_delete(void);
+ /* create new queue (constructor) */
+-int snd_seq_queue_alloc(int client, int locked, unsigned int flags);
++struct snd_seq_queue *snd_seq_queue_alloc(int client, int locked, unsigned int flags);
+ /* delete queue (destructor) */
+ int snd_seq_queue_delete(int client, int queueid);
diff --git a/queue-4.12/alsa-usb-audio-add-dsd-support-for-new-amanero-pid.patch b/queue-4.12/alsa-usb-audio-add-dsd-support-for-new-amanero-pid.patch
new file mode 100644 (file)
index 0000000..75e158b
--- /dev/null
@@ -0,0 +1,34 @@
+From ed993c6fdfa7734881a4516852d95ae2d3b604d3 Mon Sep 17 00:00:00 2001
+From: Jussi Laako <jussi@sonarnerd.net>
+Date: Fri, 18 Aug 2017 10:42:14 +0300
+Subject: ALSA: usb-audio: add DSD support for new Amanero PID
+
+From: Jussi Laako <jussi@sonarnerd.net>
+
+commit ed993c6fdfa7734881a4516852d95ae2d3b604d3 upstream.
+
+Add DSD support for new Amanero Combo384 firmware version with a new
+PID. This firmware uses DSD_U32_BE.
+
+Fixes: 3eff682d765b ("ALSA: usb-audio: Support both DSD LE/BE Amanero firmware versions")
+Signed-off-by: Jussi Laako <jussi@sonarnerd.net>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/quirks.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -1375,6 +1375,10 @@ u64 snd_usb_interface_dsd_format_quirks(
+                       }
+               }
+               break;
++      case USB_ID(0x16d0, 0x0a23):
++              if (fp->altsetting == 2)
++                      return SNDRV_PCM_FMTBIT_DSD_U32_BE;
++              break;
+       default:
+               break;
diff --git a/queue-4.12/alsa-usb-audio-add-mute-tlv-for-playback-volumes-on-c-media-devices.patch b/queue-4.12/alsa-usb-audio-add-mute-tlv-for-playback-volumes-on-c-media-devices.patch
new file mode 100644 (file)
index 0000000..2444262
--- /dev/null
@@ -0,0 +1,65 @@
+From 0f174b3525a43bd51f9397394763925e0ebe7bc7 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Wed, 16 Aug 2017 14:18:37 +0200
+Subject: ALSA: usb-audio: Add mute TLV for playback volumes on C-Media devices
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 0f174b3525a43bd51f9397394763925e0ebe7bc7 upstream.
+
+C-Media devices (at least some models) mute the playback stream when
+volumes are set to the minimum value.  But this isn't informed via TLV
+and the user-space, typically PulseAudio, gets confused as if it's
+still played in a low volume.
+
+This patch adds the new flag, min_mute, to struct usb_mixer_elem_info
+for indicating that the mixer element is with the minimum-mute volume.
+This flag is set for known C-Media devices in
+snd_usb_mixer_fu_apply_quirk() in turn.
+
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196669
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/mixer.c        |    2 ++
+ sound/usb/mixer.h        |    1 +
+ sound/usb/mixer_quirks.c |    6 ++++++
+ 3 files changed, 9 insertions(+)
+
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -542,6 +542,8 @@ int snd_usb_mixer_vol_tlv(struct snd_kco
+       if (size < sizeof(scale))
+               return -ENOMEM;
++      if (cval->min_mute)
++              scale[0] = SNDRV_CTL_TLVT_DB_MINMAX_MUTE;
+       scale[2] = cval->dBmin;
+       scale[3] = cval->dBmax;
+       if (copy_to_user(_tlv, scale, sizeof(scale)))
+--- a/sound/usb/mixer.h
++++ b/sound/usb/mixer.h
+@@ -64,6 +64,7 @@ struct usb_mixer_elem_info {
+       int cached;
+       int cache_val[MAX_CHANNELS];
+       u8 initialized;
++      u8 min_mute;
+       void *private_data;
+ };
+--- a/sound/usb/mixer_quirks.c
++++ b/sound/usb/mixer_quirks.c
+@@ -1878,6 +1878,12 @@ void snd_usb_mixer_fu_apply_quirk(struct
+               if (unitid == 7 && cval->control == UAC_FU_VOLUME)
+                       snd_dragonfly_quirk_db_scale(mixer, cval, kctl);
+               break;
++      /* lowest playback value is muted on C-Media devices */
++      case USB_ID(0x0d8c, 0x000c):
++      case USB_ID(0x0d8c, 0x0014):
++              if (strstr(kctl->id.name, "Playback"))
++                      cval->min_mute = 1;
++              break;
+       }
+ }
diff --git a/queue-4.12/alsa-usb-audio-apply-sample-rate-quirk-to-sennheiser-headset.patch b/queue-4.12/alsa-usb-audio-apply-sample-rate-quirk-to-sennheiser-headset.patch
new file mode 100644 (file)
index 0000000..54a150d
--- /dev/null
@@ -0,0 +1,35 @@
+From a8e800fe0f68bc28ce309914f47e432742b865ed Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 14 Aug 2017 14:35:50 +0200
+Subject: ALSA: usb-audio: Apply sample rate quirk to Sennheiser headset
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit a8e800fe0f68bc28ce309914f47e432742b865ed upstream.
+
+A Senheisser headset requires the typical sample-rate quirk for
+avoiding spurious errors from inquiring the current sample rate like:
+ usb 1-1: 2:1: cannot get freq at ep 0x4
+ usb 1-1: 3:1: cannot get freq at ep 0x83
+
+The USB ID 1395:740a has to be added to the entries in
+snd_usb_get_sample_rate_quirk().
+
+Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1052580
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/quirks.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -1142,6 +1142,7 @@ bool snd_usb_get_sample_rate_quirk(struc
+       case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */
+       case USB_ID(0x05A3, 0x9420): /* ELP HD USB Camera */
+       case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
++      case USB_ID(0x1395, 0x740a): /* Sennheiser DECT */
+       case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */
+       case USB_ID(0x1de7, 0x0013): /* Phoenix Audio MT202exe */
+       case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */
diff --git a/queue-4.12/mm-discard-memblock-data-later.patch b/queue-4.12/mm-discard-memblock-data-later.patch
new file mode 100644 (file)
index 0000000..97ddbca
--- /dev/null
@@ -0,0 +1,176 @@
+From 3010f876500f9ba921afaeccec30c45ca6584dc8 Mon Sep 17 00:00:00 2001
+From: Pavel Tatashin <pasha.tatashin@oracle.com>
+Date: Fri, 18 Aug 2017 15:16:05 -0700
+Subject: mm: discard memblock data later
+
+From: Pavel Tatashin <pasha.tatashin@oracle.com>
+
+commit 3010f876500f9ba921afaeccec30c45ca6584dc8 upstream.
+
+There is existing use after free bug when deferred struct pages are
+enabled:
+
+The memblock_add() allocates memory for the memory array if more than
+128 entries are needed.  See comment in e820__memblock_setup():
+
+  * The bootstrap memblock region count maximum is 128 entries
+  * (INIT_MEMBLOCK_REGIONS), but EFI might pass us more E820 entries
+  * than that - so allow memblock resizing.
+
+This memblock memory is freed here:
+        free_low_memory_core_early()
+
+We access the freed memblock.memory later in boot when deferred pages
+are initialized in this path:
+
+        deferred_init_memmap()
+                for_each_mem_pfn_range()
+                  __next_mem_pfn_range()
+                    type = &memblock.memory;
+
+One possible explanation for why this use-after-free hasn't been hit
+before is that the limit of INIT_MEMBLOCK_REGIONS has never been
+exceeded at least on systems where deferred struct pages were enabled.
+
+Tested by reducing INIT_MEMBLOCK_REGIONS down to 4 from the current 128,
+and verifying in qemu that this code is getting excuted and that the
+freed pages are sane.
+
+Link: http://lkml.kernel.org/r/1502485554-318703-2-git-send-email-pasha.tatashin@oracle.com
+Fixes: 7e18adb4f80b ("mm: meminit: initialise remaining struct pages in parallel with kswapd")
+Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
+Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
+Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
+Reviewed-by: Bob Picco <bob.picco@oracle.com>
+Acked-by: Michal Hocko <mhocko@suse.com>
+Cc: Mel Gorman <mgorman@techsingularity.net>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/linux/memblock.h |    6 ++++--
+ mm/memblock.c            |   40 ++++++++++++++++++----------------------
+ mm/nobootmem.c           |   16 ----------------
+ mm/page_alloc.c          |    4 ++++
+ 4 files changed, 26 insertions(+), 40 deletions(-)
+
+--- a/include/linux/memblock.h
++++ b/include/linux/memblock.h
+@@ -65,6 +65,7 @@ extern bool movable_node_enabled;
+ #ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
+ #define __init_memblock __meminit
+ #define __initdata_memblock __meminitdata
++void memblock_discard(void);
+ #else
+ #define __init_memblock
+ #define __initdata_memblock
+@@ -78,8 +79,6 @@ phys_addr_t memblock_find_in_range_node(
+                                       int nid, ulong flags);
+ phys_addr_t memblock_find_in_range(phys_addr_t start, phys_addr_t end,
+                                  phys_addr_t size, phys_addr_t align);
+-phys_addr_t get_allocated_memblock_reserved_regions_info(phys_addr_t *addr);
+-phys_addr_t get_allocated_memblock_memory_regions_info(phys_addr_t *addr);
+ void memblock_allow_resize(void);
+ int memblock_add_node(phys_addr_t base, phys_addr_t size, int nid);
+ int memblock_add(phys_addr_t base, phys_addr_t size);
+@@ -114,6 +113,9 @@ void __next_mem_range_rev(u64 *idx, int
+ void __next_reserved_mem_region(u64 *idx, phys_addr_t *out_start,
+                               phys_addr_t *out_end);
++void __memblock_free_early(phys_addr_t base, phys_addr_t size);
++void __memblock_free_late(phys_addr_t base, phys_addr_t size);
++
+ /**
+  * for_each_mem_range - iterate through memblock areas from type_a and not
+  * included in type_b. Or just type_a if type_b is NULL.
+--- a/mm/memblock.c
++++ b/mm/memblock.c
+@@ -288,31 +288,27 @@ static void __init_memblock memblock_rem
+ }
+ #ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
+-
+-phys_addr_t __init_memblock get_allocated_memblock_reserved_regions_info(
+-                                      phys_addr_t *addr)
+-{
+-      if (memblock.reserved.regions == memblock_reserved_init_regions)
+-              return 0;
+-
+-      *addr = __pa(memblock.reserved.regions);
+-
+-      return PAGE_ALIGN(sizeof(struct memblock_region) *
+-                        memblock.reserved.max);
+-}
+-
+-phys_addr_t __init_memblock get_allocated_memblock_memory_regions_info(
+-                                      phys_addr_t *addr)
++/**
++ * Discard memory and reserved arrays if they were allocated
++ */
++void __init memblock_discard(void)
+ {
+-      if (memblock.memory.regions == memblock_memory_init_regions)
+-              return 0;
++      phys_addr_t addr, size;
+-      *addr = __pa(memblock.memory.regions);
+-
+-      return PAGE_ALIGN(sizeof(struct memblock_region) *
+-                        memblock.memory.max);
++      if (memblock.reserved.regions != memblock_reserved_init_regions) {
++              addr = __pa(memblock.reserved.regions);
++              size = PAGE_ALIGN(sizeof(struct memblock_region) *
++                                memblock.reserved.max);
++              __memblock_free_late(addr, size);
++      }
++
++      if (memblock.memory.regions == memblock_memory_init_regions) {
++              addr = __pa(memblock.memory.regions);
++              size = PAGE_ALIGN(sizeof(struct memblock_region) *
++                                memblock.memory.max);
++              __memblock_free_late(addr, size);
++      }
+ }
+-
+ #endif
+ /**
+--- a/mm/nobootmem.c
++++ b/mm/nobootmem.c
+@@ -146,22 +146,6 @@ static unsigned long __init free_low_mem
+                               NULL)
+               count += __free_memory_core(start, end);
+-#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
+-      {
+-              phys_addr_t size;
+-
+-              /* Free memblock.reserved array if it was allocated */
+-              size = get_allocated_memblock_reserved_regions_info(&start);
+-              if (size)
+-                      count += __free_memory_core(start, start + size);
+-
+-              /* Free memblock.memory array if it was allocated */
+-              size = get_allocated_memblock_memory_regions_info(&start);
+-              if (size)
+-                      count += __free_memory_core(start, start + size);
+-      }
+-#endif
+-
+       return count;
+ }
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -1582,6 +1582,10 @@ void __init page_alloc_init_late(void)
+       /* Reinit limits that are based on free pages after the kernel is up */
+       files_maxfiles_init();
+ #endif
++#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
++      /* Discard memblock private memory */
++      memblock_discard();
++#endif
+       for_each_populated_zone(zone)
+               set_zone_contiguous(zone);
index 66660e9c52467ba66b3a7387dc98994b6fcd3fba..66447c29b9ce21d4f67413ede7a737f305795525 100644 (file)
@@ -9,3 +9,9 @@ input-elan_i2c-add-antoher-lenovo-acpi-id-for-upcoming-lenovo-nb.patch
 md-fix-test-in-md_write_start.patch
 md-always-clear-safemode-when-md_check_recovery-gets-the-mddev-lock.patch
 md-not-clear-safemode-for-external-metadata-array.patch
+alsa-seq-2nd-attempt-at-fixing-race-creating-a-queue.patch
+alsa-usb-audio-apply-sample-rate-quirk-to-sennheiser-headset.patch
+alsa-usb-audio-add-mute-tlv-for-playback-volumes-on-c-media-devices.patch
+alsa-usb-audio-add-dsd-support-for-new-amanero-pid.patch
+mm-discard-memblock-data-later.patch
+slub-fix-per-memcg-cache-leak-on-css-offline.patch
diff --git a/queue-4.12/slub-fix-per-memcg-cache-leak-on-css-offline.patch b/queue-4.12/slub-fix-per-memcg-cache-leak-on-css-offline.patch
new file mode 100644 (file)
index 0000000..2259426
--- /dev/null
@@ -0,0 +1,98 @@
+From f6ba488073fe8159851fe398cc3c5ee383bb4c7a Mon Sep 17 00:00:00 2001
+From: Vladimir Davydov <vdavydov.dev@gmail.com>
+Date: Fri, 18 Aug 2017 15:16:08 -0700
+Subject: slub: fix per memcg cache leak on css offline
+
+From: Vladimir Davydov <vdavydov.dev@gmail.com>
+
+commit f6ba488073fe8159851fe398cc3c5ee383bb4c7a upstream.
+
+To avoid a possible deadlock, sysfs_slab_remove() schedules an
+asynchronous work to delete sysfs entries corresponding to the kmem
+cache.  To ensure the cache isn't freed before the work function is
+called, it takes a reference to the cache kobject.  The reference is
+supposed to be released by the work function.
+
+However, the work function (sysfs_slab_remove_workfn()) does nothing in
+case the cache sysfs entry has already been deleted, leaking the kobject
+and the corresponding cache.
+
+This may happen on a per memcg cache destruction, because sysfs entries
+of a per memcg cache are deleted on memcg offline if the cache is empty
+(see __kmemcg_cache_deactivate()).
+
+The kmemleak report looks like this:
+
+  unreferenced object 0xffff9f798a79f540 (size 32):
+    comm "kworker/1:4", pid 15416, jiffies 4307432429 (age 28687.554s)
+    hex dump (first 32 bytes):
+      6b 6d 61 6c 6c 6f 63 2d 31 36 28 31 35 39 39 3a  kmalloc-16(1599:
+      6e 65 77 72 6f 6f 74 29 00 23 6b c0 ff ff ff ff  newroot).#k.....
+    backtrace:
+       kmemleak_alloc+0x4a/0xa0
+       __kmalloc_track_caller+0x148/0x2c0
+       kvasprintf+0x66/0xd0
+       kasprintf+0x49/0x70
+       memcg_create_kmem_cache+0xe6/0x160
+       memcg_kmem_cache_create_func+0x20/0x110
+       process_one_work+0x205/0x5d0
+       worker_thread+0x4e/0x3a0
+       kthread+0x109/0x140
+       ret_from_fork+0x2a/0x40
+  unreferenced object 0xffff9f79b6136840 (size 416):
+    comm "kworker/1:4", pid 15416, jiffies 4307432429 (age 28687.573s)
+    hex dump (first 32 bytes):
+      40 fb 80 c2 3e 33 00 00 00 00 00 40 00 00 00 00  @...>3.....@....
+      00 00 00 00 00 00 00 00 10 00 00 00 10 00 00 00  ................
+    backtrace:
+       kmemleak_alloc+0x4a/0xa0
+       kmem_cache_alloc+0x128/0x280
+       create_cache+0x3b/0x1e0
+       memcg_create_kmem_cache+0x118/0x160
+       memcg_kmem_cache_create_func+0x20/0x110
+       process_one_work+0x205/0x5d0
+       worker_thread+0x4e/0x3a0
+       kthread+0x109/0x140
+       ret_from_fork+0x2a/0x40
+
+Fix the leak by adding the missing call to kobject_put() to
+sysfs_slab_remove_workfn().
+
+Link: http://lkml.kernel.org/r/20170812181134.25027-1-vdavydov.dev@gmail.com
+Fixes: 3b7b314053d02 ("slub: make sysfs file removal asynchronous")
+Signed-off-by: Vladimir Davydov <vdavydov.dev@gmail.com>
+Reported-by: Andrei Vagin <avagin@gmail.com>
+Tested-by: Andrei Vagin <avagin@gmail.com>
+Acked-by: Tejun Heo <tj@kernel.org>
+Acked-by: David Rientjes <rientjes@google.com>
+Cc: Michal Hocko <mhocko@kernel.org>
+Cc: Johannes Weiner <hannes@cmpxchg.org>
+Cc: Christoph Lameter <cl@linux.com>
+Cc: Pekka Enberg <penberg@kernel.org>
+Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ mm/slub.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/mm/slub.c
++++ b/mm/slub.c
+@@ -5637,13 +5637,14 @@ static void sysfs_slab_remove_workfn(str
+                * A cache is never shut down before deactivation is
+                * complete, so no need to worry about synchronization.
+                */
+-              return;
++              goto out;
+ #ifdef CONFIG_MEMCG
+       kset_unregister(s->memcg_kset);
+ #endif
+       kobject_uevent(&s->kobj, KOBJ_REMOVE);
+       kobject_del(&s->kobj);
++out:
+       kobject_put(&s->kobj);
+ }