Pull slab fix from Vlastimil Babka: - A fix from Waiman Long to avoid a theoretical deadlock reported by lockdep. * tag 'slab-for-6.0-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab: mm/slab_common: Deleting kobject in kmem_cache_destroy() without holding slab_mutex/cpu_hotplug_lock
Unified · Split
| @@ -392,6 +392,28 @@ kmem_cache_create(const char *name, unsigned int size, unsigned int align, · 391 unmodified lines | ||
| 392 | 392 | } |
| 393 | 393 | EXPORT_SYMBOL(kmem_cache_create); |
| 394 | 394 | |
| 395 | +#ifdef SLAB_SUPPORTS_SYSFS | |
| 396 | +/* | |
| 397 | + * For a given kmem_cache, kmem_cache_destroy() should only be called | |
| 398 | + * once or there will be a use-after-free problem. The actual deletion | |
| 399 | + * and release of the kobject does not need slab_mutex or cpu_hotplug_lock | |
| 400 | + * protection. So they are now done without holding those locks. | |
| 401 | + * | |
| 402 | + * Note that there will be a slight delay in the deletion of sysfs files | |
| 403 | + * if kmem_cache_release() is called indrectly from a work function. | |
| 404 | + */ | |
| 405 | +static void kmem_cache_release(struct kmem_cache *s) | |
| 406 | +{ | |
| 407 | + sysfs_slab_unlink(s); | |
| 408 | + sysfs_slab_release(s); | |
| 409 | +} | |
| 410 | +#else | |
| 411 | +static void kmem_cache_release(struct kmem_cache *s) | |
| 412 | +{ | |
| 413 | + slab_kmem_cache_release(s); | |
| 414 | +} | |
| 415 | +#endif | |
| 416 | + | |
| 395 | 417 | static void slab_caches_to_rcu_destroy_workfn(struct work_struct *work) |
| 396 | 418 | { |
| 397 | 419 | LIST_HEAD(to_destroy); |
| @@ -418,11 +440,7 @@ static void slab_caches_to_rcu_destroy_workfn(struct work_struct *work) · 20 unmodified lines | ||
| 418 | 440 | list_for_each_entry_safe(s, s2, &to_destroy, list) { |
| 419 | 441 | debugfs_slab_release(s); |
| 420 | 442 | kfence_shutdown_cache(s); |
| 421 | −#ifdef SLAB_SUPPORTS_SYSFS | |
| 422 | − sysfs_slab_release(s); | |
| 423 | −#else | |
| 424 | − slab_kmem_cache_release(s); | |
| 425 | −#endif | |
| 443 | + kmem_cache_release(s); | |
| 426 | 444 | } |
| 427 | 445 | } |
| 428 | 446 | |
| @@ -437,20 +455,11 @@ static int shutdown_cache(struct kmem_cache *s) · 8 unmodified lines | ||
| 437 | 455 | list_del(&s->list); |
| 438 | 456 | |
| 439 | 457 | if (s->flags & SLAB_TYPESAFE_BY_RCU) { |
| 440 | −#ifdef SLAB_SUPPORTS_SYSFS | |
| 441 | − sysfs_slab_unlink(s); | |
| 442 | −#endif | |
| 443 | 458 | list_add_tail(&s->list, &slab_caches_to_rcu_destroy); |
| 444 | 459 | schedule_work(&slab_caches_to_rcu_destroy_work); |
| 445 | 460 | } else { |
| 446 | 461 | kfence_shutdown_cache(s); |
| 447 | 462 | debugfs_slab_release(s); |
| 448 | −#ifdef SLAB_SUPPORTS_SYSFS | |
| 449 | − sysfs_slab_unlink(s); | |
| 450 | − sysfs_slab_release(s); | |
| 451 | −#else | |
| 452 | − slab_kmem_cache_release(s); | |
| 453 | −#endif | |
| 454 | 463 | } |
| 455 | 464 | |
| 456 | 465 | return 0; |
| @@ -465,14 +474,16 @@ void slab_kmem_cache_release(struct kmem_cache *s) · 8 unmodified lines | ||
| 465 | 474 | |
| 466 | 475 | void kmem_cache_destroy(struct kmem_cache *s) |
| 467 | 476 | { |
| 477 | + int refcnt; | |
| 478 | + | |
| 468 | 479 | if (unlikely(!s) || !kasan_check_byte(s)) |
| 469 | 480 | return; |
| 470 | 481 | |
| 471 | 482 | cpus_read_lock(); |
| 472 | 483 | mutex_lock(&slab_mutex); |
| 473 | 484 | |
| 474 | − s->refcount--; | |
| 475 | − if (s->refcount) | |
| 485 | + refcnt = --s->refcount; | |
| 486 | + if (refcnt) | |
| 476 | 487 | goto out_unlock; |
| 477 | 488 | |
| 478 | 489 | WARN(shutdown_cache(s), |
| @@ -481,6 +492,8 @@ void kmem_cache_destroy(struct kmem_cache *s) · 2 unmodified lines | ||
| 481 | 492 | out_unlock: |
| 482 | 493 | mutex_unlock(&slab_mutex); |
| 483 | 494 | cpus_read_unlock(); |
| 495 | + if (!refcnt && !(s->flags & SLAB_TYPESAFE_BY_RCU)) | |
| 496 | + kmem_cache_release(s); | |
| 484 | 497 | } |
| 485 | 498 | EXPORT_SYMBOL(kmem_cache_destroy); |
| 486 | 499 | |