Return-Path: Received: from localhost (bix [127.0.0.1]) by localhost.localdomain (8.12.10/8.12.10) with ESMTP id lBBDiwI9014494 for ; Tue, 11 Dec 2007 05:44:59 -0800 Received: from imap1.linux-foundation.org [207.189.120.55] by localhost with IMAP (fetchmail-6.2.5) for akpm@localhost (single-drop); Tue, 11 Dec 2007 05:44:59 -0800 (PST) Received: from smtp1.linux-foundation.org (smtp1.linux-foundation.org [207.189.120.13]) by imap1.linux-foundation.org (8.13.5.20060308/8.13.5/Debian-3ubuntu1.1) with ESMTP id lBBDhSt8024635 for ; Tue, 11 Dec 2007 05:43:28 -0800 Received: from duck.suse.cz (styx.suse.cz [82.119.242.94]) by smtp1.linux-foundation.org (8.13.5.20060308/8.13.5/Debian-3ubuntu1.1) with ESMTP id lBBDhLfs019222 for ; Tue, 11 Dec 2007 05:43:22 -0800 Received: by duck.suse.cz (Postfix, from userid 1000) id 75DA1251B20; Tue, 11 Dec 2007 14:43:19 +0100 (CET) Date: Tue, 11 Dec 2007 14:43:19 +0100 From: Jan Kara To: Andrew Morton Cc: linux-kernel@vger.kernel.org, gentuu@gmail.com Subject: [PATCH] Improve inode list scanning in add_dquot_ref() Message-ID: <20071211134319.GB8153@duck.suse.cz> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.16 (2007-06-09) Received-SPF: none (domain of jack+f-111207@suse.cz does not designate permitted sender hosts) X-MIMEDefang-Filter: lf$Revision: 1.188 $ X-Scanned-By: MIMEDefang 2.53 on 207.189.120.13 X-Spam-Checker-Version: SpamAssassin 3.0.2 (2004-11-16) on bix X-Spam-Level: X-Spam-Status: No, score=-0.4 required=2.0 tests=AWL autolearn=ham version=3.0.2 Hi, attached patch makes add_dquot_ref() quite faster if used on a life filesystem. It has survived some testing on my machine but there could be some subtle races I've missed so please leave it in -mm for a while (not that I'd think that people use quotas with -mm kernels but at least it should go into vanilla in -rc1...). Thanks. Honza --- 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 for analyzing the problem and testing the fix. Signed-off-by: Jan Kara Cc: Nick diff --git a/fs/dquot.c b/fs/dquot.c index 2809768..ecea4be 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,20 @@ restart: __iget(inode); spin_unlock(&inode_lock); + if (old_inode) + 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); + if (old_inode) + iput(old_inode); } /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */