diff options
author | Greg Thelen <gthelen@google.com> | 2013-02-22 19:36:02 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-23 20:50:23 -0500 |
commit | 49cd0a5c290f99deca3463d16c3c1c7240107889 (patch) | |
tree | 90a7f92f4b48463483644270355006419bd0f9af /mm/shmem.c | |
parent | 5f00110f7273f9ff04ac69a5f85bb535a4fd0987 (diff) |
tmpfs: fix mempolicy object leaks
Fix several mempolicy leaks in the tmpfs mount logic. These leaks are
slow - on the order of one object leaked per mount attempt.
Leak 1 (umount doesn't free mpol allocated in mount):
while true; do
mount -t tmpfs -o mpol=interleave,size=100M nodev /mnt
umount /mnt
done
Leak 2 (errors parsing remount options will leak mpol):
mount -t tmpfs -o size=100M nodev /mnt
while true; do
mount -o remount,mpol=interleave,size=x /mnt 2> /dev/null
done
umount /mnt
Leak 3 (multiple mpol per mount leak mpol):
while true; do
mount -t tmpfs -o mpol=interleave,mpol=interleave,size=100M nodev /mnt
umount /mnt
done
This patch fixes all of the above. I could have broken the patch into
three pieces but is seemed easier to review as one.
[akpm@linux-foundation.org: fix handling of mpol_parse_str() errors, per Hugh]
Signed-off-by: Greg Thelen <gthelen@google.com>
Acked-by: Hugh Dickins <hughd@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 5e2ff592e3b8..1ad79243cb7b 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -2385,6 +2385,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, | |||
2385 | bool remount) | 2385 | bool remount) |
2386 | { | 2386 | { |
2387 | char *this_char, *value, *rest; | 2387 | char *this_char, *value, *rest; |
2388 | struct mempolicy *mpol = NULL; | ||
2388 | uid_t uid; | 2389 | uid_t uid; |
2389 | gid_t gid; | 2390 | gid_t gid; |
2390 | 2391 | ||
@@ -2413,7 +2414,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, | |||
2413 | printk(KERN_ERR | 2414 | printk(KERN_ERR |
2414 | "tmpfs: No value for mount option '%s'\n", | 2415 | "tmpfs: No value for mount option '%s'\n", |
2415 | this_char); | 2416 | this_char); |
2416 | return 1; | 2417 | goto error; |
2417 | } | 2418 | } |
2418 | 2419 | ||
2419 | if (!strcmp(this_char,"size")) { | 2420 | if (!strcmp(this_char,"size")) { |
@@ -2462,19 +2463,24 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, | |||
2462 | if (!gid_valid(sbinfo->gid)) | 2463 | if (!gid_valid(sbinfo->gid)) |
2463 | goto bad_val; | 2464 | goto bad_val; |
2464 | } else if (!strcmp(this_char,"mpol")) { | 2465 | } else if (!strcmp(this_char,"mpol")) { |
2465 | if (mpol_parse_str(value, &sbinfo->mpol)) | 2466 | mpol_put(mpol); |
2467 | mpol = NULL; | ||
2468 | if (mpol_parse_str(value, &mpol)) | ||
2466 | goto bad_val; | 2469 | goto bad_val; |
2467 | } else { | 2470 | } else { |
2468 | printk(KERN_ERR "tmpfs: Bad mount option %s\n", | 2471 | printk(KERN_ERR "tmpfs: Bad mount option %s\n", |
2469 | this_char); | 2472 | this_char); |
2470 | return 1; | 2473 | goto error; |
2471 | } | 2474 | } |
2472 | } | 2475 | } |
2476 | sbinfo->mpol = mpol; | ||
2473 | return 0; | 2477 | return 0; |
2474 | 2478 | ||
2475 | bad_val: | 2479 | bad_val: |
2476 | printk(KERN_ERR "tmpfs: Bad value '%s' for mount option '%s'\n", | 2480 | printk(KERN_ERR "tmpfs: Bad value '%s' for mount option '%s'\n", |
2477 | value, this_char); | 2481 | value, this_char); |
2482 | error: | ||
2483 | mpol_put(mpol); | ||
2478 | return 1; | 2484 | return 1; |
2479 | 2485 | ||
2480 | } | 2486 | } |
@@ -2550,6 +2556,7 @@ static void shmem_put_super(struct super_block *sb) | |||
2550 | struct shmem_sb_info *sbinfo = SHMEM_SB(sb); | 2556 | struct shmem_sb_info *sbinfo = SHMEM_SB(sb); |
2551 | 2557 | ||
2552 | percpu_counter_destroy(&sbinfo->used_blocks); | 2558 | percpu_counter_destroy(&sbinfo->used_blocks); |
2559 | mpol_put(sbinfo->mpol); | ||
2553 | kfree(sbinfo); | 2560 | kfree(sbinfo); |
2554 | sb->s_fs_info = NULL; | 2561 | sb->s_fs_info = NULL; |
2555 | } | 2562 | } |