Gitweb: http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=941d2380e979dfefb6c824452e9f42be3ef948ee Commit: 941d2380e979dfefb6c824452e9f42be3ef948ee Parent: bed9759b2e6bd938097389f6bd2ac8d622fa3884 Author: Jan Kara <[EMAIL PROTECTED]> AuthorDate: Wed Feb 6 01:37:36 2008 -0800 Committer: Linus Torvalds <[EMAIL PROTECTED]> CommitDate: Wed Feb 6 10:41:07 2008 -0800
quota: improve inode list scanning in add_dquot_ref() We restarted scan of sb->s_inodes list whenever we had to drop inode_lock in add_dquot_ref(). This leads to overall quadratic running time and thus add_dquot_ref() can take several minutes when called on a life filesystem. We fix the problem by using the fact that inode cannot be removed from s_inodes list while we hold a reference to it and thus we can safely restart the scan if we don't drop the reference. Here we use the fact that inodes freshly added to s_inodes list are already guaranteed to have quotas properly initialized and the ordering of inodes on s_inodes list does not change so we cannot skip any inode. Thanks goes to Nick <[EMAIL PROTECTED]> for analyzing the problem and testing the fix. [EMAIL PROTECTED]: iput(NULL) is legal] Signed-off-by: Jan Kara <[EMAIL PROTECTED]> Cc: Nick <[EMAIL PROTECTED]> Signed-off-by: Andrew Morton <[EMAIL PROTECTED]> Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]> --- fs/dquot.c | 15 ++++++++++----- 1 files changed, 10 insertions(+), 5 deletions(-) diff --git a/fs/dquot.c b/fs/dquot.c index cee7c6f..def4e96 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -696,9 +696,8 @@ static int dqinit_needed(struct inode *inode, int type) /* This routine is guarded by dqonoff_mutex mutex */ static void add_dquot_ref(struct super_block *sb, int type) { - struct inode *inode; + struct inode *inode, *old_inode = NULL; -restart: spin_lock(&inode_lock); list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { if (!atomic_read(&inode->i_writecount)) @@ -711,12 +710,18 @@ restart: __iget(inode); spin_unlock(&inode_lock); + iput(old_inode); sb->dq_op->initialize(inode, type); - iput(inode); - /* As we may have blocked we had better restart... */ - goto restart; + /* We hold a reference to 'inode' so it couldn't have been + * removed from s_inodes list while we dropped the inode_lock. + * We cannot iput the inode now as we can be holding the last + * reference and we cannot iput it under inode_lock. So we + * keep the reference and iput it later. */ + old_inode = inode; + spin_lock(&inode_lock); } spin_unlock(&inode_lock); + iput(old_inode); } /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */ - To unsubscribe from this list: send the line "unsubscribe git-commits-head" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html