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;
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
                if (!atomic_read(&inode->i_writecount))
@@ -711,12 +710,18 @@ restart:
+               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);
+       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

Reply via email to