self.mount_a.run_shell_payload("ln -s ../.. subvol_quiesce")
path = self.mount_a.cephfs_mntpt + "/subvol_quiesce"
- J = self.fs.rank_tell(["quiesce", "path", path, '--wait'])
+ J = self.fs.rank_tell(["quiesce", "path", path, '--wait'], check_status=False)
log.debug(f"{J}")
self.assertEqual(J['op']['result'], -20) # ENOTDIR: the link is not a directory
self.mount_a.run_shell_payload("ln -s ../../.. _nogroup")
path = self.mount_a.cephfs_mntpt + "/_nogroup/" + self.QUIESCE_SUBVOLUME
- J = self.fs.rank_tell(["quiesce", "path", path, '--wait'])
+ J = self.fs.rank_tell(["quiesce", "path", path, '--wait'], check_status=False)
log.debug(f"{J}")
self.assertEqual(J['op']['result'], -20) # ENOTDIR: path_traverse: the intermediate link is not a directory
self.mount_a.run_shell_payload("mkdir dir")
path = self.mount_a.cephfs_mntpt + "/dir"
- J = self.fs.rank_tell(["quiesce", "path", path, '--wait'])
+ J = self.fs.rank_tell(["quiesce", "path", path, '--wait'], check_status=False)
reqid = self._reqid_tostr(J['op']['reqid'])
self._wait_for_quiesce_complete(reqid, path=path)
self._verify_quiesce(root=path)
self.mount_a.run_shell_payload("touch file")
path = self.mount_a.cephfs_mntpt + "/file"
- J = self.fs.rank_tell(["quiesce", "path", path, '--wait'])
+ J = self.fs.rank_tell(["quiesce", "path", path, '--wait'], check_status=False)
log.debug(f"{J}")
self.assertEqual(J['op']['result'], -20) # ENOTDIR
self._configure_subvolume()
- op1 = self.fs.rank_tell(["quiesce", "path", self.subvolume])['op']
+ op1 = self.fs.rank_tell(["quiesce", "path", self.subvolume], check_status=False)['op']
op1_reqid = self._reqid_tostr(op1['reqid'])
- op2 = self.fs.rank_tell(["quiesce", "path", self.subvolume, '--wait'])['op']
+ op2 = self.fs.rank_tell(["quiesce", "path", self.subvolume, '--wait'], check_status=False)['op']
op1 = self.fs.get_op(op1_reqid)['type_data'] # for possible dup result
log.debug(f"op1 = {op1}")
log.debug(f"op2 = {op2}")
self.mount_a.run_shell_payload("touch file")
self.mount_a.setfattr("file", "ceph.quiesce.block", "1")
- J = self.fs.rank_tell(["quiesce", "path", self.subvolume, '--wait'])
+ J = self.fs.rank_tell(["quiesce", "path", self.subvolume, '--wait'], check_status=False)
log.debug(f"{J}")
self.assertEqual(J['op']['result'], 0)
self.assertEqual(J['state']['inodes_blocked'], 1)
self._configure_subvolume()
self._client_background_workload()
- J = self.fs.rank_tell(["quiesce", "path", self.subvolume])
+ J = self.fs.rank_tell(["quiesce", "path", self.subvolume], check_status=False)
log.debug(f"{J}")
reqid = self._reqid_tostr(J['op']['reqid'])
self._wait_for_quiesce_complete(reqid)
# drop cache
self.fs.rank_tell(["cache", "drop"])
- J = self.fs.rank_tell(["quiesce", "path", self.subvolume])
+ J = self.fs.rank_tell(["quiesce", "path", self.subvolume], check_status=False)
log.debug(f"{J}")
reqid = self._reqid_tostr(J['op']['reqid'])
self._wait_for_quiesce_complete(reqid)
self._client_background_workload()
self._wait_distributed_subtrees(2*2, rank="all", path=self.mntpnt)
- op = self.fs.rank_tell(["quiesce", "path", self.subvolume, '--wait'], rank=0)['op']
+ op = self.fs.rank_tell(["quiesce", "path", self.subvolume, '--wait'], rank=0, check_status=False)['op']
self.assertEqual(op['result'], -1) # EPERM
@unittest.skip("https://tracker.ceph.com/issues/66152")
sleep(2)
- op0 = self.fs.rank_tell(["quiesce", "path", self.subvolume], rank=0)['op']
- op1 = self.fs.rank_tell(["quiesce", "path", self.subvolume], rank=1)['op']
+ op0 = self.fs.rank_tell(["quiesce", "path", self.subvolume], rank=0, check_status=False)['op']
+ op1 = self.fs.rank_tell(["quiesce", "path", self.subvolume], rank=1, check_status=False)['op']
reqid0 = self._reqid_tostr(op0['reqid'])
reqid1 = self._reqid_tostr(op1['reqid'])
op0 = self._wait_for_quiesce_complete(reqid0, rank=0, timeout=300)
std::lock_guard l(mds_lock);
mdcache->cache_status(f);
} else if (command == "quiesce path") {
- r = command_quiesce_path(f, cmdmap, *css);
+ command_quiesce_path(f, cmdmap, std::move(on_finish));
+ return;
} else if (command == "lock path") {
command_lock_path(f, cmdmap, std::move(on_finish));
return;
class C_MDS_QuiescePathCommand : public MDCache::C_MDS_QuiescePath {
public:
- C_MDS_QuiescePathCommand(MDCache* cache, Context* fin) : C_MDS_QuiescePath(cache), finisher(fin) {}
+ C_MDS_QuiescePathCommand(MDCache* cache) : C_MDS_QuiescePath(cache) {}
void finish(int rc) override {
- if (finisher) {
- finisher->complete(rc);
- finisher = nullptr;
+ if (auto fin = std::move(finish_once)) {
+ fin(rc, *this);
}
}
-private:
- Context* finisher = nullptr;
+ std::function<void(int, C_MDS_QuiescePathCommand const&)> finish_once;
};
-int MDSRank::command_quiesce_path(Formatter* f, const cmdmap_t& cmdmap, std::ostream& ss)
+void MDSRank::command_quiesce_path(Formatter* f, const cmdmap_t& cmdmap, std::function<void(int, const std::string&, bufferlist&)> on_finish)
{
std::string path;
- {
- bool got = cmd_getval(cmdmap, "path", path);
- if (!got) {
- ss << "missing path";
- return -CEPHFS_EINVAL;
- }
+ if (!cmd_getval(cmdmap, "path", path)) {
+ bufferlist bl;
+ on_finish(-EINVAL, "missing path", bl);
+ return;
}
- bool wait = false;
- cmd_getval(cmdmap, "wait", wait);
+ bool wait = cmd_getval_or<bool>(cmdmap, "wait", false);
C_SaferCond cond;
- auto* finisher = new C_MDS_QuiescePathCommand(mdcache, wait ? &cond : nullptr);
- auto qs = finisher->qs;
- MDRequestRef mdr;
- f->open_object_section("quiesce");
- {
- std::lock_guard l(mds_lock);
- mdr = mdcache->quiesce_path(filepath(path), finisher, f);
- if (!wait) {
- f->dump_object("op", *mdr);
- }
- }
- if (wait) {
- cond.wait();
- std::lock_guard l(mds_lock);
- f->dump_object("op", *mdr);
+ auto* quiesce_ctx = new C_MDS_QuiescePathCommand(mdcache);
+
+ quiesce_ctx->finish_once = [f, respond = std::move(on_finish)](int cephrc, C_MDS_QuiescePathCommand const& cmd) {
+ f->open_object_section("response");
+ f->dump_object("op", *cmd.mdr);
+ f->dump_object("state", *cmd.qs);
+ f->close_section();
+
+ bufferlist bl;
+ // need to do this manually, because the default asok
+ // on_finish handler doesn't flush the formatter for rc < 0
+ f->flush(bl);
+ auto rc = cephrc < 0 ? -ceph_to_hostos_errno(-cephrc) : cephrc;
+ respond(rc, "", bl);
+ };
+
+ std::lock_guard l(mds_lock);
+
+ auto mdr = mdcache->quiesce_path(filepath(path), quiesce_ctx, f);
+
+ // This is a little ugly, apologies.
+ // We should still be under the mds lock for this test to be valid.
+ // MDCache will delete the quiesce_ctx if it manages to complete syncrhonously,
+ // so we are testing the `mdr->internal_op_finish` to see if that has happend
+ if (!wait && mdr && mdr->internal_op_finish) {
+ ceph_assert(mdr->internal_op_finish == quiesce_ctx);
+ quiesce_ctx->finish(mdr->result.value_or(0));
}
- f->dump_object("state", *qs);
- f->close_section();
- return 0;
}
void MDSRank::command_lock_path(Formatter* f, const cmdmap_t& cmdmap, std::function<void(int, const std::string&, bufferlist&)> on_finish)