From: Jan Kara <jack@ucw.cz>

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)

_