Commit d012fa6e authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Quota deadlock fix

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).
parent dd394c2e
...@@ -826,28 +826,49 @@ void dquot_initialize(struct inode *inode, int type) ...@@ -826,28 +826,49 @@ void dquot_initialize(struct inode *inode, int type)
} }
/* /*
* Release all quota for the specified inode. * Remove references to quota from inode
* * This function needs dqptr_sem for writing
* Note: this is a blocking operation.
*/ */
static void dquot_drop_nolock(struct inode *inode) static void dquot_drop_iupdate(struct inode *inode, struct dquot **to_drop)
{ {
int cnt; int cnt;
inode->i_flags &= ~S_QUOTA; inode->i_flags &= ~S_QUOTA;
for (cnt = 0; cnt < MAXQUOTAS; cnt++) { for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (inode->i_dquot[cnt] == NODQUOT) to_drop[cnt] = inode->i_dquot[cnt];
continue;
dqput(inode->i_dquot[cnt]);
inode->i_dquot[cnt] = NODQUOT; inode->i_dquot[cnt] = NODQUOT;
} }
} }
/*
* Release all quotas referenced by inode
*/
void dquot_drop(struct inode *inode) void dquot_drop(struct inode *inode)
{ {
struct dquot *to_drop[MAXQUOTAS];
int cnt;
down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); 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); 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 *inode, qsize_t number, int warn) ...@@ -862,6 +883,10 @@ int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
warntype[cnt] = NOWARN; warntype[cnt] = NOWARN;
down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); 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); spin_lock(&dq_data_lock);
for (cnt = 0; cnt < MAXQUOTAS; cnt++) { for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (inode->i_dquot[cnt] == NODQUOT) if (inode->i_dquot[cnt] == NODQUOT)
...@@ -894,6 +919,10 @@ int dquot_alloc_inode(const struct inode *inode, unsigned long number) ...@@ -894,6 +919,10 @@ int dquot_alloc_inode(const struct inode *inode, unsigned long number)
for (cnt = 0; cnt < MAXQUOTAS; cnt++) for (cnt = 0; cnt < MAXQUOTAS; cnt++)
warntype[cnt] = NOWARN; warntype[cnt] = NOWARN;
down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); 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); spin_lock(&dq_data_lock);
for (cnt = 0; cnt < MAXQUOTAS; cnt++) { for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (inode->i_dquot[cnt] == NODQUOT) if (inode->i_dquot[cnt] == NODQUOT)
...@@ -923,6 +952,10 @@ void dquot_free_space(struct inode *inode, qsize_t number) ...@@ -923,6 +952,10 @@ void dquot_free_space(struct inode *inode, qsize_t number)
unsigned int cnt; unsigned int cnt;
down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); 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); spin_lock(&dq_data_lock);
for (cnt = 0; cnt < MAXQUOTAS; cnt++) { for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (inode->i_dquot[cnt] == NODQUOT) if (inode->i_dquot[cnt] == NODQUOT)
...@@ -942,6 +975,10 @@ void dquot_free_inode(const struct inode *inode, unsigned long number) ...@@ -942,6 +975,10 @@ void dquot_free_inode(const struct inode *inode, unsigned long number)
unsigned int cnt; unsigned int cnt;
down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); 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); spin_lock(&dq_data_lock);
for (cnt = 0; cnt < MAXQUOTAS; cnt++) { for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (inode->i_dquot[cnt] == NODQUOT) if (inode->i_dquot[cnt] == NODQUOT)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment