]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mds: add debug "lock path" command
authorPatrick Donnelly <pdonnell@redhat.com>
Tue, 16 Apr 2024 15:44:49 +0000 (11:44 -0400)
committerPatrick Donnelly <pdonnell@redhat.com>
Mon, 22 Apr 2024 19:01:22 +0000 (15:01 -0400)
So we can have a long-running lock on an inode for certain tests.

Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
src/include/ceph_fs.h
src/mds/MDCache.cc
src/mds/MDCache.h
src/mds/MDSDaemon.cc
src/mds/MDSRank.cc
src/mds/MDSRank.h

index 49b45f26eb35b758c9a3b1818fdf2e1e783eefcf..a6ee2737710582b16eee8d664d936821f67add2e 100644 (file)
@@ -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     || \
index 607a251ff9d9107158c596b5c0c6f3f1849b345e..53c484b218b221e17a833c86c6da7df8d464dc96 100644 (file)
@@ -117,6 +117,10 @@ public:
   explicit MDCacheLogContext(MDCache *mdc_) : mdcache(mdc_) {}
 };
 
+struct LockPathState {
+  std::vector<std::string> locks;
+};
+
 struct QuiesceInodeState {
   MDRequestRef qrmdr;
   std::shared_ptr<MDCache::QuiesceStatistics> 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<LockPathState*>(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<LockPathState*>(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<std::string> 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);
index b7229e10b2c9dcf7457419c4622ac289ab70aa16..212318f516999f3afa96ec61aef9408fb7f5a157 100644 (file)
@@ -629,6 +629,8 @@ private:
   }
   void add_quiesce(CInode* parent, CInode* in);
 
+  MDRequestRef lock_path(filepath p, std::vector<std::string> 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);
index 699da57e26550d805c0c9d06b3ede2bc8b6409fe..1ea641cf3ba7852ce8586823364a8dcf6c359198 100644 (file)
@@ -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");
index 678bcd5e0d392faf43aa2eab6e012a37ea6e99cf..a340e03d8028673c8e35a739933f3edcadb553b9 100644 (file)
@@ -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<std::string> 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);
index ea33b011ee52dc7f68ac4c2cee98757b2ec64c57..de9f140d3f4d44ff12bb6b3ad0fc0e4c096919a0 100644 (file)
@@ -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);