[PATCH] quota: handle io errors in dquot_transfer

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

 



Currently quota is able to return real error code to caller.
Now it is possible to fix long standing bug with silent quota
corruption in dquot_transfer.
>From 5e529864261c7bffe32a8b3d45d7b51749b4512f Mon Sep 17 00:00:00 2001
From: Dmitry Monakhov <dmonakhov@xxxxxxxxxx>
Date: Mon, 5 Apr 2010 13:02:18 +0400
Subject: [PATCH] quota: handle io errors in dquot_transfer

Currently if one of dquot structures absent due to some io errors
dquot_transfer will ignore corresponding quotatype. Which is very
bad because result in silent quota inconsistency.

Sane implementation must return corresponding error to caller.

Signed-off-by: Dmitry Monakhov <dmonakhov@xxxxxxxxxx>
---
 fs/quota/dquot.c |   35 +++++++++++++++++++----------------
 1 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 88a8ef2..324a0fb 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -1721,15 +1721,22 @@ static int __dquot_transfer(struct inode *inode, qid_t *chid, unsigned long mask
 	space = cur_space + rsv_space;
 	/* Build the transfer_from list and check the limits */
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		if (!transfer_to[cnt])
+		if (!(mask & (1 << cnt)))
 			continue;
 		transfer_from[cnt] = inode->i_dquot[cnt];
+		/*
+		 * Due to IO error we might not have one of dquot structures.
+		 * If so, cancel whole procedure */
+		if (!transfer_from[cnt] || !transfer_to[cnt]) {
+			ret = -EIO;
+			goto bad_quota;
+		}
 		ret = check_idq(transfer_to[cnt], 1, warntype_to + cnt);
 		if (ret)
-			goto over_quota;
+			goto bad_quota;
 		ret = check_bdq(transfer_to[cnt], space, 0, warntype_to + cnt);
 		if (ret)
-			goto over_quota;
+			goto bad_quota;
 	}
 
 	/*
@@ -1739,20 +1746,16 @@ static int __dquot_transfer(struct inode *inode, qid_t *chid, unsigned long mask
 		/*
 		 * Skip changes for same uid or gid or for turned off quota-type.
 		 */
-		if (!transfer_to[cnt])
+		if (!(mask & (1 << cnt)))
 			continue;
+		warntype_from_inodes[cnt] =
+			info_idq_free(transfer_from[cnt], 1);
+		warntype_from_space[cnt] =
+			info_bdq_free(transfer_from[cnt], space);
 
-		/* Due to IO error we might not have transfer_from[] structure */
-		if (transfer_from[cnt]) {
-			warntype_from_inodes[cnt] =
-				info_idq_free(transfer_from[cnt], 1);
-			warntype_from_space[cnt] =
-				info_bdq_free(transfer_from[cnt], space);
-			dquot_decr_inodes(transfer_from[cnt], 1);
-			dquot_decr_space(transfer_from[cnt], cur_space);
-			dquot_free_reserved_space(transfer_from[cnt],
-						  rsv_space);
-		}
+		dquot_decr_inodes(transfer_from[cnt], 1);
+		dquot_decr_space(transfer_from[cnt], cur_space);
+		dquot_free_reserved_space(transfer_from[cnt], rsv_space);
 
 		dquot_incr_inodes(transfer_to[cnt], 1);
 		dquot_incr_space(transfer_to[cnt], cur_space);
@@ -1776,7 +1779,7 @@ put_all:
 	dqput_all(transfer_from);
 	dqput_all(transfer_to);
 	return ret;
-over_quota:
+bad_quota:
 	spin_unlock(&dq_data_lock);
 	up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	/* Clear dquot pointers we don't want to dqput() */
-- 
1.6.6.1


[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