diff options
author | Eric Sandeen <sandeen@redhat.com> | 2011-02-12 08:12:18 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2011-02-12 08:12:18 -0500 |
commit | 2892c15ddda6a76dc10b7499e56c0f3b892e5a69 (patch) | |
tree | bd2aa2add525d91991975e5678ef5bfe9175bdd8 /fs | |
parent | d50bdd5aa55127635fd8a5c74bd2abb256bd34e3 (diff) |
ext4: make grpinfo slab cache names static
In 2.6.37 I was running into oopses with repeated module
loads & unloads. I tracked this down to:
fb1813f4 ext4: use dedicated slab caches for group_info structures
(this was in addition to the features advert unload problem)
The kstrdup & subsequent kfree of the cache name was causing
a double free. In slub, at least, if I read it right it allocates
& frees the name itself, slab seems to do something different...
so in slub I think we were leaking -our- cachep->name, and double
freeing the one allocated by slub.
After getting lost in slab/slub/slob a bit, I just looked at other
sized-caches that get allocated. jbd2, biovec, sgpool all do it
more or less the way jbd2 does. Below patch follows the jbd2
method of dynamically allocating a cache at mount time from
a list of static names.
(This might also possibly fix a race creating the caches with
parallel mounts running).
[Folded in a fix from Dan Carpenter which fixed an off-by-one error in
the original patch]
Cc: stable@kernel.org
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/mballoc.c | 100 |
1 files changed, 60 insertions, 40 deletions
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 851f49b2f9d2..d1fe09aea73d 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -342,10 +342,15 @@ static struct kmem_cache *ext4_free_ext_cachep; | |||
342 | /* We create slab caches for groupinfo data structures based on the | 342 | /* We create slab caches for groupinfo data structures based on the |
343 | * superblock block size. There will be one per mounted filesystem for | 343 | * superblock block size. There will be one per mounted filesystem for |
344 | * each unique s_blocksize_bits */ | 344 | * each unique s_blocksize_bits */ |
345 | #define NR_GRPINFO_CACHES \ | 345 | #define NR_GRPINFO_CACHES 8 |
346 | (EXT4_MAX_BLOCK_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE + 1) | ||
347 | static struct kmem_cache *ext4_groupinfo_caches[NR_GRPINFO_CACHES]; | 346 | static struct kmem_cache *ext4_groupinfo_caches[NR_GRPINFO_CACHES]; |
348 | 347 | ||
348 | static const char *ext4_groupinfo_slab_names[NR_GRPINFO_CACHES] = { | ||
349 | "ext4_groupinfo_1k", "ext4_groupinfo_2k", "ext4_groupinfo_4k", | ||
350 | "ext4_groupinfo_8k", "ext4_groupinfo_16k", "ext4_groupinfo_32k", | ||
351 | "ext4_groupinfo_64k", "ext4_groupinfo_128k" | ||
352 | }; | ||
353 | |||
349 | static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, | 354 | static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, |
350 | ext4_group_t group); | 355 | ext4_group_t group); |
351 | static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap, | 356 | static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap, |
@@ -2414,6 +2419,55 @@ err_freesgi: | |||
2414 | return -ENOMEM; | 2419 | return -ENOMEM; |
2415 | } | 2420 | } |
2416 | 2421 | ||
2422 | static void ext4_groupinfo_destroy_slabs(void) | ||
2423 | { | ||
2424 | int i; | ||
2425 | |||
2426 | for (i = 0; i < NR_GRPINFO_CACHES; i++) { | ||
2427 | if (ext4_groupinfo_caches[i]) | ||
2428 | kmem_cache_destroy(ext4_groupinfo_caches[i]); | ||
2429 | ext4_groupinfo_caches[i] = NULL; | ||
2430 | } | ||
2431 | } | ||
2432 | |||
2433 | static int ext4_groupinfo_create_slab(size_t size) | ||
2434 | { | ||
2435 | static DEFINE_MUTEX(ext4_grpinfo_slab_create_mutex); | ||
2436 | int slab_size; | ||
2437 | int blocksize_bits = order_base_2(size); | ||
2438 | int cache_index = blocksize_bits - EXT4_MIN_BLOCK_LOG_SIZE; | ||
2439 | struct kmem_cache *cachep; | ||
2440 | |||
2441 | if (cache_index >= NR_GRPINFO_CACHES) | ||
2442 | return -EINVAL; | ||
2443 | |||
2444 | if (unlikely(cache_index < 0)) | ||
2445 | cache_index = 0; | ||
2446 | |||
2447 | mutex_lock(&ext4_grpinfo_slab_create_mutex); | ||
2448 | if (ext4_groupinfo_caches[cache_index]) { | ||
2449 | mutex_unlock(&ext4_grpinfo_slab_create_mutex); | ||
2450 | return 0; /* Already created */ | ||
2451 | } | ||
2452 | |||
2453 | slab_size = offsetof(struct ext4_group_info, | ||
2454 | bb_counters[blocksize_bits + 2]); | ||
2455 | |||
2456 | cachep = kmem_cache_create(ext4_groupinfo_slab_names[cache_index], | ||
2457 | slab_size, 0, SLAB_RECLAIM_ACCOUNT, | ||
2458 | NULL); | ||
2459 | |||
2460 | mutex_unlock(&ext4_grpinfo_slab_create_mutex); | ||
2461 | if (!cachep) { | ||
2462 | printk(KERN_EMERG "EXT4: no memory for groupinfo slab cache\n"); | ||
2463 | return -ENOMEM; | ||
2464 | } | ||
2465 | |||
2466 | ext4_groupinfo_caches[cache_index] = cachep; | ||
2467 | |||
2468 | return 0; | ||
2469 | } | ||
2470 | |||
2417 | int ext4_mb_init(struct super_block *sb, int needs_recovery) | 2471 | int ext4_mb_init(struct super_block *sb, int needs_recovery) |
2418 | { | 2472 | { |
2419 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 2473 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
@@ -2421,9 +2475,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery) | |||
2421 | unsigned offset; | 2475 | unsigned offset; |
2422 | unsigned max; | 2476 | unsigned max; |
2423 | int ret; | 2477 | int ret; |
2424 | int cache_index; | ||
2425 | struct kmem_cache *cachep; | ||
2426 | char *namep = NULL; | ||
2427 | 2478 | ||
2428 | i = (sb->s_blocksize_bits + 2) * sizeof(*sbi->s_mb_offsets); | 2479 | i = (sb->s_blocksize_bits + 2) * sizeof(*sbi->s_mb_offsets); |
2429 | 2480 | ||
@@ -2440,30 +2491,9 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery) | |||
2440 | goto out; | 2491 | goto out; |
2441 | } | 2492 | } |
2442 | 2493 | ||
2443 | cache_index = sb->s_blocksize_bits - EXT4_MIN_BLOCK_LOG_SIZE; | 2494 | ret = ext4_groupinfo_create_slab(sb->s_blocksize); |
2444 | cachep = ext4_groupinfo_caches[cache_index]; | 2495 | if (ret < 0) |
2445 | if (!cachep) { | 2496 | goto out; |
2446 | char name[32]; | ||
2447 | int len = offsetof(struct ext4_group_info, | ||
2448 | bb_counters[sb->s_blocksize_bits + 2]); | ||
2449 | |||
2450 | sprintf(name, "ext4_groupinfo_%d", sb->s_blocksize_bits); | ||
2451 | namep = kstrdup(name, GFP_KERNEL); | ||
2452 | if (!namep) { | ||
2453 | ret = -ENOMEM; | ||
2454 | goto out; | ||
2455 | } | ||
2456 | |||
2457 | /* Need to free the kmem_cache_name() when we | ||
2458 | * destroy the slab */ | ||
2459 | cachep = kmem_cache_create(namep, len, 0, | ||
2460 | SLAB_RECLAIM_ACCOUNT, NULL); | ||
2461 | if (!cachep) { | ||
2462 | ret = -ENOMEM; | ||
2463 | goto out; | ||
2464 | } | ||
2465 | ext4_groupinfo_caches[cache_index] = cachep; | ||
2466 | } | ||
2467 | 2497 | ||
2468 | /* order 0 is regular bitmap */ | 2498 | /* order 0 is regular bitmap */ |
2469 | sbi->s_mb_maxs[0] = sb->s_blocksize << 3; | 2499 | sbi->s_mb_maxs[0] = sb->s_blocksize << 3; |
@@ -2520,7 +2550,6 @@ out: | |||
2520 | if (ret) { | 2550 | if (ret) { |
2521 | kfree(sbi->s_mb_offsets); | 2551 | kfree(sbi->s_mb_offsets); |
2522 | kfree(sbi->s_mb_maxs); | 2552 | kfree(sbi->s_mb_maxs); |
2523 | kfree(namep); | ||
2524 | } | 2553 | } |
2525 | return ret; | 2554 | return ret; |
2526 | } | 2555 | } |
@@ -2734,7 +2763,6 @@ int __init ext4_init_mballoc(void) | |||
2734 | 2763 | ||
2735 | void ext4_exit_mballoc(void) | 2764 | void ext4_exit_mballoc(void) |
2736 | { | 2765 | { |
2737 | int i; | ||
2738 | /* | 2766 | /* |
2739 | * Wait for completion of call_rcu()'s on ext4_pspace_cachep | 2767 | * Wait for completion of call_rcu()'s on ext4_pspace_cachep |
2740 | * before destroying the slab cache. | 2768 | * before destroying the slab cache. |
@@ -2743,15 +2771,7 @@ void ext4_exit_mballoc(void) | |||
2743 | kmem_cache_destroy(ext4_pspace_cachep); | 2771 | kmem_cache_destroy(ext4_pspace_cachep); |
2744 | kmem_cache_destroy(ext4_ac_cachep); | 2772 | kmem_cache_destroy(ext4_ac_cachep); |
2745 | kmem_cache_destroy(ext4_free_ext_cachep); | 2773 | kmem_cache_destroy(ext4_free_ext_cachep); |
2746 | 2774 | ext4_groupinfo_destroy_slabs(); | |
2747 | for (i = 0; i < NR_GRPINFO_CACHES; i++) { | ||
2748 | struct kmem_cache *cachep = ext4_groupinfo_caches[i]; | ||
2749 | if (cachep) { | ||
2750 | char *name = (char *)kmem_cache_name(cachep); | ||
2751 | kmem_cache_destroy(cachep); | ||
2752 | kfree(name); | ||
2753 | } | ||
2754 | } | ||
2755 | ext4_remove_debugfs_entry(); | 2775 | ext4_remove_debugfs_entry(); |
2756 | } | 2776 | } |
2757 | 2777 | ||