From: simon gao Date: Tue, 6 Aug 2019 09:58:58 +0000 (-0400) Subject: tool: add cephfs-meta-injection to show and amend info of inode X-Git-Tag: v16.1.0~2784^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=974b37a45d043f1cd7f4e501d1bfe3aa7f64c317;p=ceph.git tool: add cephfs-meta-injection to show and amend info of inode Signed-off-by: simon gao --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7ae4f162af8a..460dde54a506 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -829,6 +829,7 @@ add_custom_target(cephfs_testing DEPENDS ceph-fuse ceph-dencoder cephfs-journal-tool + cephfs-meta-injection cephfs-data-scan cephfs-table-tool) diff --git a/src/common/ceph_json.cc b/src/common/ceph_json.cc index 50906a42e6d9..7250b147c4dc 100644 --- a/src/common/ceph_json.cc +++ b/src/common/ceph_json.cc @@ -478,6 +478,19 @@ void decode_json_obj(utime_t& val, JSONObj *obj) } } +void decode_json_obj(ceph_dir_layout& i, JSONObj *obj){ + + unsigned tmp; + JSONDecoder::decode_json("dir_hash", tmp, obj, true); + i.dl_dir_hash = tmp; + JSONDecoder::decode_json("unused1", tmp, obj, true); + i.dl_unused1 = tmp; + JSONDecoder::decode_json("unused2", tmp, obj, true); + i.dl_unused2 = tmp; + JSONDecoder::decode_json("unused3", tmp, obj, true); + i.dl_unused3 = tmp; +} + void encode_json(const char *name, const string& val, Formatter *f) { f->dump_string(name, val); diff --git a/src/common/ceph_json.h b/src/common/ceph_json.h index 938b6f87fca0..b22882b173cf 100644 --- a/src/common/ceph_json.h +++ b/src/common/ceph_json.h @@ -5,12 +5,12 @@ #include #include #include +#include #include "json_spirit/json_spirit.h" #include "Formatter.h" -using namespace json_spirit; class JSONObj; @@ -168,6 +168,7 @@ void decode_json_obj(bool& val, JSONObj *obj); void decode_json_obj(ceph::buffer::list& val, JSONObj *obj); class utime_t; void decode_json_obj(utime_t& val, JSONObj *obj); +void decode_json_obj(ceph_dir_layout& i, JSONObj *obj); template void decode_json_obj(std::list& l, JSONObj *obj) diff --git a/src/common/fs_types.cc b/src/common/fs_types.cc index 0dd5528eaa2e..47021e360f8c 100644 --- a/src/common/fs_types.cc +++ b/src/common/fs_types.cc @@ -4,6 +4,7 @@ #include "include/fs_types.h" #include "common/Formatter.h" #include "include/ceph_features.h" +#include "common/ceph_json.h" void dump(const ceph_file_layout& l, ceph::Formatter *f) { @@ -120,6 +121,15 @@ void file_layout_t::dump(ceph::Formatter *f) const f->dump_string("pool_ns", pool_ns); } +void file_layout_t::decode_json(JSONObj *obj){ + + JSONDecoder::decode_json("stripe_unit", stripe_unit, obj, true); + JSONDecoder::decode_json("stripe_count", stripe_count, obj, true); + JSONDecoder::decode_json("object_size", object_size, obj, true); + JSONDecoder::decode_json("pool_id", pool_id, obj, true); + JSONDecoder::decode_json("pool_ns", pool_ns, obj, true); +} + void file_layout_t::generate_test_instances(std::list& o) { o.push_back(new file_layout_t); diff --git a/src/include/fs_types.h b/src/include/fs_types.h index 091f39f4b665..757eb194b216 100644 --- a/src/include/fs_types.h +++ b/src/include/fs_types.h @@ -4,6 +4,7 @@ #define CEPH_INCLUDE_FS_TYPES_H #include "types.h" +class JSONObj; // -------------------------------------- // ino @@ -114,6 +115,7 @@ struct file_layout_t { void encode(ceph::buffer::list& bl, uint64_t features) const; void decode(ceph::buffer::list::const_iterator& p); void dump(ceph::Formatter *f) const; + void decode_json(JSONObj *obj); static void generate_test_instances(std::list& o); }; WRITE_CLASS_ENCODER_FEATURES(file_layout_t) diff --git a/src/mds/CInode.cc b/src/mds/CInode.cc index 57908d996518..0de21439be18 100644 --- a/src/mds/CInode.cc +++ b/src/mds/CInode.cc @@ -4350,6 +4350,43 @@ void InodeStoreBase::dump(Formatter *f) const f->dump_unsigned("damage_flags", damage_flags); } +template <> +void decode_json_obj(mempool::mds_co::string& t, JSONObj *obj){ + + t = mempool::mds_co::string(std::string_view(obj->get_data())); +} + +void InodeStoreBase::decode_json(JSONObj *obj){ + + inode.decode_json(obj); + JSONDecoder::decode_json("symlink", symlink, obj, true); + // JSONDecoder::decode_json("dirfragtree", dirfragtree, obj, true); // cann't decode it now + JSONDecoder::decode_json("xattrs", InodeStoreBase::xattrs, xattrs_cb, obj, true); + // JSONDecoder::decode_json("old_inodes", old_inodes, InodeStoreBase::old_indoes_cb, obj, true); // cann't decode old_inodes now + JSONDecoder::decode_json("oldest_snap", oldest_snap.val, obj, true); + JSONDecoder::decode_json("damage_flags", damage_flags, obj, true); + //sr_t srnode; + //JSONDecoder::decode_json("snap_blob", srnode, obj, true); // cann't decode it now + //snap_blob = srnode; +} + +void InodeStoreBase::xattrs_cb(InodeStoreBase::mempool_xattr_map& c, JSONObj *obj){ + + string k; + JSONDecoder::decode_json("key", k, obj, true); + string v; + JSONDecoder::decode_json("val", v, obj, true); + c[k.c_str()] = buffer::copy(v.c_str(), v.size()); +} + +void InodeStoreBase::old_indoes_cb(InodeStoreBase::mempool_old_inode_map& c, JSONObj *obj){ + + snapid_t s; + JSONDecoder::decode_json("last", s.val, obj, true); + InodeStoreBase::mempool_old_inode i; + // i.decode_json(obj); // cann't decode now, simon + c[s] = i; +} void InodeStore::generate_test_instances(std::list &ls) { diff --git a/src/mds/CInode.h b/src/mds/CInode.h index 64295f651fb5..e76fd2b3f307 100644 --- a/src/mds/CInode.h +++ b/src/mds/CInode.h @@ -91,6 +91,10 @@ public: /* For test/debug output */ void dump(ceph::Formatter *f) const; + void decode_json(JSONObj *obj); + static void xattrs_cb(InodeStoreBase::mempool_xattr_map& c, JSONObj *obj); + static void old_indoes_cb(InodeStoreBase::mempool_old_inode_map& c, JSONObj *obj); + /* For use by offline tools */ __u32 hash_dentry_name(std::string_view dn); frag_t pick_dirfrag(std::string_view dn); diff --git a/src/mds/mdstypes.cc b/src/mds/mdstypes.cc index abe459dfb14e..360a8fc6db5c 100644 --- a/src/mds/mdstypes.cc +++ b/src/mds/mdstypes.cc @@ -55,6 +55,15 @@ void frag_info_t::dump(Formatter *f) const f->dump_unsigned("change_attr", change_attr); } +void frag_info_t::decode_json(JSONObj *obj){ + + JSONDecoder::decode_json("version", version, obj, true); + //JSONDecoder::decode_json("mtime", mtime, obj, true); // remove now + JSONDecoder::decode_json("num_files", nfiles, obj, true); + JSONDecoder::decode_json("num_subdirs", nsubdirs, obj, true); + JSONDecoder::decode_json("change_attr", change_attr, obj, true); +} + void frag_info_t::generate_test_instances(std::list& ls) { ls.push_back(new frag_info_t); @@ -126,6 +135,16 @@ void nest_info_t::dump(Formatter *f) const f->dump_stream("rctime") << rctime; } +void nest_info_t::decode_json(JSONObj *obj){ + + JSONDecoder::decode_json("version", version, obj, true); + JSONDecoder::decode_json("rbytes", rbytes, obj, true); + JSONDecoder::decode_json("rfiles", rfiles, obj, true); + JSONDecoder::decode_json("rsubdirs", rsubdirs, obj, true); + JSONDecoder::decode_json("rsnaps", rsnaps, obj, true); + //JSONDecoder::decode_json("rctime", rctime, obj, true); // remove now +} + void nest_info_t::generate_test_instances(std::list& ls) { ls.push_back(new nest_info_t); @@ -164,6 +183,12 @@ void quota_info_t::dump(Formatter *f) const f->dump_int("max_files", max_files); } +void quota_info_t::decode_json(JSONObj *obj){ + + JSONDecoder::decode_json("max_bytes", max_bytes, obj, true); + JSONDecoder::decode_json("max_files", max_files, obj, true); +} + void quota_info_t::generate_test_instances(std::list& ls) { ls.push_back(new quota_info_t); @@ -212,6 +237,12 @@ void client_writeable_range_t::dump(Formatter *f) const f->dump_unsigned("follows", follows); } +void client_writeable_range_t::byte_range_t::decode_json(JSONObj *obj){ + + JSONDecoder::decode_json("first", first, obj, true); + JSONDecoder::decode_json("last", last, obj, true); +} + void client_writeable_range_t::generate_test_instances(std::list& ls) { ls.push_back(new client_writeable_range_t); diff --git a/src/mds/mdstypes.h b/src/mds/mdstypes.h index e2c61bfb2330..3f46860e78b5 100644 --- a/src/mds/mdstypes.h +++ b/src/mds/mdstypes.h @@ -30,6 +30,7 @@ #include #include "include/ceph_assert.h" #include +#include "common/ceph_json.h" #define CEPH_FS_ONDISK_MAGIC "ceph fs volume v011" @@ -189,6 +190,7 @@ struct frag_info_t : public scatter_info_t { void encode(ceph::buffer::list &bl) const; void decode(ceph::buffer::list::const_iterator& bl); void dump(ceph::Formatter *f) const; + void decode_json(JSONObj *obj); static void generate_test_instances(std::list& ls); // this frag @@ -249,6 +251,7 @@ struct nest_info_t : public scatter_info_t { void encode(ceph::buffer::list &bl) const; void decode(ceph::buffer::list::const_iterator& bl); void dump(ceph::Formatter *f) const; + void decode_json(JSONObj *obj); static void generate_test_instances(std::list& ls); // this frag + children @@ -325,6 +328,7 @@ struct quota_info_t bool is_enable() const { return max_bytes || max_files; } + void decode_json(JSONObj *obj); int64_t max_bytes = 0; int64_t max_files = 0; @@ -359,6 +363,8 @@ inline std::ostream& operator<<(std::ostream &out, const vinodeno_t &vino) { struct client_writeable_range_t { struct byte_range_t { uint64_t first = 0, last = 0; // interval client can write to + byte_range_t() {} + void decode_json(JSONObj *obj); }; void encode(ceph::buffer::list &bl) const; @@ -528,6 +534,9 @@ struct inode_t { void encode(ceph::buffer::list &bl, uint64_t features) const; void decode(ceph::buffer::list::const_iterator& bl); void dump(ceph::Formatter *f) const; + static void client_ranges_cb(client_range_map& c, JSONObj *obj); + static void old_pools_cb(compact_set, Allocator >& c, JSONObj *obj); + void decode_json(JSONObj *obj); static void generate_test_instances(std::list& ls); /** * Compare this inode_t with another that represent *the same inode* @@ -832,6 +841,65 @@ void inode_t::dump(ceph::Formatter *f) const f->dump_unsigned("last_scrub_version", last_scrub_version); } +template class Allocator> +void inode_t::client_ranges_cb(typename inode_t::client_range_map& c, JSONObj *obj){ + + int64_t client; + JSONDecoder::decode_json("client", client, obj, true); + client_writeable_range_t client_range_tmp; + JSONDecoder::decode_json("byte range", client_range_tmp.range, obj, true); + JSONDecoder::decode_json("follows", client_range_tmp.follows.val, obj, true); + c[client] = client_range_tmp; +} + +template class Allocator> +void inode_t::old_pools_cb(compact_set, Allocator >& c, JSONObj *obj){ + + int64_t tmp; + decode_json_obj(tmp, obj); + c.insert(tmp); +} + +template class Allocator> +void inode_t::decode_json(JSONObj *obj) +{ + + JSONDecoder::decode_json("ino", ino.val, obj, true); + JSONDecoder::decode_json("rdev", rdev, obj, true); + //JSONDecoder::decode_json("ctime", ctime, obj, true); + //JSONDecoder::decode_json("btime", btime, obj, true); + JSONDecoder::decode_json("mode", mode, obj, true); + JSONDecoder::decode_json("uid", uid, obj, true); + JSONDecoder::decode_json("gid", gid, obj, true); + JSONDecoder::decode_json("nlink", nlink, obj, true); + JSONDecoder::decode_json("dir_layout", dir_layout, obj, true); + JSONDecoder::decode_json("layout", layout, obj, true); + JSONDecoder::decode_json("old_pools", old_pools, inode_t::old_pools_cb, obj, true); + JSONDecoder::decode_json("size", size, obj, true); + JSONDecoder::decode_json("truncate_seq", truncate_seq, obj, true); + JSONDecoder::decode_json("truncate_size", truncate_size, obj, true); + JSONDecoder::decode_json("truncate_from", truncate_from, obj, true); + JSONDecoder::decode_json("truncate_pending", truncate_pending, obj, true); + //JSONDecoder::decode_json("mtime", mtime, obj, true); + //JSONDecoder::decode_json("atime", atime, obj, true); + JSONDecoder::decode_json("time_warp_seq", time_warp_seq, obj, true); + JSONDecoder::decode_json("change_attr", change_attr, obj, true); + JSONDecoder::decode_json("export_pin", export_pin, obj, true); + JSONDecoder::decode_json("client_ranges", client_ranges, inode_t::client_ranges_cb, obj, true); + JSONDecoder::decode_json("dirstat", dirstat, obj, true); + JSONDecoder::decode_json("rstat", rstat, obj, true); + JSONDecoder::decode_json("accounted_rstat", accounted_rstat, obj, true); + JSONDecoder::decode_json("version", version, obj, true); + JSONDecoder::decode_json("file_data_version", file_data_version, obj, true); + JSONDecoder::decode_json("xattr_version", xattr_version, obj, true); + JSONDecoder::decode_json("backtrace_version", backtrace_version, obj, true); + JSONDecoder::decode_json("stray_prior_path", stray_prior_path, obj, true); + JSONDecoder::decode_json("max_size_ever", max_size_ever, obj, true); + JSONDecoder::decode_json("quota", quota, obj, true); + JSONDecoder::decode_json("last_scrub_stamp", last_scrub_stamp, obj, true); + JSONDecoder::decode_json("last_scrub_version", last_scrub_version, obj, true); +} + template class Allocator> void inode_t::generate_test_instances(std::list& ls) { diff --git a/src/tools/cephfs/CMakeLists.txt b/src/tools/cephfs/CMakeLists.txt index f980f35f5ff1..a739fb5d704b 100644 --- a/src/tools/cephfs/CMakeLists.txt +++ b/src/tools/cephfs/CMakeLists.txt @@ -12,6 +12,15 @@ add_executable(cephfs-journal-tool ${cephfs_journal_tool_srcs}) target_link_libraries(cephfs-journal-tool librados mds osdc global ${BLKID_LIBRARIES} ${CMAKE_DL_LIBS}) +set(cephfs-meta-injection_srcs + cephfs-meta-injection.cc + MetaTool.cc + RoleSelector.cc + MDSUtility.cc) +add_executable(cephfs-meta-injection ${cephfs-meta-injection_srcs}) +target_link_libraries(cephfs-meta-injection librados mds osdc global + ${BLKID_LIBRARIES} ${CMAKE_DL_LIBS}) + set(cephfs_table_tool_srcs cephfs-table-tool.cc TableTool.cc diff --git a/src/tools/cephfs/MetaTool.cc b/src/tools/cephfs/MetaTool.cc new file mode 100644 index 000000000000..1b3660389abb --- /dev/null +++ b/src/tools/cephfs/MetaTool.cc @@ -0,0 +1,814 @@ +#include +#include +#include +#include + +#include "include/types.h" +#include "common/Formatter.h" +#include "common/ceph_argparse.h" +#include "common/errno.h" +#include "osdc/Journaler.h" +#include "mds/mdstypes.h" +#include "mds/LogEvent.h" +#include "mds/InoTable.h" + +#include "mds/events/ENoOp.h" +#include "mds/events/EUpdate.h" + +#include "mds/JournalPointer.h" +// #include "JournalScanner.h" +// #include "EventOutput.h" +// #include "Dumper.h" +// #include "Resetter.h" + +// #include "JournalTool.h" +#include "MetaTool.h" +#include "type_helper.hpp" +#include "include/object.h" + +WRITE_RAW_ENCODER(char) +WRITE_RAW_ENCODER(unsigned char) + +#define dout_context g_ceph_context +#define dout_subsys ceph_subsys_mds +#undef dout_prefix +#define dout_prefix *_dout << __func__ << ": " + + +void MetaTool::meta_op::release(){ + for (const auto& i : inodes) { + delete i.second; + } + while(!sub_ops.empty()){ + delete sub_ops.top(); + sub_ops.pop(); + } +} + +void MetaTool::inode_meta_t::decode_json(JSONObj *obj){ + unsigned long long tmp; + JSONDecoder::decode_json("snapid_t", tmp, obj, true); + _f.val = tmp; + JSONDecoder::decode_json("itype", tmp, obj, true); + _t = tmp; + if (NULL == _i) + _i = new InodeStore; + JSONDecoder::decode_json("store", *_i, obj, true); +} + +void MetaTool::usage(){ + generic_client_usage(); +} + +int MetaTool::main(string& mode, + string& rank_str, + string& minfo, + string&ino, + string& out, + string& in, + bool confirm + ){ + int r = 0; + + std::string manual_meta_pool; + std::string manual_data_pool; + std::string manual_rank_num; + bool manual_mode = false; + if (minfo != ""){ + vector v; + string_split(minfo, v); + manual_meta_pool = v.size() >= 1?v[0]:""; + manual_data_pool = v.size() >= 2?v[1]:""; + manual_rank_num = v.size() >= 3?v[2]:""; + std::cout << "("<< minfo<< ")=>" + << " mpool: " << manual_meta_pool + << " dpool: " << manual_data_pool + << " rank: " << manual_rank_num + << std::endl; + if (!manual_meta_pool.empty() && !manual_data_pool.empty() && !manual_rank_num.empty()){ + std::cout << "you specify rank: " << manual_rank_num + << " mpool: " << manual_meta_pool + << " dpool: " << manual_data_pool + << "\nstart manual mode!!"<< std::endl; + manual_mode = true; + } + } + + // RADOS init + r = rados.init_with_context(g_ceph_context); + if (r < 0) { + cerr << "RADOS unavailable" << std::endl; + return r; + } + + if(_debug) + cout << "MetaTool: connecting to RADOS..." << std::endl; + r = rados.connect(); + if (r < 0) { + cerr << "couldn't connect to cluster: " << cpp_strerror(r) << std::endl; + return r; + } + + if (!manual_mode){ + r = role_selector.parse(*fsmap, rank_str); + if (r != 0) { + cerr << "Couldn't determine MDS rank." << std::endl; + return r; + } + + auto fs = fsmap->get_filesystem(role_selector.get_ns()); + assert(fs != nullptr); + + // prepare io for meta pool + int64_t const pool_id = fs->mds_map.get_metadata_pool(); + features = fs->mds_map.get_up_features(); + if (features == 0) + features = CEPH_FEATURES_SUPPORTED_DEFAULT; + else if (features != CEPH_FEATURES_SUPPORTED_DEFAULT){ + cout << "I think we need to check the feature! : " << features << std::endl; + return -1; + } + + std::string pool_name; + r = rados.pool_reverse_lookup(pool_id, &pool_name); + if (r < 0) { + cerr << "Pool " << pool_id << " named in MDS map not found in RADOS!" << std::endl; + return r; + } + + if (_debug) + cout << "MetaTool: creating IoCtx.." << std::endl; + r = rados.ioctx_create(pool_name.c_str(), io_meta); + assert(r == 0); + output.dup(io_meta); + + // prepare io for data pool + const std::vector & data_pools_v = fs->mds_map.get_data_pools(); + for(auto i = data_pools_v.begin(); i != data_pools_v.end(); ++i){ + r = rados.pool_reverse_lookup(*i, &pool_name); + if (r < 0) { + cerr << "Pool " << pool_id << " named in MDS map not found in RADOS!" << std::endl; + return r; + } + librados::IoCtx* io_data = new librados::IoCtx; + r = rados.ioctx_create(pool_name.c_str(), *io_data); + assert(r == 0); + io_data_v.push_back(io_data); + } + + for (auto role : role_selector.get_roles()) { + rank = role.rank; + + int ret = process(mode, ino, out, in, confirm); + cout << "executing for rank " << rank << " op[" <(manual_rank_num); + int ret = process(mode, ino, out, in, confirm); + cout << "op[" << mode << "] ret : " << ret << std::endl; + } + return r; +} + +int MetaTool::process(string& mode, string& ino, string out, string in, bool confirm){ + if (mode == "showm") { + return show_meta_info(ino, out); + }else if (mode == "listc") { + return list_meta_info(ino, out); + }else if (mode == "amend") { + return amend_meta_info(ino, in, confirm); + }else { + cerr << "bad command '" << mode << "'" << std::endl; + return -EINVAL; + } +} + +int MetaTool::amend_meta_info(string& ino, string& in, bool confirm){ + if (ino != "0" && in != ""){ + inodeno_t i_ino = conv2hexino(ino.c_str()); + meta_op op(_debug, "", in, confirm); + meta_op::sub_op* nsop = new meta_op::sub_op(&op); + nsop->sub_op_t = meta_op::OP_AMEND; + nsop->sub_ino_t = meta_op::INO_DIR; + nsop->ino = i_ino; + op.push_op(nsop); + return op_process(op); + }else{ + cerr << "parameter error? : ino = " << ino << std::endl; + } + return 0; +} +int MetaTool::list_meta_info(string& ino, string& out){ + if (ino != "0") { + inodeno_t i_ino = conv2hexino(ino.c_str()); + meta_op op(_debug, out); + meta_op::sub_op* nsop = new meta_op::sub_op(&op); + nsop->sub_op_t = meta_op::OP_LIST; + nsop->sub_ino_t = meta_op::INO_DIR; + nsop->ino = i_ino; + op.push_op(nsop); + return op_process(op); + }else{ + cerr << "parameter error? : ino = " << ino << std::endl; + } + return 0; +} +int MetaTool::show_meta_info(string& ino, string& out){ + if (ino != "0"){ + inodeno_t i_ino = conv2hexino(ino.c_str()); + meta_op op(_debug, out); + + meta_op::sub_op* nsop = new meta_op::sub_op(&op); + nsop->sub_op_t = meta_op::OP_SHOW; + nsop->sub_ino_t = meta_op::INO_DIR; + nsop->ino = i_ino; + op.push_op(nsop); + return op_process(op); + }else{ + cerr << "parameter error? : ino = " << ino << std::endl; + } + return 0; +} + +int MetaTool::op_process(meta_op& op){ + int r = 0; + while(!op.no_sops()){ + if (_debug) + std::cout << "process : " << op.top_op()->detail() << std::endl; + switch(op.top_op()->sub_op_t){ + case meta_op::OP_LIST: + r = list_meta(op); + break; + case meta_op::OP_LTRACE: + r = file_meta(op); + break; + case meta_op::OP_SHOW: + r = show_meta(op); + break; + case meta_op::OP_AMEND: + r = amend_meta(op); + break; + default: + cerr << "unknow op" << std::endl; + } + if (r == 0) + op.pop_op(); + else if (r < 0) + op.clear_sops(); + } + op.release(); + return r; +} + +int MetaTool::amend_meta(meta_op &op){ + meta_op::sub_op* sop = op.top_op(); + auto item = op.inodes.find(sop->ino); + auto item_k = op.okeys.find(sop->ino); + if (item != op.inodes.end() && item_k != op.okeys.end()){ + if (_amend_meta(item_k->second, *(item->second), op.infile(), op) < 0) + return -1; + }else{ + if (op.inodes.empty()){ + meta_op::sub_op* nsop = new meta_op::sub_op(&op); + nsop->sub_op_t = meta_op::OP_LIST; + nsop->sub_ino_t = meta_op::INO_DIR; + nsop->trace_level = 0; + nsop->ino_c = sop->ino; + op.push_op(nsop); + return 1; + }else{ + return -1; + } + } + return 0; +} + +void MetaTool::inode_meta_t::encode(::ceph::bufferlist& bl, uint64_t features){ + ::encode(_f, bl); + ::encode(_t, bl); + _i->encode_bare(bl, features); +} +int MetaTool::_amend_meta(string& k, inode_meta_t& inode_meta, const string& fn, meta_op& op){ + JSONParser parser; + if(!parser.parse(fn.c_str())) { + cout << "Error parsing create user response" << std::endl; + return -1; + } + try { + inode_meta.decode_json(&parser); + } catch (JSONDecoder::err& e) { + cout << "failed to decode JSON input: " << e.what() << std::endl; + return -1; + } + if (!op.confirm_chg() || op.is_debug()){ + cout << "you will amend info of inode ==>: " << std::endl; + _show_meta(inode_meta, ""); + } + if (!op.confirm_chg()){ + cout << "warning: this operation is irreversibl!!!\n" + << " You must confirm that all logs of mds have been flushed!!!\n" + << " if you want amend it, please add --yes-i-really-really-mean-it!!!" + << std::endl; + + } + bufferlist bl; + inode_meta.encode(bl, features); + map to_set; + to_set[k].swap(bl); + inode_backpointer_t bp; + if (!op.top_op()->get_ancestor(bp)) + return false; + frag_t frag; + auto item = op.inodes.find(bp.dirino); + if (item != op.inodes.end()){ + frag = item->second->get_meta()->pick_dirfrag(bp.dname); + } + string oid = obj_name(bp.dirino, frag); + int ret = io_meta.omap_set(oid, to_set); + to_set.clear(); + return ret; +} + +int MetaTool::show_meta(meta_op &op){ + meta_op::sub_op* sop = op.top_op(); + auto item = op.inodes.find(sop->ino); + if (item != op.inodes.end()){ + if (_show_meta(*(item->second), op.outfile()) < 0) + return -1; + }else{ + if (op.inodes.empty()){ + meta_op::sub_op* nsop = new meta_op::sub_op(&op); + nsop->sub_op_t = meta_op::OP_LIST; + nsop->sub_ino_t = meta_op::INO_DIR; + nsop->trace_level = 0; + nsop->ino_c = sop->ino; + op.push_op(nsop); + return 1; + }else{ + return -1; + } + } + return 0; +} +int MetaTool::_show_meta(inode_meta_t& inode_meta, const string& fn){ + std::stringstream ds; + std::string format = "json"; + InodeStore& inode_data = *inode_meta.get_meta(); + Formatter* f = Formatter::create(format); + f->enable_line_break(); + f->open_object_section("meta"); + f->dump_unsigned("snapid_t", inode_meta.get_snapid()); + f->dump_unsigned("itype", inode_meta.get_type()); + f->open_object_section("store"); + inode_data.dump(f); + try { + if (inode_data.snap_blob.length()){ + sr_t srnode; + auto p = inode_data.snap_blob.cbegin(); + decode(srnode, p); + f->open_object_section("snap_blob"); + srnode.dump(f); + f->close_section(); + } + }catch (const buffer::error &err){ + cerr << "corrupt decode in snap_blob" + << ": " << err << std::endl; + return -1; + } + + f->close_section(); + f->close_section(); + f->flush(ds); + + if (fn != ""){ + ofstream o; + o.open(fn); + if (o){ + o << ds.str(); + o.close(); + } + else{ + cout << "out to file (" << fn << ") failed" << std::endl; + cout << ds.str() << std::endl; + } + + }else + std::cout << ds.str() << std::endl; + return 0; +} +int MetaTool::list_meta(meta_op &op){ + meta_op::sub_op* sop = op.top_op(); + + bool list_all = false; + string oid; + inodeno_t ino = sop->ino_c; + frag_t frag = sop->frag; + + if (sop->ino_c == 0){ + list_all = true; + oid = obj_name(sop->ino, frag); + }else { + if (_debug) + std::cout << __func__ << " : " << sop->trace_level << " " << op.ancestors.size() << std::endl; + inode_backpointer_t bp; + if (sop->get_c_ancestor(bp)){ + auto item = op.inodes.find(bp.dirino); + if (item != op.inodes.end()){ + frag = item->second->get_meta()->pick_dirfrag(bp.dname); + } + oid = obj_name(bp.dirino, frag); + }else{ + meta_op::sub_op* nsop = new meta_op::sub_op(&op); + nsop->ino = sop->ino_c; + nsop->sub_op_t = meta_op::OP_LTRACE; + nsop->sub_ino_t = meta_op::INO_DIR; + op.push_op(nsop); + return 1; + } + } + if (_debug) + std::cout << __func__ << " : " << string(list_all?"listall ":"info ") << oid << " "<< ino << std::endl; + bufferlist hbl; + int ret = io_meta.omap_get_header(oid, &hbl); + if (ret < 0){ + std::cerr << __func__ << " : cantn't find it, maybe it (ino:"<< sop->ino<< ")isn't a normal dir!" << std::endl; + return -1; + } + + if (hbl.length() == 0){ // obj has splite + if (list_all){ + if (frag == frag_t()){ + auto item = op.inodes.find(sop->ino); + if (item != op.inodes.end()){ + inodeno_t tmp = sop->ino; + op.pop_op(); + std::list frags; + item->second->get_meta()->dirfragtree.get_leaves(frags); + for (const auto &frag : frags){ + meta_op::sub_op* nsop = new meta_op::sub_op(&op); + nsop->ino = tmp; + nsop->sub_op_t = meta_op::OP_LIST; + nsop->sub_ino_t = meta_op::INO_DIR; + nsop->frag = frag; + op.push_op(nsop); + } + }else{ + meta_op::sub_op* nsop = new meta_op::sub_op(&op); + nsop->ino_c = sop->ino; + nsop->sub_op_t = meta_op::OP_LIST; + nsop->sub_ino_t = meta_op::INO_DIR; + op.push_op(nsop); + } + return 1; + }else{ + cerr << __func__ << " missing some data (" << oid << ")???" << std::endl; + return -1; + } + }else{ + if (frag == frag_t()){ + inode_backpointer_t bp; + if (sop->get_c_ancestor(bp)){ + meta_op::sub_op* nsop = new meta_op::sub_op(&op); + nsop->ino_c = bp.dirino; + nsop->sub_op_t = meta_op::OP_LIST; + nsop->sub_ino_t = meta_op::INO_DIR; + nsop->trace_level = sop->trace_level + 1; + op.push_op(nsop); + return 1; + }else{ + cerr << __func__ << "cann't find obj(" << oid << ") ,miss ancestors or miss some objs??? " << std::endl; + return -1; + } + }else{ + cerr << __func__ << "missing some objs(" << oid << ")??? " << std::endl; + return -1; + } + } + } + + fnode_t got_fnode; + try { + auto p = hbl.cbegin(); + ::decode(got_fnode, p); + }catch (const buffer::error &err){ + cerr << "corrupt fnode header in " << oid + << ": " << err << std::endl; + return -1; + } + + if (_debug){ + std::string format = "json"; + Formatter* f = Formatter::create(format); + f->enable_line_break(); + f->dump_string("type", "--fnode--"); + f->open_object_section("fnode"); + got_fnode.dump(f); + f->close_section(); + f->flush(std::cout); + std::cout << std::endl; + } + + // print children + std::map out_vals; + int max_vals = 5; + io_meta.omap_get_vals(oid, "", max_vals, &out_vals); + + bool force_dirty = false; + const set *snaps = NULL; + unsigned pos = out_vals.size() - 1; + std::string last_dname; + for (map::iterator p = out_vals.begin(); + p != out_vals.end(); + ++p, --pos) { + string dname; + snapid_t last; + dentry_key_t::decode_helper(p->first, dname, last); + if(_debug) + + last_dname = dname; + try { + if (!list_all){ + if (show_child(p->first, dname, last, p->second, pos, snaps, + &force_dirty, ino, &op) == 1){ + return 0; + } + }else { + cout << "dname : " << dname << " " << last << std::endl; + if (show_child(p->first, dname, last, p->second, pos, snaps, + &force_dirty) == 1) + return 0; + } + } catch (const buffer::error &err) { + derr << "Corrupt dentry '" << dname << "' : " + << err << "(" << "" << ")" << dendl; + return -1; + } + } + while(out_vals.size() == (size_t)max_vals){ + out_vals.clear(); + io_meta.omap_get_vals(oid, last_dname, max_vals, &out_vals); + pos = out_vals.size() - 1; + for (map::iterator p = (++out_vals.begin()); + p != out_vals.end(); + ++p, --pos) { + string dname; + snapid_t last; + dentry_key_t::decode_helper(p->first, dname, last); + last_dname = dname; + try { + if (!list_all){ + if (show_child(p->first, dname, last, p->second, pos, snaps, + &force_dirty, ino, &op) == 1){ + return 0; + } + }else { + cout << "dname : " << dname << " " << last << std::endl; + if (show_child(p->first, dname, last, p->second, pos, snaps, + &force_dirty) == 1) + return 0; + } + } catch (const buffer::error &err) { + derr << "Corrupt dentry '" << dname << "' : " + << err << "(" << "" << ")" << dendl; + return -1; + } + } + } + + if (!list_all){ + cerr << __func__ << "miss obj(ino:" << ino << ")??? " << std::endl; + return -1; + } + return 0; +} +unsigned long long MetaTool::conv2hexino(const char* ino){ + unsigned long long iino = 0; + std::stringstream conv; + conv << ino; + conv >> iino; + printf("convert to hexadecimal ino %s => %llx \n", ino, iino); + return iino; +} + +int MetaTool::file_meta(meta_op &op){ + int r = 0; + if (op.top_op()->sub_ino_t == meta_op::INO_DIR){ + r = _file_meta(op, io_meta); + }else if (op.top_op()->sub_ino_t == meta_op::INO_F){ + for (auto i = io_data_v.begin(); i != io_data_v.end(); ++i) + if ((r = _file_meta(op, **i)) == 1) + break; + } + if (r == 1){ + inode_backpointer_t bp; + if (op.top_op()->get_ancestor(bp)){ + return 0; + }else { + std::cerr << "no trace for obj (ino:" << op.top_op()->ino <<")??" << std::endl; + return -1; + } + }else if (op.top_op()->sub_ino_t == meta_op::INO_DIR){ + std::cerr << "\tmaybe it's a file(ino:" << op.top_op()->ino << ")" << std::endl; + op.top_op()->sub_ino_t = meta_op::INO_F; + return 1; + } + + std::cerr << "can't get (ino:" << op.top_op()->ino <<")trace??" << std::endl; + return -1; +} + +int MetaTool::_file_meta(meta_op &op, librados::IoCtx& io){ + inodeno_t ino = op.top_op()->ino; + std::string oid = obj_name(ino); + bufferlist pointer_bl; + std::map attrset; + int r = 0; + bool have_data = false; + r = io.getxattrs (oid.c_str(), attrset); + if (0 == r){ + std::stringstream ds; + std::string format = "json"; + Formatter* f = Formatter::create(format); + auto item = attrset.find("parent"); + if (item != attrset.end()){ + inode_backtrace_t i_bt; + try { + bufferlist::const_iterator q = item->second.cbegin(); + i_bt.decode(q); + f->open_array_section("info"); + have_data = true; + if (i_bt.ancestors.size() > 0) + op.ancestors[ino] = i_bt.ancestors[0]; + f->dump_string("type", "--i_bt--"); + f->open_object_section("parent"); + i_bt.dump(f); + f->close_section(); + }catch (buffer::error &e){ + cerr << "failed to decode parent of " << oid << std::endl; + return -1; + } + }else{ + cerr << oid << " in " << io.get_pool_name() << " , but no parent" << std::endl; + return -1; + } + + item = attrset.find("layout"); + if (item != attrset.end()){ + file_layout_t layout; + try { + auto q = item->second.cbegin(); + layout.decode(q); + f->dump_string("type", "--layout--"); + f->open_object_section("layout"); + layout.dump(f); + f->close_section(); + + }catch (buffer::error &e){ + cerr << "failed to decode layout of " << oid << std::endl; + return -1; + } + }else{ + cerr << oid << " in " << io.get_pool_name() << " , but no layout" << std::endl; + } + if (have_data){ + f->close_section(); + f->flush(ds); + if (_debug) + cout << ino << " : "<< ds.str() << std::endl; + return 1; + } + } + return 0; +} +std::string MetaTool::obj_name(inodeno_t ino, uint64_t offset, const char *suffix) const{ + char name[60]; + snprintf(name, sizeof(name), "%llx.%08llx%s", (long long unsigned)ino, (long long unsigned)offset, suffix ? suffix : ""); + return std::string(name); +} +std::string MetaTool::obj_name(inodeno_t ino, frag_t fg, const char *suffix) const +{ + char name[60]; + snprintf(name, sizeof(name), "%llx.%08llx%s", (long long unsigned)ino, (long long unsigned)fg, suffix ? suffix : ""); + return std::string(name); +} + +std::string MetaTool::obj_name(const char* ino, uint64_t offset, const char *suffix) const +{ + char name[60]; + snprintf(name, sizeof(name), "%s.%08llx%s", ino, (long long unsigned)offset, suffix ? suffix : ""); + std::string out = name; + transform(out.begin(), out.end(), out.begin(),::tolower); + return out; +} + +int MetaTool::show_child(std::string_view key, + std::string_view dname, + const snapid_t last, + bufferlist &bl, + const int pos, + const std::set *snaps, + bool *force_dirty, + inodeno_t sp_ino, + meta_op* op){ + bufferlist::const_iterator q = bl.cbegin(); + + snapid_t first; + ::decode(first, q); + + // marker + char type; + ::decode(type, q); + + if (_debug) + std::cout << pos << " type '" << type << "' dname '" << dname + << " [" << first << "," << last << "]" + << std::endl; + // bool stale = false; + if (snaps && last != CEPH_NOSNAP){ + derr << "!!!! erro !!!!" << dendl; + return -1; + } + + // CDentry *dn = NULL; + // look for existing dentry for _last_ snap, cann't process snap of obj + //if *(stale) + // dn = lookup_exact_snap(dname, last); + //else + // dn = lookup(dname, last); + if (type == 'L'){ + // hard link + inodeno_t ino; + unsigned char d_type; + ::decode(ino, q); + ::decode(d_type, q); + if (sp_ino > 0){ + if (sp_ino == ino){ + std::cout << "find hard link : " << ino << "," << d_type << std::endl; + return 1; + } + } + + std::cout << "hard link : " << ino << "," << d_type << std::endl; + }else if (type == 'I') { + // inode + // load inode data before lookuping up or constructing CInode + InodeStore& inode_data = *(new InodeStore); + inode_data.decode_bare(q); + + std::stringstream ds; + //std::string format = "json-pretty"; + std::string format = "json"; + // Formatter f = new JSONFormatter(false); + Formatter* f = Formatter::create(format); + f->enable_line_break(); + f->open_object_section("meta"); + f->dump_unsigned("snapid_t", first); + f->dump_unsigned("itype", type); + f->open_object_section("store"); + inode_data.dump(f); + try { + if (inode_data.snap_blob.length()){ + sr_t srnode; + auto p = inode_data.snap_blob.cbegin(); + srnode.decode(p); + f->open_object_section("snap_blob"); + srnode.dump(f); + f->close_section(); + } + }catch (const buffer::error &err){ + cerr << "corrupt decode in snap_blob" + << ": " << err << std::endl; + } + f->close_section(); + f->close_section(); + f->flush(ds); + + if (sp_ino > 0 && op != NULL && sp_ino == inode_data.inode.ino){ + inode_meta_t* tmp = new inode_meta_t(first, type, &inode_data); + op->inodes[inode_data.inode.ino] = tmp; + op->okeys[inode_data.inode.ino] = key.data(); + return 1; + }else{ + delete &inode_data; + } + + if (sp_ino == 0){ + cout << ds.str() << std::endl; + } + }else{ + std::cerr << __func__ << "unknow type : " << dname << "," << type << std::endl; + } + return 0; +} + diff --git a/src/tools/cephfs/MetaTool.h b/src/tools/cephfs/MetaTool.h new file mode 100644 index 000000000000..a51933b0df54 --- /dev/null +++ b/src/tools/cephfs/MetaTool.h @@ -0,0 +1,255 @@ +#ifndef METATOOL_H__ +#define METATOOL_H__ + +#include "MDSUtility.h" +#include "RoleSelector.h" +#include +#include +using std::stack; +#include "mds/mdstypes.h" +#include "mds/LogEvent.h" +#include "mds/events/EMetaBlob.h" + +#include "include/rados/librados.hpp" +#include "common/ceph_json.h" + +using ::ceph::bufferlist; +class MetaTool : public MDSUtility +{ + public: + class inode_meta_t{ + public: + inode_meta_t(snapid_t f = CEPH_NOSNAP, char t = 255, InodeStore* i = NULL): + _f(f),_t(t),_i(i){ + }; + snapid_t get_snapid() const { + return _f; + } + InodeStore* get_meta() const { + if (_t == 'I') + return _i; + else + return NULL; + } + int get_type() const{ + return _t; + } + void decode_json(JSONObj *obj); + void encode(::ceph::bufferlist& bl, uint64_t features); + private: + snapid_t _f; + char _t; + InodeStore* _i; + }; + private: + class meta_op{ + public: + meta_op(bool debug = false, string out = "", string in = "", bool confirm = false): + _debug(debug), + _out(out), + _in(in), + _confirm(confirm) + {} + void release(); + typedef enum{ + OP_LIST = 0, + OP_LTRACE, + OP_SHOW, + OP_AMEND, + OP_NO + }op_type; + typedef enum{ + INO_DIR = 0, + INO_F + }ino_type; + static string op_type_name(op_type& t){ + string name; + switch (t){ + case OP_LIST: + name = "list dir"; + break; + case OP_LTRACE: + name = "load trace"; + break; + case OP_SHOW: + name = "show info"; + break; + case OP_AMEND: + name = "amend info"; + break; + case OP_NO: + name = "noop"; + break; + default: + name = "unknow op type"; + } + return name; + } + static string ino_type_name(ino_type& t){ + string name; + switch (t){ + case INO_DIR: + name = "dir"; + break; + case INO_F: + name = "file"; + break; + default: + name = "unknow file type"; + } + return name; + } + class sub_op{ + public: + sub_op(meta_op* mop): + trace_level(0), + _proc(false), + _mop(mop) + {} + void print(){ + std::cout << detail() << std::endl; + } + string detail(){ + std::stringstream ds; + ds << " [sub_op]" << op_type_name(sub_op_t) << "|" + << ino_type_name(sub_ino_t) << "|" + << ino << "|" + << frag << "|" + << ino_c << "|" + << trace_level << "|" + << name; + return ds.str(); + } + bool get_c_ancestor(inode_backpointer_t& bp){ + if (!_mop || !ino_c) + return false; + auto item = _mop->ancestors.find(ino_c); + if (item != _mop->ancestors.end()){ + bp = item->second; + return true; + }else + return false; + } + bool get_ancestor(inode_backpointer_t& bp){ + if (!_mop || !ino) + return false; + auto item = _mop->ancestors.find(ino); + if (item != _mop->ancestors.end()){ + bp = item->second; + return true; + }else + return false; + } + op_type sub_op_t; + ino_type sub_ino_t; + inodeno_t ino; + frag_t frag; + inodeno_t ino_c; + unsigned trace_level; + std::string name; + bool _proc; + meta_op* _mop; + }; + + std::map ancestors; + std::map inodes; + std::map okeys; + + void clear_sops(){ + while(!no_sops()) + pop_op(); + } + bool no_sops(){ + return sub_ops.empty(); + } + void push_op(sub_op* sop){ + if (_debug) + std::cout << "<<====" << sop->detail() << std::endl; + sub_ops.push(sop); + } + sub_op* top_op(){ + return sub_ops.top(); + } + void pop_op(){ + sub_op* sop = sub_ops.top(); + if (_debug) + std::cout << "====>>" << sop->detail() << std::endl;; + delete sop; + sub_ops.pop(); + } + string outfile(){ + return _out; + } + string infile(){ + return _in; + } + bool is_debug(){ + return _debug; + } + bool confirm_chg(){ + return _confirm; + } + private: + stack sub_ops; + bool _debug; + string _out; + string _in; + bool _confirm; + }; + MDSRoleSelector role_selector; + mds_rank_t rank; + + // I/O handles + librados::Rados rados; + librados::IoCtx io_meta; + std::vector io_data_v; + librados::IoCtx output; + bool _debug; + uint64_t features; + + std::string obj_name(inodeno_t ino, frag_t fg = frag_t(), const char *suffix = NULL) const; + std::string obj_name(inodeno_t ino, uint64_t offset, const char *suffix = NULL) const; + std::string obj_name(const char* ino, uint64_t offset, const char *suffix = NULL) const; + + // 0 : continue to find + // 1 : stop to find it + int show_child(std::string_view key, + std::string_view dname, + const snapid_t last, + bufferlist &bl, + const int pos, + const std::set *snaps, + bool *force_dirty, + inodeno_t sp_ino = 0, + meta_op* op = NULL + ); + + int process(string& mode, string& ino, string out, string in, bool confirm); + int show_meta_info(string& ino, string& out); + int list_meta_info(string& ino, string& out); + int amend_meta_info(string& ino, string& in, bool confirm); + int op_process(meta_op &op); + int list_meta(meta_op &op); + int file_meta(meta_op &op); + int show_meta(meta_op &op); + int amend_meta(meta_op &op); + + public: + int _file_meta(meta_op &op, librados::IoCtx& io); + int _show_meta(inode_meta_t& i, const string& fn); + int _amend_meta(string &k, inode_meta_t& i, const string& fn, meta_op& op); + static unsigned long long conv2hexino(const char* ino); + void usage(); + MetaTool(bool debug=false): + _debug(debug){} + ~MetaTool(){} + int main(string& mode, + string& rank_str, + string& minfo, + string&ino, + string& out, + string& in, + bool confirm = false + ); +}; +#endif // METATOOL_H__ diff --git a/src/tools/cephfs/cephfs-meta-injection.cc b/src/tools/cephfs/cephfs-meta-injection.cc new file mode 100644 index 000000000000..b93d921ed281 --- /dev/null +++ b/src/tools/cephfs/cephfs-meta-injection.cc @@ -0,0 +1,99 @@ +#include +#include "common/config.h" +#include "common/ceph_argparse.h" +#include "common/errno.h" +#include "global/global_init.h" + +#include "MetaTool.h" +#include +#include +#include + +#include +namespace po = boost::program_options; +using std::string; +using namespace std; +static string version = "cephfs-meta-injection v1.1"; + +int main(int argc, const char **argv){ + vector args; + argv_to_vec(argc, argv, args); + env_to_vec(args); + auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, + CODE_ENVIRONMENT_UTILITY, 0); + common_init_finish(g_ceph_context); + + string rank_str, minfo, ino, out,in; + po::options_description general("general options"); + general.add_options() + ("help,h", "produce help message") + ("debug", "show debug info") + ("rank,r", po::value(&rank_str), "the rank of cephfs, default(0) (e.g. -r cephfs_a:0)") + ("minfo", po::value(&minfo), "specify metapool, datapools and rank (e.g. cephfs_metadata_a:cephfs_data_a:0)") + ("ino,i", po::value(&ino), "specify inode. e.g. 1099511627776, you can find it with cmd, 'ls -i'") + ("out,o", po::value(&out), "output file") + ("in", po::value(&in), "input file") + ("yes-i-really-really-mean-it", "need by amend info") + ; + + string mode; + po::options_description modeoptions("mode options"); + modeoptions.add_options() + ("mode", po::value(&mode), + "\tconv : convert decimal ino to hex\n" \ + "\tlistc : list all obj of dir\n" \ + "\tshowm : show the info of ino\n" \ + "\tamend : amend part of the meta data\n" + ); + + po::positional_options_description p; + p.add("mode", 1); + + po::options_description all("all options"); + all.add(modeoptions).add(general); + po::variables_map vm; + try{ + po::store(po::command_line_parser(argc, argv).options(all).positional(p).run(), vm); + }catch(exception &e){ + cerr << "error : " << e.what() << std::endl; + return -1; + } + catch(...){ + cout << "param error" << std::endl; + return 0; + } + + boost::program_options::notify(vm); + if (vm.count("help")){ + std::cout << version << std::endl; + std::cout << "usage : \n" + << " cephfs-meta-injection -r -i " + << std::endl; + std::cout << "example : \n" + << " amend info of inode(1099531628828)\n" + << " cephfs-meta-injection showm -r cephfs_a:0 -i 1099531628828 -o out\n" + << " alter file\n" + << " cephfs-meta-injection amend -r cephfs_a:0 -i 1099531628828 --in out --yes-i-really-mean-it" + << std::endl; + std::cout << all << std::endl; + return 0; + } + + if (mode == "conv"){ + MetaTool::conv2hexino(ino.c_str()); + return 0; + } + + MetaTool mt(vm.count("debug")); + int rc = mt.init(); + if (rc != 0) { + std::cerr << "error in initialization: " << cpp_strerror(rc) << std::endl; + return rc; + } + rc = mt.main(mode, rank_str, minfo, ino, out, in, vm.count("yes-i-really-really-mean-it")); + if (rc != 0) { + std::cerr << "error (" << cpp_strerror(rc) << ")" << std::endl; + return -1; + } + return rc; +} diff --git a/src/tools/cephfs/type_helper.hpp b/src/tools/cephfs/type_helper.hpp new file mode 100644 index 000000000000..06dfa0afe5e6 --- /dev/null +++ b/src/tools/cephfs/type_helper.hpp @@ -0,0 +1,28 @@ +#ifndef TYPE_HELPER_HPP__ +#define TYPE_HELPER_HPP__ + +template +T1 conv_t(T2 s){ + T1 target; + std::stringstream conv; + conv << s; + conv >> target; + return target; +} + +void string_split(std::string str, vector& out, string split = ":"){ + std::cout << str << std::endl; + auto pos = str.find(split); + while(pos != std::string::npos){ + std::cout << str.substr(0, pos) << std::endl; + out.push_back(str.substr(0, pos)); + if (str.size() > pos + split.size()){ + str = str.substr(pos + split.size()); + pos = str.find(split); + }else + return; + } + out.push_back(str.substr()); + return; +} +#endif // TYPE_HELPER_HPP__