[PATCH 3/6] quota: Check what quota is properly initialized for inode before charge

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <dmonakhov@xxxxxxxxxx>
---
 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

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux