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)
}
/*
* 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 *inode, qsize_t number, int warn)
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 *inode, unsigned long number)
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 *inode, qsize_t number)
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 *inode, unsigned long number)
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)
......
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