From patchwork Sun Jan 20 10:11:36 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chen Gang X-Patchwork-Id: 213949 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 52E472C0084 for ; Sun, 20 Jan 2013 21:10:50 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751361Ab3ATKKt (ORCPT ); Sun, 20 Jan 2013 05:10:49 -0500 Received: from intranet.asianux.com ([58.214.24.6]:5948 "EHLO intranet.asianux.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751249Ab3ATKKs (ORCPT ); Sun, 20 Jan 2013 05:10:48 -0500 Received: by intranet.asianux.com (Postfix, from userid 103) id 0244D1840275; Sun, 20 Jan 2013 18:10:48 +0800 (CST) X-Spam-Score: -100.4 X-Spam-Checker-Version: SpamAssassin 3.1.9 (2007-02-13) on intranet.asianux.com X-Spam-Level: X-Spam-Status: No, score=-100.4 required=5.0 tests=AWL,BAYES_00, RATWARE_GECKO_BUILD, TW_JQ, TW_RJ, TW_RP, TW_SR, USER_IN_WHITELIST autolearn=no version=3.1.9 Received: from [10.1.0.143] (unknown [219.143.36.82]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by intranet.asianux.com (Postfix) with ESMTP id A05BB1840242; Sun, 20 Jan 2013 18:10:47 +0800 (CST) Message-ID: <50FBC2D8.9070807@asianux.com> Date: Sun, 20 Jan 2013 18:11:36 +0800 From: Chen Gang User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/17.0 Thunderbird/17.0 MIME-Version: 1.0 To: Theodore Ts'o CC: Jan Kara , akpm@linux-foundation.org, linux-ext4@vger.kernel.org Subject: [PATCH] ext4: Fix memory leak when quota options are specified multiple times Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org When usrjquota or grpjquota mount options are specified several times, we leak memory storing the names. Free the memory correctly. Signed-off-by: Chen Gang Cc: Jan Kara Reviewed-by: Jan Kara --- fs/ext4/super.c | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index c014edd..a4a8ecc 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1351,21 +1351,25 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args) "Not enough memory for storing quotafile name"); return -1; } - if (sbi->s_qf_names[qtype] && - strcmp(sbi->s_qf_names[qtype], qname)) { - ext4_msg(sb, KERN_ERR, - "%s quota file already specified", QTYPE2NAME(qtype)); + if (sbi->s_qf_names[qtype]) { + int ret = 1; + + if (strcmp(sbi->s_qf_names[qtype], qname)) { + ext4_msg(sb, KERN_ERR, + "%s quota file already specified", + QTYPE2NAME(qtype)); + ret = -1; + } kfree(qname); - return -1; + return ret; } - sbi->s_qf_names[qtype] = qname; - if (strchr(sbi->s_qf_names[qtype], '/')) { + if (strchr(qname, '/')) { ext4_msg(sb, KERN_ERR, "quotafile must be on filesystem root"); - kfree(sbi->s_qf_names[qtype]); - sbi->s_qf_names[qtype] = NULL; + kfree(qname); return -1; } + sbi->s_qf_names[qtype] = qname; set_opt(sb, QUOTA); return 1; } @@ -1381,10 +1385,7 @@ static int clear_qf_name(struct super_block *sb, int qtype) " when quota turned on"); return -1; } - /* - * The space will be released later when all options are confirmed - * to be correct - */ + kfree(sbi->s_qf_names[qtype]); sbi->s_qf_names[qtype] = NULL; return 1; } @@ -4605,7 +4606,18 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) #ifdef CONFIG_QUOTA old_opts.s_jquota_fmt = sbi->s_jquota_fmt; for (i = 0; i < MAXQUOTAS; i++) - old_opts.s_qf_names[i] = sbi->s_qf_names[i]; + if (sbi->s_qf_names[i]) { + old_opts.s_qf_names[i] = kstrdup(sbi->s_qf_names[i], + GFP_KERNEL); + if (!old_opts.s_qf_names[i]) { + int j; + + for (j = 0; j < i; j++) + kfree(old_opts.s_qf_names[j]); + return -ENOMEM; + } + } else + old_opts.s_qf_names[i] = NULL; #endif if (sbi->s_journal && sbi->s_journal->j_task->io_context) journal_ioprio = sbi->s_journal->j_task->io_context->ioprio; @@ -4738,9 +4750,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) #ifdef CONFIG_QUOTA /* Release old quota file names */ for (i = 0; i < MAXQUOTAS; i++) - if (old_opts.s_qf_names[i] && - old_opts.s_qf_names[i] != sbi->s_qf_names[i]) - kfree(old_opts.s_qf_names[i]); + kfree(old_opts.s_qf_names[i]); if (enable_quota) { if (sb_any_quota_suspended(sb)) dquot_resume(sb, -1); @@ -4769,9 +4779,7 @@ restore_opts: #ifdef CONFIG_QUOTA sbi->s_jquota_fmt = old_opts.s_jquota_fmt; for (i = 0; i < MAXQUOTAS; i++) { - if (sbi->s_qf_names[i] && - old_opts.s_qf_names[i] != sbi->s_qf_names[i]) - kfree(sbi->s_qf_names[i]); + kfree(sbi->s_qf_names[i]); sbi->s_qf_names[i] = old_opts.s_qf_names[i]; } #endif