From mboxrd@z Thu Jan 1 00:00:00 1970 From: Dmitry Monakhov Subject: [PATCH 3/6] quota: Check what quota is properly initialized for inode before charge Date: Thu, 8 Apr 2010 22:04:22 +0400 Message-ID: <1270749865-25441-4-git-send-email-dmonakhov@openvz.org> References: <1270749865-25441-1-git-send-email-dmonakhov@openvz.org> <1270749865-25441-2-git-send-email-dmonakhov@openvz.org> <1270749865-25441-3-git-send-email-dmonakhov@openvz.org> Cc: jack@suse.cz, hch@infradead.org, sandeen@redhat.com, Dmitry Monakhov To: linux-fsdevel@vger.kernel.org Return-path: Received: from mail-bw0-f209.google.com ([209.85.218.209]:64715 "EHLO mail-bw0-f209.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758238Ab0DHSFZ (ORCPT ); Thu, 8 Apr 2010 14:05:25 -0400 Received: by mail-bw0-f209.google.com with SMTP id 1so1996475bwz.21 for ; Thu, 08 Apr 2010 11:05:24 -0700 (PDT) In-Reply-To: <1270749865-25441-3-git-send-email-dmonakhov@openvz.org> Sender: linux-fsdevel-owner@vger.kernel.org List-ID: Due to previous IO error or other bugs an inode may not has quota pointer. This definite sign of quota inconsistency/corruption. In fact this condition must being checked in all charge/uncharge functions. And if error was detected it is reasonable to fail whole operation. But uncharge(free_space/claim_space/free_inode) functions has no fail nature. This is because caller can't handle errors from such functions. How can you handle error from following call-trace? write_page()->quota_claim_space() So alloc_space() and alloc_inode() are the only functions which we may reliably abort in case of any errors. This patch add corresponding checks only for charge functions. Signed-off-by: Dmitry Monakhov --- fs/quota/dquot.c | 39 +++++++++++++++++++++++++++++++++------ 1 files changed, 33 insertions(+), 6 deletions(-) diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 3f4541e..7480e03 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -1516,7 +1516,7 @@ static void inode_decr_space(struct inode *inode, qsize_t number, int reserve) int __dquot_alloc_space(struct inode *inode, qsize_t number, int warn, int reserve) { - int cnt, ret = 0; + int cnt, active, ret = 0; char warntype[MAXQUOTAS]; /* @@ -1529,13 +1529,27 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, } down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + /* Now recheck reliably when holding dqptr_sem */ + if (!(active = sb_any_quota_active(inode->i_sb)) || IS_NOQUOTA(inode)) { + inode_incr_space(inode, number, reserve); + goto out; + } + for (cnt = 0; cnt < MAXQUOTAS; cnt++) warntype[cnt] = QUOTA_NL_NOWARN; spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (!inode->i_dquot[cnt]) + if (!(active & (1 << cnt))) continue; + /* + * Given quota type is active, so quota must being + * initialized for this inode + */ + if (!inode->i_dquot[cnt]) { + ret = -EIO; + goto out_flush_warn; + } ret = check_bdq(inode->i_dquot[cnt], number, !warn, warntype+cnt); if (ret) { @@ -1544,7 +1558,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, } } for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (!inode->i_dquot[cnt]) + if (!(active & (1 << cnt))) continue; if (reserve) dquot_resv_space(inode->i_dquot[cnt], number); @@ -1570,7 +1584,7 @@ EXPORT_SYMBOL(__dquot_alloc_space); */ int dquot_alloc_inode(const struct inode *inode) { - int cnt, ret = 0; + int cnt, active, ret = 0; char warntype[MAXQUOTAS]; /* First test before acquiring mutex - solves deadlocks when we @@ -1580,17 +1594,30 @@ int dquot_alloc_inode(const struct inode *inode) for (cnt = 0; cnt < MAXQUOTAS; cnt++) warntype[cnt] = QUOTA_NL_NOWARN; down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + /* Now recheck reliably when holding dqptr_sem */ + if (!(active = sb_any_quota_active(inode->i_sb)) || IS_NOQUOTA(inode)) { + return 0; + } + spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (!inode->i_dquot[cnt]) + if (!(active & (1 < cnt))) continue; + /* + * Given quota type is active, so quota must being + * initialized for this inode + */ + if (!inode->i_dquot[cnt]) { + ret = -EIO; + goto warn_put_all; + } ret = check_idq(inode->i_dquot[cnt], 1, warntype + cnt); if (ret) goto warn_put_all; } for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (!inode->i_dquot[cnt]) + if ((!active & (1 < cnt))) continue; dquot_incr_inodes(inode->i_dquot[cnt], 1); } -- 1.6.6.1