From: Patrick Donnelly Date: Tue, 16 Apr 2024 15:44:49 +0000 (-0400) Subject: mds: add debug "lock path" command X-Git-Tag: testing/wip-pdonnell-testing-20240425.014513-debug~2^2~3 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=7f1d066756383adae37d61cc2b2f5d99bc167f65;p=ceph-ci.git 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 --- diff --git a/src/include/ceph_fs.h b/src/include/ceph_fs.h index 49b45f26eb3..a6ee2737710 100644 --- a/src/include/ceph_fs.h +++ b/src/include/ceph_fs.h @@ -439,6 +439,7 @@ enum { 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 607a251ff9d..53c484b218b 100644 --- a/src/mds/MDCache.cc +++ b/src/mds/MDCache.cc @@ -117,6 +117,10 @@ public: explicit MDCacheLogContext(MDCache *mdc_) : mdcache(mdc_) {} }; +struct LockPathState { + std::vector locks; +}; + struct QuiesceInodeState { MDRequestRef qrmdr; std::shared_ptr qs; @@ -9702,6 +9706,7 @@ MDRequestRef MDCache::request_start_internal(int op) switch (op) { case CEPH_MDS_OP_QUIESCE_PATH: case CEPH_MDS_OP_QUIESCE_INODE: + case CEPH_MDS_OP_LOCK_PATH: params.continuous = true; break; default: @@ -9831,6 +9836,9 @@ void MDCache::dispatch_request(const MDRequestRef& mdr) case CEPH_MDS_OP_QUIESCE_INODE: dispatch_quiesce_inode(mdr); break; + case CEPH_MDS_OP_LOCK_PATH: + dispatch_lock_path(mdr); + break; case CEPH_MDS_OP_FRAGMENTDIR: dispatch_fragment_dir(mdr); break; @@ -9957,6 +9965,12 @@ void MDCache::request_cleanup(const MDRequestRef& mdr) mdr->internal_op_private = nullptr; break; } + case CEPH_MDS_OP_LOCK_PATH: { + auto* lpp = static_cast(mdr->internal_op_private); + delete lpp; + mdr->internal_op_private = nullptr; + break; + } default: break; } @@ -13895,6 +13909,99 @@ MDRequestRef MDCache::quiesce_path(filepath p, C_MDS_QuiescePath* c, Formatter * return mdr; } +void MDCache::dispatch_lock_path(const 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 == "quiesce") { + l = &in->quiescelock; + } else 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, {in}, false, true)) { + 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); diff --git a/src/mds/MDCache.h b/src/mds/MDCache.h index b7229e10b2c..212318f5169 100644 --- a/src/mds/MDCache.h +++ b/src/mds/MDCache.h @@ -629,6 +629,8 @@ private: } void add_quiesce(CInode* parent, CInode* in); + 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); @@ -1473,6 +1475,8 @@ private: void dispatch_quiesce_path(const MDRequestRef& mdr); void dispatch_quiesce_inode(const MDRequestRef& mdr); + void dispatch_lock_path(const 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 699da57e265..1ea641cf3ba 100644 --- a/src/mds/MDSDaemon.cc +++ b/src/mds/MDSDaemon.cc @@ -360,6 +360,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 678bcd5e0d3..a340e03d802 100644 --- a/src/mds/MDSRank.cc +++ b/src/mds/MDSRank.cc @@ -3003,6 +3003,8 @@ void MDSRankDispatcher::handle_asok_command( mdcache->cache_status(f); } else if (command == "quiesce path") { r = command_quiesce_path(f, cmdmap, *css); + } 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") { @@ -3534,6 +3536,30 @@ int MDSRank::command_quiesce_path(Formatter* f, const cmdmap_t& cmdmap, std::ost return 0; } +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 ea33b011ee5..de9f140d3f4 100644 --- a/src/mds/MDSRank.h +++ b/src/mds/MDSRank.h @@ -531,6 +531,7 @@ class MDSRank { void command_openfiles_ls(Formatter *f); void command_dump_tree(const cmdmap_t &cmdmap, std::ostream &ss, Formatter *f); int command_quiesce_path(Formatter *f, const cmdmap_t &cmdmap, std::ostream &ss); + 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);