// 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);
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<SimpleLock*> 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;
+}
while (n--) ++p;
return p->second;
}
-
+ void scrub_dentry(const string& path, Formatter *f, Context *fin);
};
class C_MDS_RetryRequest : public MDSInternalContext {
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;
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",
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;
}
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,