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 || \
explicit MDCacheLogContext(MDCache *mdc_) : mdcache(mdc_) {}
};
+struct LockPathState {
+ std::vector<std::string> locks;
+};
+
MDCache::MDCache(MDSRank *m, PurgeQueue &purge_queue_) :
mds(m),
open_file_table(m),
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;
mdr->clear_ambiguous_auth();
if (!mdr->more()->waiting_for_finish.empty())
mds->queue_waiters(mdr->more()->waiting_for_finish);
- }
+ }
request_drop_locks(mdr);
}
}
+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<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 == "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<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);
if (!in) {
std::map<dirfrag_t,std::vector<dirfrag_t> >& subtrees);
ESubtreeMap *create_subtree_map();
+ 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);
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);
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");
} 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") {
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<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);
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);