From 24cc5cc2962dec69413686b9257b554865ca022a Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Thu, 26 Apr 2018 15:20:01 -0700 Subject: [PATCH] scoutfs: lock manifest root request The manifest root request processing samples the stable_manifest_root in the server info. The stable_manifest_root is updated after a commit has suceeded. The read of stable_manifest_root in request processing was locking the manifest. The update during commit doesn't lock the manifest so these paths were racing. The race is very tight, a few cpu stores, but it could in theory give a client a malformed root that could be misinterpreted as corruption. Add a seqcount around the store of the stable manifest root during commit and its load during request processing. This ensures that clients always get a consistent manifest root. Signed-off-by: Zach Brown --- kmod/src/server.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/kmod/src/server.c b/kmod/src/server.c index 89a39d81..5642c18f 100644 --- a/kmod/src/server.c +++ b/kmod/src/server.c @@ -61,6 +61,7 @@ struct server_info { wait_queue_head_t compaction_waitq; /* server remembers the stable manifest root for clients */ + seqcount_t stable_seqcount; struct scoutfs_btree_root stable_manifest_root; /* server tracks seq use */ @@ -166,8 +167,11 @@ static void scoutfs_server_commit_func(struct work_struct *work) scoutfs_btree_write_complete(sb); + write_seqcount_begin(&server->stable_seqcount); server->stable_manifest_root = SCOUTFS_SB(sb)->super.manifest.root; + write_seqcount_end(&server->stable_seqcount); + scoutfs_advance_dirty_super(sb); } else { ret = 0; @@ -530,15 +534,15 @@ static int process_get_manifest_root(struct server_connection *conn, u64 id, u8 type, void *data, unsigned data_len) { struct server_info *server = conn->server; - struct super_block *sb = server->sb; struct scoutfs_btree_root root; + unsigned int start; int ret; if (data_len == 0) { - scoutfs_manifest_lock(sb); - memcpy(&root, &server->stable_manifest_root, - sizeof(struct scoutfs_btree_root)); - scoutfs_manifest_unlock(sb); + do { + start = read_seqcount_begin(&server->stable_seqcount); + root = server->stable_manifest_root; + } while (read_seqcount_retry(&server->stable_seqcount, start)); ret = 0; } else { ret = -EINVAL; @@ -1062,6 +1066,7 @@ int scoutfs_server_setup(struct super_block *sb) init_llist_head(&server->commit_waiters); INIT_WORK(&server->commit_work, scoutfs_server_commit_func); init_waitqueue_head(&server->compaction_waitq); + seqcount_init(&server->stable_seqcount); spin_lock_init(&server->seq_lock); INIT_LIST_HEAD(&server->pending_seqs);