From 1193fbc9c5a56eac46f9b79579446a5cc4de04bd Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Thu, 28 Sep 2017 15:35:40 -0700 Subject: [PATCH] scoutfs: add a node_id lock A mount's node_id item operations need to be locked. For now let's use a lock that's held for the duration of the mount. It makes it trivial for us to use it with node_id items but we'll have work to do if we want to opportunistically get access to other mount's node_id items while they're still up. Signed-off-by: Zach Brown --- kmod/src/lock.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ kmod/src/lock.h | 2 ++ kmod/src/super.c | 12 ++++++++++-- kmod/src/super.h | 2 ++ 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/kmod/src/lock.c b/kmod/src/lock.c index 7fc15526..75c0fa7c 100644 --- a/kmod/src/lock.c +++ b/kmod/src/lock.c @@ -190,6 +190,13 @@ static struct ocfs2_lock_res_ops scoutfs_global_lops = { .flags = 0, }; +static struct ocfs2_lock_res_ops scoutfs_node_id_lops = { + .get_osb = get_ino_lock_osb, + /* XXX: .check_downconvert that queries the item cache for dirty items */ + .downconvert_worker = ino_lock_downconvert, + .flags = 0, +}; + static struct scoutfs_lock *alloc_scoutfs_lock(struct super_block *sb, struct scoutfs_lock_name *lock_name, struct ocfs2_lock_res_ops *type, @@ -671,6 +678,48 @@ int scoutfs_lock_inode_index(struct super_block *sb, int mode, &scoufs_ino_index_lops, &start, &end, ret_lock); } +/* + * The node_id lock protects a mount's private persistent items in the + * node_id zone. It's held for the duration of the mount. It lets the + * mount modify the node_id items at will and signals to other mounts + * that we're still alive and our node_id items shouldn't be reclaimed. + * + * Being held for the entire mount prevents other nodes from reclaiming + * our items, like free blocks, when it would make sense for them to be + * able to. Maybe we have a bunch free and they're trying to allocate + * and are getting ENOSPC. + */ +int scoutfs_lock_node_id(struct super_block *sb, int mode, int flags, + u64 node_id, struct scoutfs_lock **lock) +{ + struct scoutfs_lock_name lock_name; + struct scoutfs_orphan_key start_okey; + struct scoutfs_orphan_key end_okey; + struct scoutfs_key_buf start; + struct scoutfs_key_buf end; + + lock_name.scope = SCOUTFS_LOCK_SCOPE_FS_ITEMS; + lock_name.zone = SCOUTFS_NODE_ZONE; + lock_name.type = 0; + lock_name.first = cpu_to_le64(node_id); + lock_name.second = 0; + + start_okey.zone = SCOUTFS_NODE_ZONE; + start_okey.node_id = cpu_to_be64(node_id); + start_okey.type = 0; + start_okey.ino = 0; + scoutfs_key_init(&start, &start_okey, sizeof(start_okey)); + + end_okey.zone = SCOUTFS_NODE_ZONE; + end_okey.node_id = cpu_to_be64(node_id); + end_okey.type = ~0; + end_okey.ino = cpu_to_be64(~0ULL); + scoutfs_key_init(&end, &end_okey, sizeof(end_okey)); + + return lock_name_keys(sb, mode, flags, &lock_name, + &scoutfs_node_id_lops, &start, &end, lock); +} + void scoutfs_unlock(struct super_block *sb, struct scoutfs_lock *lock, int level) { diff --git a/kmod/src/lock.h b/kmod/src/lock.h index 65c0a4f2..cd80a4fd 100644 --- a/kmod/src/lock.h +++ b/kmod/src/lock.h @@ -46,6 +46,8 @@ int scoutfs_lock_inodes(struct super_block *sb, int mode, int flags, struct inode *d, struct scoutfs_lock **D_lock); int scoutfs_lock_global(struct super_block *sb, int mode, int flags, int type, struct scoutfs_lock **lock); +int scoutfs_lock_node_id(struct super_block *sb, int mode, int flags, + u64 node_id, struct scoutfs_lock **lock); void scoutfs_unlock(struct super_block *sb, struct scoutfs_lock *lock, int level); diff --git a/kmod/src/super.c b/kmod/src/super.c index 0a8b71af..e3d81395 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -290,6 +290,8 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) */ ret = scoutfs_server_setup(sb) ?: scoutfs_client_setup(sb); + scoutfs_lock_node_id(sb, DLM_LOCK_EX, 0, sbi->node_id, + &sbi->node_id_lock); if (ret) goto out; @@ -313,8 +315,11 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) // scoutfs_scan_orphans(sb); ret = 0; out: - if (ret) - scoutfs_server_destroy(sb); + if (ret) { + scoutfs_server_destroy(sb); + scoutfs_unlock(sb, sbi->node_id_lock, DLM_LOCK_EX); + sbi->node_id_lock = NULL; + } return ret; } @@ -342,6 +347,9 @@ static void scoutfs_kill_sb(struct super_block *sb) kill_block_super(sb); if (sbi) { + scoutfs_unlock(sb, sbi->node_id_lock, DLM_LOCK_EX); + sbi->node_id_lock = NULL; + scoutfs_lock_destroy(sb); scoutfs_client_destroy(sb); scoutfs_server_destroy(sb); diff --git a/kmod/src/super.h b/kmod/src/super.h index 933ed2b4..89a843f9 100644 --- a/kmod/src/super.h +++ b/kmod/src/super.h @@ -23,7 +23,9 @@ struct btree_info; struct scoutfs_sb_info { struct super_block *sb; + /* assigned once at the start of each mount, read-only */ u64 node_id; + struct scoutfs_lock *node_id_lock; struct scoutfs_super_block super;