diff options
author | Jan Kara <jack@suse.cz> | 2012-12-31 06:38:36 -0500 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2013-01-21 05:19:55 -0500 |
commit | f56426ae4d4414c9c996567710dceecbdfc39acc (patch) | |
tree | 1ef907778df97d0ac0c0a680d5a44280324ad1cb /fs/ext3/super.c | |
parent | 306a74920ba9ccf6b5f110f97c1cb6bb2caeff93 (diff) |
ext3: Fix memory leak when quota options are specified multiple times
When usrjquota or grpjquota mount options are specified several times,
we leak memory storing the names. Free the memory correctly.
Reported-by: Chen Gang <gang.chen@asianux.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/ext3/super.c')
-rw-r--r-- | fs/ext3/super.c | 51 |
1 files changed, 30 insertions, 21 deletions
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 6e50223b3299..0926fe46ae3e 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
@@ -916,21 +916,24 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args) | |||
916 | "Not enough memory for storing quotafile name"); | 916 | "Not enough memory for storing quotafile name"); |
917 | return 0; | 917 | return 0; |
918 | } | 918 | } |
919 | if (sbi->s_qf_names[qtype] && | 919 | if (sbi->s_qf_names[qtype]) { |
920 | strcmp(sbi->s_qf_names[qtype], qname)) { | 920 | int same = !strcmp(sbi->s_qf_names[qtype], qname); |
921 | ext3_msg(sb, KERN_ERR, | 921 | |
922 | "%s quota file already specified", QTYPE2NAME(qtype)); | ||
923 | kfree(qname); | 922 | kfree(qname); |
924 | return 0; | 923 | if (!same) { |
924 | ext3_msg(sb, KERN_ERR, | ||
925 | "%s quota file already specified", | ||
926 | QTYPE2NAME(qtype)); | ||
927 | } | ||
928 | return same; | ||
925 | } | 929 | } |
926 | sbi->s_qf_names[qtype] = qname; | 930 | if (strchr(qname, '/')) { |
927 | if (strchr(sbi->s_qf_names[qtype], '/')) { | ||
928 | ext3_msg(sb, KERN_ERR, | 931 | ext3_msg(sb, KERN_ERR, |
929 | "quotafile must be on filesystem root"); | 932 | "quotafile must be on filesystem root"); |
930 | kfree(sbi->s_qf_names[qtype]); | 933 | kfree(qname); |
931 | sbi->s_qf_names[qtype] = NULL; | ||
932 | return 0; | 934 | return 0; |
933 | } | 935 | } |
936 | sbi->s_qf_names[qtype] = qname; | ||
934 | set_opt(sbi->s_mount_opt, QUOTA); | 937 | set_opt(sbi->s_mount_opt, QUOTA); |
935 | return 1; | 938 | return 1; |
936 | } | 939 | } |
@@ -945,11 +948,10 @@ static int clear_qf_name(struct super_block *sb, int qtype) { | |||
945 | " when quota turned on"); | 948 | " when quota turned on"); |
946 | return 0; | 949 | return 0; |
947 | } | 950 | } |
948 | /* | 951 | if (sbi->s_qf_names[qtype]) { |
949 | * The space will be released later when all options are confirmed | 952 | kfree(sbi->s_qf_names[qtype]); |
950 | * to be correct | 953 | sbi->s_qf_names[qtype] = NULL; |
951 | */ | 954 | } |
952 | sbi->s_qf_names[qtype] = NULL; | ||
953 | return 1; | 955 | return 1; |
954 | } | 956 | } |
955 | #endif | 957 | #endif |
@@ -2605,7 +2607,18 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) | |||
2605 | #ifdef CONFIG_QUOTA | 2607 | #ifdef CONFIG_QUOTA |
2606 | old_opts.s_jquota_fmt = sbi->s_jquota_fmt; | 2608 | old_opts.s_jquota_fmt = sbi->s_jquota_fmt; |
2607 | for (i = 0; i < MAXQUOTAS; i++) | 2609 | for (i = 0; i < MAXQUOTAS; i++) |
2608 | old_opts.s_qf_names[i] = sbi->s_qf_names[i]; | 2610 | if (sbi->s_qf_names[i]) { |
2611 | old_opts.s_qf_names[i] = kstrdup(sbi->s_qf_names[i], | ||
2612 | GFP_KERNEL); | ||
2613 | if (!old_opts.s_qf_names[i]) { | ||
2614 | int j; | ||
2615 | |||
2616 | for (j = 0; j < i; j++) | ||
2617 | kfree(old_opts.s_qf_names[j]); | ||
2618 | return -ENOMEM; | ||
2619 | } | ||
2620 | } else | ||
2621 | old_opts.s_qf_names[i] = NULL; | ||
2609 | #endif | 2622 | #endif |
2610 | 2623 | ||
2611 | /* | 2624 | /* |
@@ -2698,9 +2711,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) | |||
2698 | #ifdef CONFIG_QUOTA | 2711 | #ifdef CONFIG_QUOTA |
2699 | /* Release old quota file names */ | 2712 | /* Release old quota file names */ |
2700 | for (i = 0; i < MAXQUOTAS; i++) | 2713 | for (i = 0; i < MAXQUOTAS; i++) |
2701 | if (old_opts.s_qf_names[i] && | 2714 | kfree(old_opts.s_qf_names[i]); |
2702 | old_opts.s_qf_names[i] != sbi->s_qf_names[i]) | ||
2703 | kfree(old_opts.s_qf_names[i]); | ||
2704 | #endif | 2715 | #endif |
2705 | if (enable_quota) | 2716 | if (enable_quota) |
2706 | dquot_resume(sb, -1); | 2717 | dquot_resume(sb, -1); |
@@ -2714,9 +2725,7 @@ restore_opts: | |||
2714 | #ifdef CONFIG_QUOTA | 2725 | #ifdef CONFIG_QUOTA |
2715 | sbi->s_jquota_fmt = old_opts.s_jquota_fmt; | 2726 | sbi->s_jquota_fmt = old_opts.s_jquota_fmt; |
2716 | for (i = 0; i < MAXQUOTAS; i++) { | 2727 | for (i = 0; i < MAXQUOTAS; i++) { |
2717 | if (sbi->s_qf_names[i] && | 2728 | kfree(sbi->s_qf_names[i]); |
2718 | old_opts.s_qf_names[i] != sbi->s_qf_names[i]) | ||
2719 | kfree(sbi->s_qf_names[i]); | ||
2720 | sbi->s_qf_names[i] = old_opts.s_qf_names[i]; | 2729 | sbi->s_qf_names[i] = old_opts.s_qf_names[i]; |
2721 | } | 2730 | } |
2722 | #endif | 2731 | #endif |