From 3a82090ab158c80f06aea26fbba4e1544ea2b33d Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 12 May 2020 18:17:14 -0700 Subject: [PATCH] scoutfs: have per-fs inode nr allocators We had previously seen lock contention between mounts that were either resolving paths by looking up entries in directories or writing xattrs in file inodes as they did archiving work. The previous attempt to avoid this contention was to give each directory its own inode number allocator which ensured that inodes created for entries in the directory wouldn't share lock groups with inodes in other directories. But this creates the problem of operating on few files per lock for reasonably small directories. It also creates more server commits as each new directory gets its inode allocation reservation. The fix is to have mount-wide seperate allocators for directories and for everything else. This puts directories and files in seperate groups and locks, regardless of directory population. Signed-off-by: Zach Brown --- kmod/src/dir.c | 2 +- kmod/src/inode.c | 23 +++++++++++++++-------- kmod/src/inode.h | 11 +---------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/kmod/src/dir.c b/kmod/src/dir.c index 18164384..12cd42ab 100644 --- a/kmod/src/dir.c +++ b/kmod/src/dir.c @@ -642,7 +642,7 @@ static struct inode *lock_hold_create(struct inode *dir, struct dentry *dentry, if (ret) return ERR_PTR(ret); - ret = scoutfs_alloc_ino(dir, &ino); + ret = scoutfs_alloc_ino(sb, S_ISDIR(mode), &ino); if (ret) return ERR_PTR(ret); diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 124d9375..efab16fd 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -47,9 +47,17 @@ * - describe data locking size problems */ +struct inode_allocator { + spinlock_t lock; + u64 ino; + u64 nr; +}; + struct inode_sb_info { spinlock_t writeback_lock; struct rb_root writeback_inodes; + struct inode_allocator dir_ino_alloc; + struct inode_allocator ino_alloc; }; #define DECLARE_INODE_SB_INFO(sb, name) \ @@ -74,7 +82,6 @@ static void scoutfs_inode_ctor(void *obj) init_waitqueue_head(&ci->data_waitq.waitq); init_rwsem(&ci->xattr_rwsem); RB_CLEAR_NODE(&ci->writeback_node); - spin_lock_init(&ci->ino_alloc.lock); inode_init_once(&ci->inode); } @@ -682,8 +689,6 @@ struct inode *scoutfs_iget(struct super_block *sb, u64 ino) /* XXX ensure refresh, instead clear in drop_inode? */ si = SCOUTFS_I(inode); atomic64_set(&si->last_refreshed, 0); - si->ino_alloc.ino = 0; - si->ino_alloc.nr = 0; ret = scoutfs_inode_refresh(inode, lock, 0); if (ret) { @@ -1322,14 +1327,16 @@ u64 scoutfs_last_ino(struct super_block *sb) * minimize that loss while still being large enough for typical * directory file counts. */ -int scoutfs_alloc_ino(struct inode *parent, u64 *ino_ret) +int scoutfs_alloc_ino(struct super_block *sb, bool is_dir, u64 *ino_ret) { - struct scoutfs_inode_allocator *ia = &SCOUTFS_I(parent)->ino_alloc; - struct super_block *sb = parent->i_sb; + DECLARE_INODE_SB_INFO(sb, inf); + struct inode_allocator *ia; u64 ino; u64 nr; int ret; + ia = is_dir ? &inf->dir_ino_alloc : &inf->ino_alloc; + spin_lock(&ia->lock); if (ia->nr == 0) { @@ -1385,8 +1392,6 @@ struct inode *scoutfs_new_inode(struct super_block *sb, struct inode *dir, ci->have_item = false; atomic64_set(&ci->last_refreshed, lock->refresh_gen); ci->flags = 0; - ci->ino_alloc.ino = 0; - ci->ino_alloc.nr = 0; scoutfs_inode_set_meta_seq(inode); scoutfs_inode_set_data_seq(inode); @@ -1725,6 +1730,8 @@ int scoutfs_inode_setup(struct super_block *sb) spin_lock_init(&inf->writeback_lock); inf->writeback_inodes = RB_ROOT; + spin_lock_init(&inf->dir_ino_alloc.lock); + spin_lock_init(&inf->ino_alloc.lock); sbi->inode_sb_info = inf; diff --git a/kmod/src/inode.h b/kmod/src/inode.h index 719fb391..9034aef4 100644 --- a/kmod/src/inode.h +++ b/kmod/src/inode.h @@ -10,12 +10,6 @@ struct scoutfs_lock; -struct scoutfs_inode_allocator { - spinlock_t lock; - u64 ino; - u64 nr; -}; - struct scoutfs_inode_info { /* read or initialized for each inode instance */ u64 ino; @@ -42,9 +36,6 @@ struct scoutfs_inode_info { /* updated at on each new lock acquisition */ atomic64_t last_refreshed; - /* reset for every new inode instance */ - struct scoutfs_inode_allocator ino_alloc; - /* initialized once for slab object */ seqcount_t seqcount; bool staging; /* holder of i_mutex is staging */ @@ -95,7 +86,7 @@ int scoutfs_dirty_inode_item(struct inode *inode, struct scoutfs_lock *lock); void scoutfs_update_inode_item(struct inode *inode, struct scoutfs_lock *lock, struct list_head *ind_locks); -int scoutfs_alloc_ino(struct inode *parent, u64 *ino); +int scoutfs_alloc_ino(struct super_block *sb, bool is_dir, u64 *ino_ret); struct inode *scoutfs_new_inode(struct super_block *sb, struct inode *dir, umode_t mode, dev_t rdev, u64 ino, struct scoutfs_lock *lock);