Commit a0a133ff authored by Jan Kara's avatar Jan Kara Committed by Linus Torvalds

[PATCH] Fix minor quota race

It fixes a possible race between quotaoff and prune_icache.  The race could
lead to some forgotten pointers to quotas in inodes leading later to BUG
when invalidating quota structures.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3fec7922
......@@ -112,8 +112,10 @@
* operations on dquots don't hold dq_lock as they copy data under dq_data_lock
* spinlock to internal buffers before writing.
*
* Lock ordering (including journal_lock) is following:
* dqonoff_sem > journal_lock > dqptr_sem > dquot->dq_lock > dqio_sem
* Lock ordering (including some related VFS locks) is the following:
* i_sem > dqonoff_sem > iprune_sem > journal_lock > dqptr_sem >
* > dquot->dq_lock > dqio_sem
* i_sem on quota files is special (it's below dqio_sem)
*/
spinlock_t dq_list_lock = SPIN_LOCK_UNLOCKED;
......@@ -728,17 +730,18 @@ static void put_dquot_list(struct list_head *tofree_head)
}
}
/* Function in inode.c - remove pointers to dquots in icache */
extern void remove_dquot_ref(struct super_block *, int, struct list_head *);
/* Gather all references from inodes and drop them */
static void drop_dquot_ref(struct super_block *sb, int type)
{
LIST_HEAD(tofree_head);
/* We need to be guarded against prune_icache to reach all the
* inodes - otherwise some can be on the local list of prune_icache */
down(&iprune_sem);
down_write(&sb_dqopt(sb)->dqptr_sem);
remove_dquot_ref(sb, type, &tofree_head);
up_write(&sb_dqopt(sb)->dqptr_sem);
up(&iprune_sem);
put_dquot_list(&tofree_head);
}
......
......@@ -90,7 +90,7 @@ spinlock_t inode_lock = SPIN_LOCK_UNLOCKED;
* from its final dispose_list, the struct super_block they refer to
* (for inode->i_sb->s_op) may already have been freed and reused.
*/
static DECLARE_MUTEX(iprune_sem);
DECLARE_MUTEX(iprune_sem);
/*
* Statistics gathering..
......
......@@ -1374,6 +1374,8 @@ extern void clear_inode(struct inode *);
extern void destroy_inode(struct inode *);
extern struct inode *new_inode(struct super_block *);
extern int remove_suid(struct dentry *);
extern void remove_dquot_ref(struct super_block *, int, struct list_head *);
extern struct semaphore iprune_sem;
extern void __insert_inode_hash(struct inode *, unsigned long hashval);
extern void remove_inode_hash(struct inode *);
......
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