diff options
-rw-r--r-- | fs/dquot.c | 15 |
1 files changed, 10 insertions, 5 deletions
diff --git a/fs/dquot.c b/fs/dquot.c index cee7c6f428f0..def4e969df77 100644 --- a/fs/dquot.c +++ b/fs/dquot.c | |||
@@ -696,9 +696,8 @@ static int dqinit_needed(struct inode *inode, int type) | |||
696 | /* This routine is guarded by dqonoff_mutex mutex */ | 696 | /* This routine is guarded by dqonoff_mutex mutex */ |
697 | static void add_dquot_ref(struct super_block *sb, int type) | 697 | static void add_dquot_ref(struct super_block *sb, int type) |
698 | { | 698 | { |
699 | struct inode *inode; | 699 | struct inode *inode, *old_inode = NULL; |
700 | 700 | ||
701 | restart: | ||
702 | spin_lock(&inode_lock); | 701 | spin_lock(&inode_lock); |
703 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 702 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
704 | if (!atomic_read(&inode->i_writecount)) | 703 | if (!atomic_read(&inode->i_writecount)) |
@@ -711,12 +710,18 @@ restart: | |||
711 | __iget(inode); | 710 | __iget(inode); |
712 | spin_unlock(&inode_lock); | 711 | spin_unlock(&inode_lock); |
713 | 712 | ||
713 | iput(old_inode); | ||
714 | sb->dq_op->initialize(inode, type); | 714 | sb->dq_op->initialize(inode, type); |
715 | iput(inode); | 715 | /* We hold a reference to 'inode' so it couldn't have been |
716 | /* As we may have blocked we had better restart... */ | 716 | * removed from s_inodes list while we dropped the inode_lock. |
717 | goto restart; | 717 | * We cannot iput the inode now as we can be holding the last |
718 | * reference and we cannot iput it under inode_lock. So we | ||
719 | * keep the reference and iput it later. */ | ||
720 | old_inode = inode; | ||
721 | spin_lock(&inode_lock); | ||
718 | } | 722 | } |
719 | spin_unlock(&inode_lock); | 723 | spin_unlock(&inode_lock); |
724 | iput(old_inode); | ||
720 | } | 725 | } |
721 | 726 | ||
722 | /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */ | 727 | /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */ |