From e36b6761dadc6adc4f9bb1ee684efee528e40dc5 Mon Sep 17 00:00:00 2001 From: Patrick Donnelly Date: Tue, 16 Apr 2024 11:44:49 -0400 Subject: [PATCH] mds: add debug "lock path" command So we can have a long-running lock on an inode for certain tests. Signed-off-by: Patrick Donnelly (cherry picked from commit 7f1d066756383adae37d61cc2b2f5d99bc167f65) Conflicts: src/include/ceph_fs.h: missing quiesce code src/mds/MDCache.cc: missing quiesce code src/mds/MDCache.h: missing quiesce code src/mds/MDSRank.cc: missing quiesce code src/mds/MDSRank.h: missing quiesce code --- src/include/ceph_fs.h | 5 ++- src/mds/MDCache.cc | 101 +++++++++++++++++++++++++++++++++++++++++- src/mds/MDCache.h | 4 ++ src/mds/MDSDaemon.cc | 6 +++ src/mds/MDSRank.cc | 26 +++++++++++ src/mds/MDSRank.h | 1 + 6 files changed, 141 insertions(+), 2 deletions(-) diff --git a/src/include/ceph_fs.h b/src/include/ceph_fs.h index 4c56d7b7f54..ad604fe9f0e 100644 --- a/src/include/ceph_fs.h +++ b/src/include/ceph_fs.h @@ -430,7 +430,10 @@ enum { CEPH_MDS_OP_ENQUEUE_SCRUB = 0x01503, CEPH_MDS_OP_REPAIR_FRAGSTATS = 0x01504, CEPH_MDS_OP_REPAIR_INODESTATS = 0x01505, - CEPH_MDS_OP_RDLOCK_FRAGSSTATS = 0x01507 + CEPH_MDS_OP_RDLOCK_FRAGSSTATS = 0x01507, + CEPH_MDS_OP_QUIESCE_PATH = 0x01508, + CEPH_MDS_OP_QUIESCE_INODE = 0x01509, + CEPH_MDS_OP_LOCK_PATH = 0x0150a, }; #define IS_CEPH_MDS_OP_NEWINODE(op) (op == CEPH_MDS_OP_CREATE || \ diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc index cd4f8c4f015..34d83d50de3 100644 --- a/src/mds/MDCache.cc +++ b/src/mds/MDCache.cc @@ -115,6 +115,10 @@ public: explicit MDCacheLogContext(MDCache *mdc_) : mdcache(mdc_) {} }; +struct LockPathState { + std::vector locks; +}; + MDCache::MDCache(MDSRank *m, PurgeQueue &purge_queue_) : mds(m), open_file_table(m), @@ -9758,6 +9762,9 @@ void MDCache::dispatch_request(MDRequestRef& mdr) mds->server->dispatch_peer_request(mdr); } else { switch (mdr->internal_op) { + case CEPH_MDS_OP_LOCK_PATH: + dispatch_lock_path(mdr); + break; case CEPH_MDS_OP_FRAGMENTDIR: dispatch_fragment_dir(mdr); break; @@ -9875,7 +9882,7 @@ void MDCache::request_cleanup(MDRequestRef& mdr) mdr->clear_ambiguous_auth(); if (!mdr->more()->waiting_for_finish.empty()) mds->queue_waiters(mdr->more()->waiting_for_finish); - } + } request_drop_locks(mdr); @@ -13441,6 +13448,98 @@ void MDCache::clear_dirty_bits_for_stray(CInode* diri) { } } +void MDCache::dispatch_lock_path(MDRequestRef& mdr) +{ + CInode* in = nullptr; + CF_MDS_RetryRequestFactory cf(this, mdr, true); + static const int ptflags = 0 + | MDS_TRAVERSE_DISCOVER + | MDS_TRAVERSE_RDLOCK_PATH + | MDS_TRAVERSE_WANT_INODE + ; + int r = path_traverse(mdr, cf, mdr->get_filepath(), ptflags, nullptr, &in); + if (r > 0) + return; + if (r < 0) { + mds->server->respond_to_request(mdr, r); + return; + } + + auto& lps = *static_cast(mdr->internal_op_private); + + MutationImpl::LockOpVec lov; + for (const auto &lock : lps.locks) { + auto colonps = lock.find(':'); + if (colonps == std::string::npos) { + mds->server->respond_to_request(mdr, -CEPHFS_EINVAL); + return; + } + auto lock_type = lock.substr(0, colonps); + auto lock_kind = lock.substr(colonps+1, lock.size()); + dout(20) << "lock: " << lock_type << " " << lock_kind << dendl; + + SimpleLock* l; + if (lock_type == "snap") { + l = &in->snaplock; + } else if (lock_type == "policy") { + l = &in->policylock; + } else if (lock_type == "file") { + l = &in->filelock; + } else if (lock_type == "nest") { + l = &in->nestlock; + } else if (lock_type == "dft") { + l = &in->dirfragtreelock; + } else if (lock_type == "auth") { + l = &in->authlock; + } else if (lock_type == "link") { + l = &in->linklock; + } else if (lock_type == "xattr") { + l = &in->xattrlock; + } else if (lock_type == "flock") { + l = &in->flocklock; + } else { + mds->server->respond_to_request(mdr, -CEPHFS_EINVAL); + return; + } + + if (lock_kind.size() != 1) { + mds->server->respond_to_request(mdr, -CEPHFS_EINVAL); + return; + } + + switch (lock_kind[0]) { + case 'r': + lov.add_rdlock(l); + break; + case 'w': + lov.add_wrlock(l); + break; + case 'x': + lov.add_xlock(l); + break; + default: + mds->server->respond_to_request(mdr, -CEPHFS_EINVAL); + return; + } + } + + if (!mds->locker->acquire_locks(mdr, lov, nullptr, false)) { + return; + } + + /* deliberately leak until killed */ +} + +MDRequestRef MDCache::lock_path(filepath p, std::vector locks) +{ + MDRequestRef mdr = request_start_internal(CEPH_MDS_OP_LOCK_PATH); + mdr->set_filepath(p); + mdr->internal_op_finish = new LambdaContext([](int r) {}); + mdr->internal_op_private = new LockPathState{locks}; + dispatch_request(mdr); + return mdr; +} + bool MDCache::dump_inode(Formatter *f, uint64_t number) { CInode *in = get_inode(number); if (!in) { diff --git a/src/mds/MDCache.h b/src/mds/MDCache.h index d773b5fcfaf..d1daa251be5 100644 --- a/src/mds/MDCache.h +++ b/src/mds/MDCache.h @@ -527,6 +527,8 @@ class MDCache { std::map >& subtrees); ESubtreeMap *create_subtree_map(); + MDRequestRef lock_path(filepath p, std::vector locks); + void clean_open_file_lists(); void dump_openfiles(Formatter *f); bool dump_inode(Formatter *f, uint64_t number); @@ -1351,6 +1353,8 @@ class MDCache { void finish_uncommitted_fragment(dirfrag_t basedirfrag, int op); void rollback_uncommitted_fragment(dirfrag_t basedirfrag, frag_vec_t&& old_frags); + void dispatch_lock_path(MDRequestRef& mdr); + void upkeep_main(void); bool is_ready_to_trim_cache(void); diff --git a/src/mds/MDSDaemon.cc b/src/mds/MDSDaemon.cc index debd6a46cca..374c5e9a17d 100644 --- a/src/mds/MDSDaemon.cc +++ b/src/mds/MDSDaemon.cc @@ -336,6 +336,12 @@ void MDSDaemon::set_up_admin_socket() asok_hook, "trim cache and optionally request client to release all caps and flush the journal"); ceph_assert(r == 0); + r = admin_socket->register_command("lock path" + " name=path,type=CephString,req=true" + " name=locks,type=CephString,n=N,req=false" + ,asok_hook + ,"lock a path"); + ceph_assert(r == 0); r = admin_socket->register_command("cache status", asok_hook, "show cache status"); diff --git a/src/mds/MDSRank.cc b/src/mds/MDSRank.cc index 7d089e89b9c..491940639a4 100644 --- a/src/mds/MDSRank.cc +++ b/src/mds/MDSRank.cc @@ -2899,6 +2899,8 @@ void MDSRankDispatcher::handle_asok_command( } else if (command == "cache status") { std::lock_guard l(mds_lock); mdcache->cache_status(f); + } else if (command == "lock path") { + r = command_lock_path(f, cmdmap, *css); } else if (command == "dump tree") { command_dump_tree(cmdmap, *css, f); } else if (command == "dump loads") { @@ -3362,6 +3364,30 @@ void MDSRank::command_openfiles_ls(Formatter *f) mdcache->dump_openfiles(f); } +int MDSRank::command_lock_path(Formatter* f, const cmdmap_t& cmdmap, std::ostream& ss) +{ + std::string path; + { + bool got = cmd_getval(cmdmap, "path", path); + if (!got) { + ss << "missing path"; + return -CEPHFS_EINVAL; + } + } + + std::vector locks; + cmd_getval(cmdmap, "locks", locks); + + f->open_object_section("lock"); + { + std::lock_guard l(mds_lock); + auto mdr = mdcache->lock_path(filepath(path), locks); + f->dump_object("op", *mdr); + } + f->close_section(); + return 0; +} + void MDSRank::command_dump_inode(Formatter *f, const cmdmap_t &cmdmap, std::ostream &ss) { std::lock_guard l(mds_lock); diff --git a/src/mds/MDSRank.h b/src/mds/MDSRank.h index a9e8da1817a..23c3b37f8d4 100644 --- a/src/mds/MDSRank.h +++ b/src/mds/MDSRank.h @@ -525,6 +525,7 @@ class MDSRank { std::ostream &ss); void command_openfiles_ls(Formatter *f); void command_dump_tree(const cmdmap_t &cmdmap, std::ostream &ss, Formatter *f); + int command_lock_path(Formatter *f, const cmdmap_t &cmdmap, std::ostream &ss); void command_dump_inode(Formatter *f, const cmdmap_t &cmdmap, std::ostream &ss); void command_dump_dir(Formatter *f, const cmdmap_t &cmdmap, std::ostream &ss); void command_cache_drop(uint64_t timeout, Formatter *f, Context *on_finish); -- 2.39.5