[PATCH] Quota locking fix

From: Jan Kara
Date: Wed Oct 15 2003 - 06:07:41 EST


Hi Linus,

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). The patch against 2.6.0-test7 is attached.
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@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/