|
6 | 6 | #include <linux/module.h>
|
7 | 7 | #include <linux/kernel.h>
|
8 | 8 | #include <linux/rcupdate.h>
|
| 9 | +#include <linux/delay.h> |
9 | 10 | #include "../mm/slab.h"
|
10 | 11 |
|
11 | 12 | static struct kunit_resource resource;
|
@@ -181,6 +182,63 @@ static void test_kfree_rcu(struct kunit *test)
|
181 | 182 | KUNIT_EXPECT_EQ(test, 0, slab_errors);
|
182 | 183 | }
|
183 | 184 |
|
| 185 | +struct cache_destroy_work { |
| 186 | + struct work_struct work; |
| 187 | + struct kmem_cache *s; |
| 188 | +}; |
| 189 | + |
| 190 | +static void cache_destroy_workfn(struct work_struct *w) |
| 191 | +{ |
| 192 | + struct cache_destroy_work *cdw; |
| 193 | + |
| 194 | + cdw = container_of(w, struct cache_destroy_work, work); |
| 195 | + kmem_cache_destroy(cdw->s); |
| 196 | +} |
| 197 | + |
| 198 | +#define KMEM_CACHE_DESTROY_NR 10 |
| 199 | + |
| 200 | +static void test_kfree_rcu_wq_destroy(struct kunit *test) |
| 201 | +{ |
| 202 | + struct test_kfree_rcu_struct *p; |
| 203 | + struct cache_destroy_work cdw; |
| 204 | + struct workqueue_struct *wq; |
| 205 | + struct kmem_cache *s; |
| 206 | + unsigned int delay; |
| 207 | + int i; |
| 208 | + |
| 209 | + if (IS_BUILTIN(CONFIG_SLUB_KUNIT_TEST)) |
| 210 | + kunit_skip(test, "can't do kfree_rcu() when test is built-in"); |
| 211 | + |
| 212 | + INIT_WORK_ONSTACK(&cdw.work, cache_destroy_workfn); |
| 213 | + wq = alloc_workqueue("test_kfree_rcu_destroy_wq", |
| 214 | + WQ_HIGHPRI | WQ_UNBOUND | WQ_MEM_RECLAIM, 0); |
| 215 | + |
| 216 | + if (!wq) |
| 217 | + kunit_skip(test, "failed to alloc wq"); |
| 218 | + |
| 219 | + for (i = 0; i < KMEM_CACHE_DESTROY_NR; i++) { |
| 220 | + s = test_kmem_cache_create("TestSlub_kfree_rcu_wq_destroy", |
| 221 | + sizeof(struct test_kfree_rcu_struct), |
| 222 | + SLAB_NO_MERGE); |
| 223 | + |
| 224 | + if (!s) |
| 225 | + kunit_skip(test, "failed to create cache"); |
| 226 | + |
| 227 | + delay = get_random_u8(); |
| 228 | + p = kmem_cache_alloc(s, GFP_KERNEL); |
| 229 | + kfree_rcu(p, rcu); |
| 230 | + |
| 231 | + cdw.s = s; |
| 232 | + |
| 233 | + msleep(delay); |
| 234 | + queue_work(wq, &cdw.work); |
| 235 | + flush_work(&cdw.work); |
| 236 | + } |
| 237 | + |
| 238 | + destroy_workqueue(wq); |
| 239 | + KUNIT_EXPECT_EQ(test, 0, slab_errors); |
| 240 | +} |
| 241 | + |
184 | 242 | static void test_leak_destroy(struct kunit *test)
|
185 | 243 | {
|
186 | 244 | struct kmem_cache *s = test_kmem_cache_create("TestSlub_leak_destroy",
|
@@ -254,6 +312,7 @@ static struct kunit_case test_cases[] = {
|
254 | 312 | KUNIT_CASE(test_clobber_redzone_free),
|
255 | 313 | KUNIT_CASE(test_kmalloc_redzone_access),
|
256 | 314 | KUNIT_CASE(test_kfree_rcu),
|
| 315 | + KUNIT_CASE(test_kfree_rcu_wq_destroy), |
257 | 316 | KUNIT_CASE(test_leak_destroy),
|
258 | 317 | KUNIT_CASE(test_krealloc_redzone_zeroing),
|
259 | 318 | {}
|
|
0 commit comments