Skip to content

Commit

Permalink
tools: Create cephfs-journal-tool
Browse files Browse the repository at this point in the history
This is for debugging/repairing CephFS journals.

Signed-off-by: John Spray <[email protected]>
  • Loading branch information
John Spray committed May 20, 2014
1 parent fb8f469 commit f7e9ff1
Show file tree
Hide file tree
Showing 20 changed files with 1,785 additions and 170 deletions.
89 changes: 0 additions & 89 deletions src/ceph_mds.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ using namespace std;

#include "mon/MonMap.h"
#include "mds/MDS.h"
#include "mds/Dumper.h"
#include "mds/Resetter.h"

#include "msg/Messenger.h"

Expand All @@ -55,65 +53,14 @@ void usage()
<< " connect to monitor at given address\n"
<< " --debug_mds n\n"
<< " debug MDS level (e.g. 10)\n"
<< " --dump-journal rank filename\n"
<< " dump the MDS journal (binary) for rank.\n"
<< " --dump-journal-entries rank filename\n"
<< " dump the MDS journal (JSON) for rank.\n"
<< " --journal-check rank\n"
<< " replay the journal for rank, then exit\n"
<< " --hot-standby rank\n"
<< " start up as a hot standby for rank\n"
<< " --reset-journal rank\n"
<< " discard the MDS journal for rank, and replace it with a single\n"
<< " event that updates/resets inotable and sessionmap on replay.\n"
<< dendl;
generic_server_usage();
}

static int do_cmds_special_action(const std::string &action,
const std::string &dump_file, int rank)
{
common_init_finish(g_ceph_context, CINIT_FLAG_NO_DAEMON_ACTIONS);

if (action == "dump-journal") {
dout(0) << "dumping journal for mds." << rank << " to " << dump_file << dendl;
Dumper journal_dumper;
journal_dumper.init(rank);
journal_dumper.dump(dump_file.c_str());
journal_dumper.shutdown();
} else if (action == "dump-journal-entries") {
Dumper journal_dumper;
journal_dumper.init(rank);
journal_dumper.dump_entries();
journal_dumper.shutdown();
} else if (action == "undump-journal") {
dout(0) << "undumping journal for mds." << rank << " from " << dump_file << dendl;
Dumper journal_dumper;
journal_dumper.init(rank);
journal_dumper.undump(dump_file.c_str());
journal_dumper.shutdown();
} else if (action == "reset-journal") {
dout(0) << "resetting journal" << dendl;
Resetter resetter;
resetter.init(rank);
resetter.reset();
resetter.shutdown();
} else {
assert(0);
}
return 0;
}

static void set_special_action(std::string &dest, const std::string &act)
{
if (!dest.empty()) {
derr << "Parse error! Can't specify more than one action. You "
<< "specified both " << act << " and " << dest << "\n" << dendl;
usage();
exit(1);
}
dest = act;
}

static int parse_rank(const char *opt_name, const std::string &val)
{
Expand Down Expand Up @@ -148,44 +95,13 @@ int main(int argc, const char **argv)

// mds specific args
int shadow = 0;
int rank = -1;
std::string dump_file;

std::string val, action;
for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ) {
if (ceph_argparse_double_dash(args, i)) {
break;
}
else if (ceph_argparse_witharg(args, i, &val, "--dump-journal", (char*)NULL)) {
set_special_action(action, "dump-journal");
rank = parse_rank("dump-journal", val);
if (i == args.end()) {
derr << "error parsing --dump-journal: you must give a second "
<< "dump-journal argument: the filename to dump the journal to. "
<< "\n" << dendl;
usage();
}
dump_file = *i++;
}
else if (ceph_argparse_witharg(args, i, &val, "--undump-journal", (char*)NULL)) {
set_special_action(action, "undump-journal");
rank = parse_rank("undump-journal", val);
if (i == args.end()) {
derr << "error parsing --undump-journal: you must give a second "
<< "undump-journal argument: the filename to undump the journal from. "
<< "\n" << dendl;
usage();
}
dump_file = *i++;
}
else if (ceph_argparse_witharg(args, i, &val, "--dump-journal-entries", (char*)NULL)){
set_special_action(action, "dump-journal-entries");
rank = parse_rank("dump-journal-entries", val);
}
else if (ceph_argparse_witharg(args, i, &val, "--reset-journal", (char*)NULL)) {
set_special_action(action, "reset-journal");
rank = parse_rank("reset-journal", val);
}
else if (ceph_argparse_witharg(args, i, &val, "--journal-check", (char*)NULL)) {
int r = parse_rank("journal-check", val);
if (shadow) {
Expand Down Expand Up @@ -220,11 +136,6 @@ int main(int argc, const char **argv)

pick_addresses(g_ceph_context, CEPH_PICK_ADDRESS_PUBLIC);

// Check for special actions
if (!action.empty()) {
return do_cmds_special_action(action, dump_file, rank);
}

// Normal startup
if (g_conf->name.has_default_id()) {
derr << "must specify '-i name' with the ceph-mds instance name" << dendl;
Expand Down
6 changes: 0 additions & 6 deletions src/mds/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
libmds_la_SOURCES = \
mds/Capability.cc \
mds/Dumper.cc \
mds/Resetter.cc \
mds/MDS.cc \
mds/flock.cc \
mds/locks.c \
Expand All @@ -25,7 +23,6 @@ libmds_la_SOURCES = \
mds/snap.cc \
mds/SessionMap.cc \
mds/MDLog.cc \
mds/MDSUtility.cc \
common/TrackedOp.cc
libmds_la_LIBADD = $(LIBOSDC)
noinst_LTLIBRARIES += libmds.la
Expand All @@ -39,7 +36,6 @@ noinst_HEADERS += \
mds/CDir.h \
mds/CInode.h \
mds/Capability.h \
mds/Dumper.h \
mds/InoTable.h \
mds/LocalLock.h \
mds/Locker.h \
Expand All @@ -53,10 +49,8 @@ noinst_HEADERS += \
mds/MDSTable.h \
mds/MDSTableServer.h \
mds/MDSTableClient.h \
mds/MDSUtility.h \
mds/Mutation.h \
mds/Migrator.h \
mds/Resetter.h \
mds/ScatterLock.h \
mds/Server.h \
mds/SessionMap.h \
Expand Down
6 changes: 3 additions & 3 deletions src/mds/events/ENoOp.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
#include "../LogEvent.h"

class ENoOp : public LogEvent {
uint32_t size;
uint32_t pad_size;

public:
ENoOp() : LogEvent(EVENT_NOOP), size(0) { }
ENoOp(uint32_t size_) : LogEvent(EVENT_NOOP), size(size){ }
ENoOp() : LogEvent(EVENT_NOOP), pad_size(0) { }
ENoOp(uint32_t size_) : LogEvent(EVENT_NOOP), pad_size(size_){ }

void encode(bufferlist& bl) const;
void decode(bufferlist::iterator& bl);
Expand Down
22 changes: 13 additions & 9 deletions src/mds/journal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -857,9 +857,8 @@ void EMetaBlob::get_inodes(
void EMetaBlob::get_dentries(std::map<dirfrag_t, std::set<std::string> > &dentries)
{
for (std::map<dirfrag_t, dirlump>::iterator i = lump_map.begin(); i != lump_map.end(); ++i) {
inodeno_t const dir_ino = i->first.ino;
dirlump &dl = i->second;
dirfrag_t &df = i->first;
dirfrag_t const &df = i->first;

// Get all bits
dl._decode_bits();
Expand Down Expand Up @@ -2996,27 +2995,32 @@ void EResetJournal::replay(MDS *mds)

void ENoOp::encode(bufferlist &bl) const
{
::encode(size, bl);
uint32_t const pad_bytes = size - sizeof(size);
uint32_t const pad = 0xdeadbeef;
for (unsigned int i = 0; i < pad_bytes / sizeof(uint32_t); ++i) {
ENCODE_START(2, 2, bl);
::encode(pad_size, bl);
uint8_t const pad = 0xff;
for (unsigned int i = 0; i < pad_size; ++i) {
::encode(pad, bl);
}
ENCODE_FINISH(bl);
}


void ENoOp::decode(bufferlist::iterator &bl)
{
::decode(size, bl);
if (bl.get_remaining() != (size - sizeof(size))) {
DECODE_START(2, bl);
::decode(pad_size, bl);
if (bl.get_remaining() != pad_size) {
// This is spiritually an assertion, but expressing in a way that will let
// journal debug tools catch it and recognise a malformed entry.
throw buffer::end_of_buffer();
} else {
bl.advance(pad_size);
}
DECODE_FINISH(bl);
}


void ENoOp::replay(MDS *mds)
{
dout(4) << "ENoOp::replay, " << size << " bytes skipped in journal" << dendl;
dout(4) << "ENoOp::replay, " << pad_size << " bytes skipped in journal" << dendl;
}
19 changes: 19 additions & 0 deletions src/tools/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,18 @@ rados_SOURCES += common/obj_bencher.cc # needs cleanup so it can go in libcommon
rados_LDADD = libcls_lock_client.la $(LIBRADOS) $(CEPH_GLOBAL)
bin_PROGRAMS += rados

cephfs_journal_tool_SOURCES = \
tools/cephfs/cephfs-journal-tool.cc \
tools/cephfs/JournalTool.cc \
tools/cephfs/JournalFilter.cc \
tools/cephfs/JournalScanner.cc \
tools/cephfs/EventOutput.cc \
tools/cephfs/Dumper.cc \
tools/cephfs/Resetter.cc \
tools/cephfs/MDSUtility.cc
cephfs_journal_tool_LDADD = $(LIBMDS) $(LIBRADOS) $(CEPH_GLOBAL)
bin_PROGRAMS += cephfs-journal-tool

if WITH_REST_BENCH
rest_bench_SOURCES = tools/rest_bench.cc
rest_bench_SOURCES += common/obj_bencher.cc # needs cleanup so it can go in libcommon.la
Expand Down Expand Up @@ -99,6 +111,13 @@ ceph_mon_store_converter_LDADD = $(LIBMON) $(LIBOS) $(CEPH_GLOBAL)
bin_PROGRAMS += ceph_mon_store_converter

noinst_HEADERS += \
tools/cephfs/JournalTool.h \
tools/cephfs/JournalScanner.h \
tools/cephfs/JournalFilter.h \
tools/cephfs/EventOutput.h \
tools/cephfs/Resetter.h \
tools/cephfs/Dumper.h \
tools/cephfs/MDSUtility.h \
tools/rados/rados_sync.h \
tools/common.h

60 changes: 2 additions & 58 deletions src/mds/Dumper.cc → src/tools/cephfs/Dumper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@
#include "common/entity_name.h"
#include "common/errno.h"
#include "common/safe_io.h"
#include "mds/Dumper.h"
#include "mds/mdstypes.h"
#include "mds/LogEvent.h"
#include "osdc/Journaler.h"

#include "Dumper.h"

#define dout_subsys ceph_subsys_mds


Expand Down Expand Up @@ -219,60 +220,3 @@ void Dumper::undump(const char *dump_file)
cout << "done." << std::endl;
}


/**
* Write JSON-formatted log entries to standard out.
*/
void Dumper::dump_entries()
{
Mutex localLock("dump_entries");
JSONFormatter jf(true);

if (recover_journal()) {
return;
}

jf.open_array_section("log");
lock.Lock();
// Until the journal is empty, pop an event or wait for one to
// be available.
dout(10) << "Journaler read/write/size: "
<< journaler->get_read_pos() << "/" << journaler->get_write_pos()
<< "/" << journaler->get_write_pos() - journaler->get_read_pos() << dendl;
while (journaler->get_read_pos() != journaler->get_write_pos()) {
bufferlist entry_bl;
bool got_data = journaler->try_read_entry(entry_bl);
dout(10) << "try_read_entry: " << got_data << dendl;
if (got_data) {
LogEvent *le = LogEvent::decode(entry_bl);
if (!le) {
dout(0) << "Error decoding LogEvent" << dendl;
break;
} else {
jf.open_object_section("log_event");
jf.dump_unsigned("type", le->get_type());
jf.dump_unsigned("start_off", le->get_start_off());
jf.dump_unsigned("stamp_sec", le->get_stamp().tv.tv_sec);
jf.dump_unsigned("stamp_nsec", le->get_stamp().tv.tv_nsec);
le->dump(&jf);
jf.close_section();
delete le;
}
} else {
bool done = false;
Cond cond;

journaler->wait_for_readable(new C_SafeCond(&localLock, &cond, &done));
lock.Unlock();
localLock.Lock();
while (!done)
cond.Wait(localLock);
localLock.Unlock();
lock.Lock();
}
}
lock.Unlock();
jf.close_section();
jf.flush(cout);
return;
}
3 changes: 1 addition & 2 deletions src/mds/Dumper.h → src/tools/cephfs/Dumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#define JOURNAL_DUMPER_H_


#include "mds/MDSUtility.h"
#include "MDSUtility.h"
#include "osdc/Journaler.h"

/**
Expand All @@ -41,7 +41,6 @@ class Dumper : public MDSUtility {
int recover_journal();
void dump(const char *dumpfile);
void undump(const char *dumpfile);
void dump_entries();
};

#endif /* JOURNAL_DUMPER_H_ */
Loading

0 comments on commit f7e9ff1

Please sign in to comment.