From: Jan Kara attached patch should fix a quota locking problem causing deadlock (when inode was being released from icache and it caused newly created quota structure to be written). 25-akpm/fs/dquot.c | 53 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 45 insertions(+), 8 deletions(-) diff -puN fs/dquot.c~quota-locking-fix fs/dquot.c --- 25/fs/dquot.c~quota-locking-fix Wed Oct 15 12:54:55 2003 +++ 25-akpm/fs/dquot.c Wed Oct 15 12:54:55 2003 @@ -826,28 +826,49 @@ void dquot_initialize(struct inode *inod } /* - * 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 @@ int dquot_alloc_space(struct inode *inod 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 @@ int dquot_alloc_inode(const struct inode 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 @@ void dquot_free_space(struct inode *inod 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 @@ void dquot_free_inode(const struct inode 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) _