]>
Commit | Line | Data |
---|---|---|
0f714131 GKH |
1 | From d50d82faa0c964e31f7a946ba8aba7c715ca7ab0 Mon Sep 17 00:00:00 2001 |
2 | From: Mikulas Patocka <mpatocka@redhat.com> | |
3 | Date: Wed, 27 Jun 2018 23:26:09 -0700 | |
4 | Subject: slub: fix failure when we delete and create a slab cache | |
5 | ||
6 | From: Mikulas Patocka <mpatocka@redhat.com> | |
7 | ||
8 | commit d50d82faa0c964e31f7a946ba8aba7c715ca7ab0 upstream. | |
9 | ||
10 | In kernel 4.17 I removed some code from dm-bufio that did slab cache | |
11 | merging (commit 21bb13276768: "dm bufio: remove code that merges slab | |
12 | caches") - both slab and slub support merging caches with identical | |
13 | attributes, so dm-bufio now just calls kmem_cache_create and relies on | |
14 | implicit merging. | |
15 | ||
16 | This uncovered a bug in the slub subsystem - if we delete a cache and | |
17 | immediatelly create another cache with the same attributes, it fails | |
18 | because of duplicate filename in /sys/kernel/slab/. The slub subsystem | |
19 | offloads freeing the cache to a workqueue - and if we create the new | |
20 | cache before the workqueue runs, it complains because of duplicate | |
21 | filename in sysfs. | |
22 | ||
23 | This patch fixes the bug by moving the call of kobject_del from | |
24 | sysfs_slab_remove_workfn to shutdown_cache. kobject_del must be called | |
25 | while we hold slab_mutex - so that the sysfs entry is deleted before a | |
26 | cache with the same attributes could be created. | |
27 | ||
28 | Running device-mapper-test-suite with: | |
29 | ||
30 | dmtest run --suite thin-provisioning -n /commit_failure_causes_fallback/ | |
31 | ||
32 | triggered: | |
33 | ||
34 | Buffer I/O error on dev dm-0, logical block 1572848, async page read | |
35 | device-mapper: thin: 253:1: metadata operation 'dm_pool_alloc_data_block' failed: error = -5 | |
36 | device-mapper: thin: 253:1: aborting current metadata transaction | |
37 | sysfs: cannot create duplicate filename '/kernel/slab/:a-0000144' | |
38 | CPU: 2 PID: 1037 Comm: kworker/u48:1 Not tainted 4.17.0.snitm+ #25 | |
39 | Hardware name: Supermicro SYS-1029P-WTR/X11DDW-L, BIOS 2.0a 12/06/2017 | |
40 | Workqueue: dm-thin do_worker [dm_thin_pool] | |
41 | Call Trace: | |
42 | dump_stack+0x5a/0x73 | |
43 | sysfs_warn_dup+0x58/0x70 | |
44 | sysfs_create_dir_ns+0x77/0x80 | |
45 | kobject_add_internal+0xba/0x2e0 | |
46 | kobject_init_and_add+0x70/0xb0 | |
47 | sysfs_slab_add+0xb1/0x250 | |
48 | __kmem_cache_create+0x116/0x150 | |
49 | create_cache+0xd9/0x1f0 | |
50 | kmem_cache_create_usercopy+0x1c1/0x250 | |
51 | kmem_cache_create+0x18/0x20 | |
52 | dm_bufio_client_create+0x1ae/0x410 [dm_bufio] | |
53 | dm_block_manager_create+0x5e/0x90 [dm_persistent_data] | |
54 | __create_persistent_data_objects+0x38/0x940 [dm_thin_pool] | |
55 | dm_pool_abort_metadata+0x64/0x90 [dm_thin_pool] | |
56 | metadata_operation_failed+0x59/0x100 [dm_thin_pool] | |
57 | alloc_data_block.isra.53+0x86/0x180 [dm_thin_pool] | |
58 | process_cell+0x2a3/0x550 [dm_thin_pool] | |
59 | do_worker+0x28d/0x8f0 [dm_thin_pool] | |
60 | process_one_work+0x171/0x370 | |
61 | worker_thread+0x49/0x3f0 | |
62 | kthread+0xf8/0x130 | |
63 | ret_from_fork+0x35/0x40 | |
64 | kobject_add_internal failed for :a-0000144 with -EEXIST, don't try to register things with the same name in the same directory. | |
65 | kmem_cache_create(dm_bufio_buffer-16) failed with error -17 | |
66 | ||
67 | Link: http://lkml.kernel.org/r/alpine.LRH.2.02.1806151817130.6333@file01.intranet.prod.int.rdu2.redhat.com | |
68 | Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> | |
69 | Reported-by: Mike Snitzer <snitzer@redhat.com> | |
70 | Tested-by: Mike Snitzer <snitzer@redhat.com> | |
71 | Cc: Christoph Lameter <cl@linux.com> | |
72 | Cc: Pekka Enberg <penberg@kernel.org> | |
73 | Cc: David Rientjes <rientjes@google.com> | |
74 | Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> | |
75 | Cc: <stable@vger.kernel.org> | |
76 | Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | |
77 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | |
78 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
79 | ||
80 | --- | |
81 | include/linux/slub_def.h | 4 ++++ | |
82 | mm/slab_common.c | 4 ++++ | |
83 | mm/slub.c | 7 ++++++- | |
84 | 3 files changed, 14 insertions(+), 1 deletion(-) | |
85 | ||
86 | --- a/include/linux/slub_def.h | |
87 | +++ b/include/linux/slub_def.h | |
88 | @@ -151,8 +151,12 @@ struct kmem_cache { | |
89 | ||
90 | #ifdef CONFIG_SYSFS | |
91 | #define SLAB_SUPPORTS_SYSFS | |
92 | +void sysfs_slab_unlink(struct kmem_cache *); | |
93 | void sysfs_slab_release(struct kmem_cache *); | |
94 | #else | |
95 | +static inline void sysfs_slab_unlink(struct kmem_cache *s) | |
96 | +{ | |
97 | +} | |
98 | static inline void sysfs_slab_release(struct kmem_cache *s) | |
99 | { | |
100 | } | |
101 | --- a/mm/slab_common.c | |
102 | +++ b/mm/slab_common.c | |
103 | @@ -546,10 +546,14 @@ static int shutdown_cache(struct kmem_ca | |
104 | list_del(&s->list); | |
105 | ||
106 | if (s->flags & SLAB_TYPESAFE_BY_RCU) { | |
107 | +#ifdef SLAB_SUPPORTS_SYSFS | |
108 | + sysfs_slab_unlink(s); | |
109 | +#endif | |
110 | list_add_tail(&s->list, &slab_caches_to_rcu_destroy); | |
111 | schedule_work(&slab_caches_to_rcu_destroy_work); | |
112 | } else { | |
113 | #ifdef SLAB_SUPPORTS_SYSFS | |
114 | + sysfs_slab_unlink(s); | |
115 | sysfs_slab_release(s); | |
116 | #else | |
117 | slab_kmem_cache_release(s); | |
118 | --- a/mm/slub.c | |
119 | +++ b/mm/slub.c | |
120 | @@ -5660,7 +5660,6 @@ static void sysfs_slab_remove_workfn(str | |
121 | kset_unregister(s->memcg_kset); | |
122 | #endif | |
123 | kobject_uevent(&s->kobj, KOBJ_REMOVE); | |
124 | - kobject_del(&s->kobj); | |
125 | out: | |
126 | kobject_put(&s->kobj); | |
127 | } | |
128 | @@ -5745,6 +5744,12 @@ static void sysfs_slab_remove(struct kme | |
129 | schedule_work(&s->kobj_remove_work); | |
130 | } | |
131 | ||
132 | +void sysfs_slab_unlink(struct kmem_cache *s) | |
133 | +{ | |
134 | + if (slab_state >= FULL) | |
135 | + kobject_del(&s->kobj); | |
136 | +} | |
137 | + | |
138 | void sysfs_slab_release(struct kmem_cache *s) | |
139 | { | |
140 | if (slab_state >= FULL) |