From: Samuel Just Date: Wed, 13 Nov 2013 22:39:26 +0000 (-0800) Subject: ceph-filestore-tool: add tool for fixing lost objects X-Git-Tag: v0.73~16 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=878f3540d1a69d0ca7d2014ba7a9f3cb5cfd986d;p=ceph.git ceph-filestore-tool: add tool for fixing lost objects Used to repair: #6761 Backport: emperor Signed-off-by: Samuel Just Reviewed-by: Greg Farnum --- diff --git a/ceph.spec.in b/ceph.spec.in index 7aeca1a4ddb0..b2c9d839904f 100644 --- a/ceph.spec.in +++ b/ceph.spec.in @@ -625,6 +625,7 @@ fi %{_bindir}/ceph_smalliobenchfs %{_bindir}/ceph_smalliobenchrbd %{_bindir}/ceph_filestore_dump +%{_bindir}/ceph_filestore_tool %{_bindir}/ceph_streamtest %{_bindir}/ceph_test_cfuse_cache_invalidate %{_bindir}/ceph_test_cls_hello diff --git a/debian/ceph-test.install b/debian/ceph-test.install index 237a05850be9..30120fa58a6c 100644 --- a/debian/ceph-test.install +++ b/debian/ceph-test.install @@ -2,6 +2,7 @@ usr/bin/ceph-coverage usr/bin/ceph_bench_log usr/bin/ceph_dupstore usr/bin/ceph_filestore_dump +usr/bin/ceph_filestore_tool usr/bin/ceph_kvstorebench usr/bin/ceph_multi_stress_watch usr/bin/ceph_omapbench diff --git a/src/.gitignore b/src/.gitignore index 817fee955ffa..264f9d457b2d 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -24,6 +24,7 @@ Makefile /ceph_bench_log /ceph_dupstore /ceph_filestore_dump +/ceph_filestore_tool /ceph_mon_store_converter /ceph_multi_stress_watch /ceph_psim diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am index 89417014dd46..db86067c0bef 100644 --- a/src/tools/Makefile.am +++ b/src/tools/Makefile.am @@ -12,6 +12,13 @@ ceph_kvstore_tool_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph-kvstore-tool +ceph_filestore_tool_SOURCES = tools/ceph-filestore-tool.cc +ceph_filestore_tool_LDADD = $(LIBOSD) $(LIBOS) $(CEPH_GLOBAL) -lboost_program_options +if LINUX +ceph_filestore_tool_LDADD += -ldl +endif # LINUX +bin_PROGRAMS += ceph_filestore_tool + ceph_filestore_dump_SOURCES = tools/ceph-filestore-dump.cc ceph_filestore_dump_LDADD = $(LIBOSD) $(LIBOS) $(CEPH_GLOBAL) -lboost_program_options if LINUX diff --git a/src/tools/ceph-filestore-tool.cc b/src/tools/ceph-filestore-tool.cc new file mode 100644 index 000000000000..e9b1351d87cf --- /dev/null +++ b/src/tools/ceph-filestore-tool.cc @@ -0,0 +1,260 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2013 Inktank + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/Formatter.h" + +#include "global/global_init.h" +#include "os/ObjectStore.h" +#include "os/FileStore.h" +#include "common/perf_counters.h" +#include "common/errno.h" +#include "osd/PGLog.h" +#include "osd/osd_types.h" +#include "osd/OSD.h" + +namespace po = boost::program_options; +using namespace std; + +static void invalid_path(string &path) +{ + cout << "Invalid path to osd store specified: " << path << "\n"; + exit(1); +} + +int main(int argc, char **argv) +{ + string fspath, jpath, pgidstr; + bool list_lost_objects = false; + bool fix_lost_objects = false; + unsigned LIST_AT_A_TIME = 100; + unsigned scanned = 0; + + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "produce help message") + ("filestore-path", po::value(&fspath), + "path to filestore directory, mandatory") + ("journal-path", po::value(&jpath), + "path to journal, mandatory") + ("pgid", po::value(&pgidstr), + "PG id") + ("list-lost-objects", po::value( + &list_lost_objects)->default_value(false), + "list lost objects") + ("fix-lost-objects", po::value( + &fix_lost_objects)->default_value(false), + "fix lost objects") + ; + + po::variables_map vm; + po::parsed_options parsed = + po::command_line_parser(argc, argv).options(desc). + allow_unregistered().run(); + po::store( parsed, vm); + try { + po::notify(vm); + } + catch(...) { + cout << desc << std::endl; + exit(1); + } + + if (vm.count("help")) { + cout << desc << std::endl; + return 1; + } + + if (!vm.count("filestore-path")) { + cerr << "Must provide filestore-path" << std::endl + << desc << std::endl; + return 1; + } + if (!vm.count("journal-path")) { + cerr << "Must provide journal-path" << std::endl + << desc << std::endl; + return 1; + } + + if ((fspath.length() == 0 || jpath.length() == 0)) { + cerr << "Invalid params" << desc << std::endl; + exit(1); + } + + vector ceph_options, def_args; + vector ceph_option_strings = po::collect_unrecognized( + parsed.options, po::include_positional); + ceph_options.reserve(ceph_option_strings.size()); + for (vector::iterator i = ceph_option_strings.begin(); + i != ceph_option_strings.end(); + ++i) { + ceph_options.push_back(i->c_str()); + } + + global_init( + &def_args, ceph_options, CEPH_ENTITY_TYPE_OSD, + CODE_ENVIRONMENT_UTILITY, 0); + //CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); + common_init_finish(g_ceph_context); + g_ceph_context->_conf->apply_changes(NULL); + g_conf = g_ceph_context->_conf; + + //Verify that fspath really is an osd store + struct stat st; + if (::stat(fspath.c_str(), &st) == -1) { + perror("fspath"); + invalid_path(fspath); + } + if (!S_ISDIR(st.st_mode)) { + invalid_path(fspath); + } + string check = fspath + "/whoami"; + if (::stat(check.c_str(), &st) == -1) { + perror("whoami"); + invalid_path(fspath); + } + if (!S_ISREG(st.st_mode)) { + invalid_path(fspath); + } + check = fspath + "/current"; + if (::stat(check.c_str(), &st) == -1) { + perror("current"); + invalid_path(fspath); + } + if (!S_ISDIR(st.st_mode)) { + invalid_path(fspath); + } + + ObjectStore *fs = new FileStore(fspath, jpath); + + int r = fs->mount(); + if (r < 0) { + if (r == -EBUSY) { + cout << "OSD has the store locked" << std::endl; + } else { + cout << "Mount failed with '" << cpp_strerror(-r) << "'" << std::endl; + } + return 1; + } + + vector colls_to_check; + if (pgidstr.length()) { + pg_t pgid; + if (!pgid.parse(pgidstr.c_str())) { + cout << "Invalid pgid '" << pgidstr << "' specified" << std::endl; + exit(1); + } + colls_to_check.push_back(coll_t(pgid)); + } else { + vector candidates; + r = fs->list_collections(candidates); + if (r < 0) { + cerr << "Error listing collections: " << cpp_strerror(r) << std::endl; + goto UMOUNT; + } + for (vector::iterator i = candidates.begin(); + i != candidates.end(); + ++i) { + pg_t pgid; + snapid_t snap; + if (i->is_pg(pgid, snap)) { + colls_to_check.push_back(*i); + } + } + } + + cerr << colls_to_check.size() << " pgs to scan" << std::endl; + for (vector::iterator i = colls_to_check.begin(); + i != colls_to_check.end(); + ++i, ++scanned) { + cerr << "Scanning " << *i << ", " << scanned << "/" + << colls_to_check.size() << " completed" << std::endl; + ghobject_t next; + while (!next.is_max()) { + vector list; + r = fs->collection_list_partial( + *i, + next, + LIST_AT_A_TIME, + LIST_AT_A_TIME, + CEPH_NOSNAP, + &list, + &next); + if (r < 0) { + cerr << "Error listing collection: " << *i << ", " + << cpp_strerror(r) << std::endl; + goto UMOUNT; + } + for (vector::iterator obj = list.begin(); + obj != list.end(); + ++obj) { + bufferlist attr; + r = fs->getattr(*i, *obj, OI_ATTR, attr); + if (r < 0) { + cerr << "Error getting attr on : " << make_pair(*i, *obj) << ", " + << cpp_strerror(r) << std::endl; + goto UMOUNT; + } + object_info_t oi; + bufferlist::iterator bp = attr.begin(); + try { + ::decode(oi, bp); + } catch (...) { + r = -EINVAL; + cerr << "Error getting attr on : " << make_pair(*i, *obj) << ", " + << cpp_strerror(r) << std::endl; + goto UMOUNT; + } + if (oi.is_lost()) { + if (list_lost_objects) { + cout << *i << "/" << *obj << " is lost" << std::endl; + } + if (fix_lost_objects) { + cerr << *i << "/" << *obj << " is lost, fixing" << std::endl; + oi.clear_flag(object_info_t::FLAG_LOST); + bufferlist bl2; + ::encode(oi, bl2); + ObjectStore::Transaction t; + t.setattr(*i, *obj, OI_ATTR, bl2); + r = fs->apply_transaction(t); + if (r < 0) { + cerr << "Error getting fixing attr on : " << make_pair(*i, *obj) + << ", " + << cpp_strerror(r) << std::endl; + goto UMOUNT; + } + } + } + } + } + } + cerr << "Completed" << std::endl; + + UMOUNT: + fs->sync_and_flush(); + fs->umount(); + return r; +}