ceph-fuse
ceph-dencoder
cephfs-journal-tool
+ cephfs-meta-injection
cephfs-data-scan
cephfs-table-tool)
}
}
+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);
#include <typeindex>
#include <include/types.h>
#include <boost/container/flat_map.hpp>
+#include <include/ceph_fs.h>
#include "json_spirit/json_spirit.h"
#include "Formatter.h"
-using namespace json_spirit;
class JSONObj;
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<class T>
void decode_json_obj(std::list<T>& l, JSONObj *obj)
#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)
{
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<file_layout_t*>& o)
{
o.push_back(new file_layout_t);
#define CEPH_INCLUDE_FS_TYPES_H
#include "types.h"
+class JSONObj;
// --------------------------------------
// ino
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<file_layout_t*>& o);
};
WRITE_CLASS_ENCODER_FEATURES(file_layout_t)
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<InodeStore*> &ls)
{
/* 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);
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<frag_info_t*>& ls)
{
ls.push_back(new frag_info_t);
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<nest_info_t*>& ls)
{
ls.push_back(new nest_info_t);
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<quota_info_t *>& ls)
{
ls.push_back(new quota_info_t);
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<client_writeable_range_t*>& ls)
{
ls.push_back(new client_writeable_range_t);
#include <boost/pool/pool.hpp>
#include "include/ceph_assert.h"
#include <boost/serialization/strong_typedef.hpp>
+#include "common/ceph_json.h"
#define CEPH_FS_ONDISK_MAGIC "ceph fs volume v011"
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<frag_info_t*>& ls);
// this frag
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<nest_info_t*>& ls);
// this frag + children
bool is_enable() const {
return max_bytes || max_files;
}
+ void decode_json(JSONObj *obj);
int64_t max_bytes = 0;
int64_t max_files = 0;
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;
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<int64_t, std::less<int64_t>, Allocator<int64_t> >& c, JSONObj *obj);
+ void decode_json(JSONObj *obj);
static void generate_test_instances(std::list<inode_t*>& ls);
/**
* Compare this inode_t with another that represent *the same inode*
f->dump_unsigned("last_scrub_version", last_scrub_version);
}
+template<template<typename> class Allocator>
+void inode_t<Allocator>::client_ranges_cb(typename inode_t<Allocator>::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<template<typename> class Allocator>
+void inode_t<Allocator>::old_pools_cb(compact_set<int64_t, std::less<int64_t>, Allocator<int64_t> >& c, JSONObj *obj){
+
+ int64_t tmp;
+ decode_json_obj(tmp, obj);
+ c.insert(tmp);
+}
+
+template<template<typename> class Allocator>
+void inode_t<Allocator>::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<Allocator>::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<Allocator>::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<template<typename> class Allocator>
void inode_t<Allocator>::generate_test_instances(std::list<inode_t*>& ls)
{
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
--- /dev/null
+#include <string.h>
+#include <map>
+#include <sstream>
+#include <fstream>
+
+#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<string> 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<int64_t> & 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[" <<mode<< "] ret : " << ret << std::endl;
+ }
+
+ }else{
+ features = CEPH_FEATURES_SUPPORTED_DEFAULT;
+ r = rados.ioctx_create(manual_meta_pool.c_str(), io_meta);
+ assert(r == 0);
+
+ librados::IoCtx* io_data = new librados::IoCtx;
+ r = rados.ioctx_create(manual_data_pool.c_str(), *io_data);
+ assert(r == 0);
+ io_data_v.push_back(io_data);
+
+
+ rank = conv_t<int>(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<string, bufferlist> 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<frag_t> 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<string, bufferlist> out_vals;
+ int max_vals = 5;
+ io_meta.omap_get_vals(oid, "", max_vals, &out_vals);
+
+ bool force_dirty = false;
+ const set<snapid_t> *snaps = NULL;
+ unsigned pos = out_vals.size() - 1;
+ std::string last_dname;
+ for (map<string, bufferlist>::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<string, bufferlist>::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<std::string, bufferlist> 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<snapid_t> *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;
+}
+
--- /dev/null
+#ifndef METATOOL_H__
+#define METATOOL_H__
+
+#include "MDSUtility.h"
+#include "RoleSelector.h"
+#include <vector>
+#include <stack>
+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<inodeno_t, inode_backpointer_t > ancestors;
+ std::map<inodeno_t, inode_meta_t* > inodes;
+ std::map<inodeno_t, string > 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_op*> 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<librados::IoCtx*> 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<snapid_t> *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__
--- /dev/null
+#include <include/types.h>
+#include "common/config.h"
+#include "common/ceph_argparse.h"
+#include "common/errno.h"
+#include "global/global_init.h"
+
+#include "MetaTool.h"
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <boost/program_options.hpp>
+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<const char*> 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<string>(&rank_str), "the rank of cephfs, default(0) (e.g. -r cephfs_a:0)")
+ ("minfo", po::value<string>(&minfo), "specify metapool, datapools and rank (e.g. cephfs_metadata_a:cephfs_data_a:0)")
+ ("ino,i", po::value<string>(&ino), "specify inode. e.g. 1099511627776, you can find it with cmd, 'ls -i'")
+ ("out,o", po::value<string>(&out), "output file")
+ ("in", po::value<string>(&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<string>(&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 <conv|listc|showm|amend> -r <fsname:rank> -i <ino>"
+ << 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;
+}
--- /dev/null
+#ifndef TYPE_HELPER_HPP__
+#define TYPE_HELPER_HPP__
+
+template<typename T1, typename T2>
+T1 conv_t(T2 s){
+ T1 target;
+ std::stringstream conv;
+ conv << s;
+ conv >> target;
+ return target;
+}
+
+void string_split(std::string str, vector<string>& 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__