From mboxrd@z Thu Jan 1 00:00:00 1970 From: Josef Bacik Subject: [PATCH 4/8] sync: serialise per-superblock sync operations Date: Tue, 23 Jun 2015 20:23:58 -0700 Message-ID: <1435116242-27495-5-git-send-email-jbacik@fb.com> References: <1435116242-27495-1-git-send-email-jbacik@fb.com> Mime-Version: 1.0 Content-Type: text/plain Cc: Dave Chinner To: , , , , , Return-path: Received: from mx0b-00082601.pphosted.com ([67.231.153.30]:48631 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753639AbbFXDZY (ORCPT ); Tue, 23 Jun 2015 23:25:24 -0400 In-Reply-To: <1435116242-27495-1-git-send-email-jbacik@fb.com> Sender: linux-fsdevel-owner@vger.kernel.org List-ID: From: Dave Chinner When competing sync(2) calls walk the same filesystem, they need to walk the list of inodes on the superblock to find all the inodes that we need to wait for IO completion on. However, when multiple wait_sb_inodes() calls do this at the same time, they contend on the the inode_sb_list_lock and the contention causes system wide slowdowns. In effect, concurrent sync(2) calls can take longer and burn more CPU than if they were serialised. Stop the worst of the contention by adding a per-sb mutex to wrap around wait_sb_inodes() so that we only execute one sync(2) IO completion walk per superblock superblock at a time and hence avoid contention being triggered by concurrent sync(2) calls. Signed-off-by: Dave Chinner Signed-off-by: Josef Bacik Reviewed-by: Jan Kara Reviewed-by: Christoph Hellwig Tested-by: Dave Chinner --- fs/fs-writeback.c | 11 +++++++++++ fs/super.c | 1 + include/linux/fs.h | 2 ++ 3 files changed, 14 insertions(+) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 333afa3..04fbc8a 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1361,6 +1361,15 @@ out_unlock_inode: } EXPORT_SYMBOL(__mark_inode_dirty); +/* + * The @s_sync_lock is used to serialise concurrent sync operations + * to avoid lock contention problems with concurrent wait_sb_inodes() calls. + * Concurrent callers will block on the s_sync_lock rather than doing contending + * walks. The queueing maintains sync(2) required behaviour as all the IO that + * has been issued up to the time this function is enter is guaranteed to be + * completed by the time we have gained the lock and waited for all IO that is + * in progress regardless of the order callers are granted the lock. + */ static void wait_sb_inodes(struct super_block *sb) { struct inode *inode, *old_inode = NULL; @@ -1371,6 +1380,7 @@ static void wait_sb_inodes(struct super_block *sb) */ WARN_ON(!rwsem_is_locked(&sb->s_umount)); + mutex_lock(&sb->s_sync_lock); spin_lock(&sb->s_inode_list_lock); /* @@ -1412,6 +1422,7 @@ static void wait_sb_inodes(struct super_block *sb) } spin_unlock(&sb->s_inode_list_lock); iput(old_inode); + mutex_unlock(&sb->s_sync_lock); } /** diff --git a/fs/super.c b/fs/super.c index 15e57f5..ac2b64b 100644 --- a/fs/super.c +++ b/fs/super.c @@ -190,6 +190,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags) s->s_flags = flags; INIT_HLIST_NODE(&s->s_instances); INIT_HLIST_BL_HEAD(&s->s_anon); + mutex_init(&s->s_sync_lock); INIT_LIST_HEAD(&s->s_inodes); spin_lock_init(&s->s_inode_list_lock); diff --git a/include/linux/fs.h b/include/linux/fs.h index 6a3f507..2d4d104 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1346,6 +1346,8 @@ struct super_block { struct list_lru s_inode_lru ____cacheline_aligned_in_smp; struct rcu_head rcu; + struct mutex s_sync_lock; /* sync serialisation lock */ + /* * Indicates how deep in a filesystem stack this SB is */ -- 2.1.0