From: Greg Farnum Date: Fri, 11 Jul 2014 22:20:32 +0000 (-0700) Subject: MDCache: add a scrub_dentry() function, and wire it up to the admin socket X-Git-Tag: v0.89~50^2~15 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=515ab2d5870bfdd9440c5c165489e86c73aafb74;p=ceph.git MDCache: add a scrub_dentry() function, and wire it up to the admin socket scrub_dentry() is passed a string path, and it validates it before replying. We hook up an admin socket command "scrub_path" to call it and dump the output. Signed-off-by: Greg Farnum --- diff --git a/src/include/ceph_fs.h b/src/include/ceph_fs.h index 10b52a5033ab..cf6148eee949 100644 --- a/src/include/ceph_fs.h +++ b/src/include/ceph_fs.h @@ -340,6 +340,7 @@ enum { // internal op CEPH_MDS_OP_FRAGMENTDIR= 0x01500, CEPH_MDS_OP_EXPORTDIR = 0x01501, + CEPH_MDS_OP_VALIDATE = 0x01502 }; extern const char *ceph_mds_op_name(int op); diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc index 20318cc36332..c52a90b8b3a4 100644 --- a/src/mds/MDCache.cc +++ b/src/mds/MDCache.cc @@ -11493,3 +11493,43 @@ void C_MDS_RetryRequest::finish(int r) mdr->retry++; cache->dispatch_request(mdr); } + +class C_scrub_dentry_finish : public Context { +public: + CInode::validated_data results; + MDCache *mdcache; + MDRequestRef mdr; + Context *on_finish; + Formatter *formatter; + C_scrub_dentry_finish(MDCache *mdc, MDRequestRef& mdr, + Context *fin, Formatter *f) : + mdcache(mdc), mdr(mdr), on_finish(fin), formatter(f) {} + + void finish(int r) { + CInode::dump_validation_results(results, formatter); + mdcache->request_finish(mdr); + on_finish->complete(r); + } +}; + +void MDCache::scrub_dentry(const string& path, Formatter *f, Context *fin) +{ + dout(10) << "scrub_dentry " << path << dendl; + MDRequestRef mdr = request_start_internal(CEPH_MDS_OP_VALIDATE); + set rdlocks, wrlocks, xlocks; + filepath fp(path.c_str()); + mdr->set_filepath(fp); + + // TODO: this is not actually safe with multiple MDSes! + CInode *in = mds->server->rdlock_path_pin_ref(mdr, 0, rdlocks, true); + assert(in != NULL); // TODO: obviously can't keep this, but it helps ensure authness + assert(in->is_auth()); + + bool locked = mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks); + if (!locked) + return; + C_scrub_dentry_finish *finisher = new C_scrub_dentry_finish(this, mdr, + fin, f); + in->validate_disk_state(&finisher->results, finisher); + return; +} diff --git a/src/mds/MDCache.h b/src/mds/MDCache.h index 812b4ec2402c..bd991f618a8a 100644 --- a/src/mds/MDCache.h +++ b/src/mds/MDCache.h @@ -1032,7 +1032,7 @@ public: while (n--) ++p; return p->second; } - + void scrub_dentry(const string& path, Formatter *f, Context *fin); }; class C_MDS_RetryRequest : public MDSInternalContext { diff --git a/src/mds/MDS.cc b/src/mds/MDS.cc index 5661fb51dc04..74d81f1df44d 100644 --- a/src/mds/MDS.cc +++ b/src/mds/MDS.cc @@ -286,12 +286,27 @@ bool MDS::asok_command(string command, cmdmap_t& cmdmap, string format, dout(15) << "session " << session << " not in sessionmap!" << dendl; mds_lock.Unlock(); } + } else if (command == "scrub_path") { + string path; + cmd_getval(g_ceph_context, cmdmap, "path", path); + command_scrub_path(f, path); } f->flush(ss); delete f; return true; } +void MDS::command_scrub_path(Formatter *f, const string& path) +{ + C_SaferCond scond; + { + Mutex::Locker l(mds_lock); + mdcache->scrub_dentry(path, f, &scond); + } + scond.wait(); + // scrub_dentry() finishers will dump the data for us; we're done! +} + void MDS::set_up_admin_socket() { int r; @@ -307,6 +322,10 @@ void MDS::set_up_admin_socket() r = admin_socket->register_command("dump_historic_ops", "dump_historic_ops", asok_hook, "show slowest recent ops"); + r = admin_socket->register_command("scrub_path", + "scrub_path name=path,type=CephString", + asok_hook, + "scrub an inode and output results"); assert(0 == r); r = admin_socket->register_command("session evict", "session evict name=client_id,type=CephString", @@ -326,6 +345,7 @@ void MDS::clean_up_admin_socket() admin_socket->unregister_command("status"); admin_socket->unregister_command("dump_ops_in_flight"); admin_socket->unregister_command("dump_historic_ops"); + admin_socket->unregister_command("scrub_path"); delete asok_hook; asok_hook = NULL; } diff --git a/src/mds/MDS.h b/src/mds/MDS.h index a51a5f9b032d..aac6e6760a94 100644 --- a/src/mds/MDS.h +++ b/src/mds/MDS.h @@ -375,6 +375,7 @@ private: void set_up_admin_socket(); void clean_up_admin_socket(); void check_ops_in_flight(); // send off any slow ops to monitor + void command_scrub_path(Formatter *f, const string& path); // config observer bits virtual const char** get_tracked_conf_keys() const; virtual void handle_conf_change(const struct md_config_t *conf,