Messages in this thread Patch in this message | | | Date | Sun, 19 Oct 2003 21:07:55 +0200 | From | Jan Kara <> | Subject | [PATCH] Quota locking fix |
| |
Hi Linus,
I'm resending patch which fixes a quota locking problem causing deadlock (when inode was being released from icache and it caused newly created quota structure to be written). The patch against 2.6.0-test7 and should apply at test8 too. Please apply.
Honza
------------- cut here ---------------
diff -ruNX /home/jack/.kerndiffexclude linux-2.6.0-test7/fs/dquot.c linux-2.6.0-test7-1-lockfix/fs/dquot.c --- linux-2.6.0-test7/fs/dquot.c Tue Oct 14 15:52:08 2003 +++ linux-2.6.0-test7-1-lockfix/fs/dquot.c Tue Oct 14 16:26:28 2003 @@ -826,28 +826,49 @@ } /* - * Release all quota for the specified inode. - * - * Note: this is a blocking operation. + * Remove references to quota from inode + * This function needs dqptr_sem for writing */ -static void dquot_drop_nolock(struct inode *inode) +static void dquot_drop_iupdate(struct inode *inode, struct dquot **to_drop) { int cnt; inode->i_flags &= ~S_QUOTA; for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (inode->i_dquot[cnt] == NODQUOT) - continue; - dqput(inode->i_dquot[cnt]); + to_drop[cnt] = inode->i_dquot[cnt]; inode->i_dquot[cnt] = NODQUOT; } } +/* + * Release all quotas referenced by inode + */ void dquot_drop(struct inode *inode) { + struct dquot *to_drop[MAXQUOTAS]; + int cnt; + down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); - dquot_drop_nolock(inode); + dquot_drop_iupdate(inode, to_drop); up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if (to_drop[cnt] != NODQUOT) + dqput(to_drop[cnt]); +} + +/* + * Release all quotas referenced by inode. + * This function assumes dqptr_sem for writing + */ +void dquot_drop_nolock(struct inode *inode) +{ + struct dquot *to_drop[MAXQUOTAS]; + int cnt; + + dquot_drop_iupdate(inode, to_drop); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if (to_drop[cnt] != NODQUOT) + dqput(to_drop[cnt]); } /* @@ -862,6 +883,10 @@ warntype[cnt] = NOWARN; down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + if (IS_NOQUOTA(inode)) { + up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + return QUOTA_OK; + } spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (inode->i_dquot[cnt] == NODQUOT) @@ -894,6 +919,10 @@ for (cnt = 0; cnt < MAXQUOTAS; cnt++) warntype[cnt] = NOWARN; down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + if (IS_NOQUOTA(inode)) { + up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + return QUOTA_OK; + } spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (inode->i_dquot[cnt] == NODQUOT) @@ -923,6 +952,10 @@ unsigned int cnt; down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + if (IS_NOQUOTA(inode)) { + up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + return; + } spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (inode->i_dquot[cnt] == NODQUOT) @@ -942,6 +975,10 @@ unsigned int cnt; down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + if (IS_NOQUOTA(inode)) { + up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + return; + } spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (inode->i_dquot[cnt] == NODQUOT) - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |