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 <zab@versity.com>
This commit is contained in:
Zach Brown
2020-05-12 18:17:14 -07:00
committed by Zach Brown
parent 4d0b78f5cb
commit 3a82090ab1
3 changed files with 17 additions and 19 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);