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