diff options
Diffstat (limited to 'src/tools/cephfs/MetaTool.cc')
-rw-r--r-- | src/tools/cephfs/MetaTool.cc | 1000 |
1 files changed, 1000 insertions, 0 deletions
diff --git a/src/tools/cephfs/MetaTool.cc b/src/tools/cephfs/MetaTool.cc new file mode 100644 index 000000000..baa0d498a --- /dev/null +++ b/src/tools/cephfs/MetaTool.cc @@ -0,0 +1,1000 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +#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/CDentry.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__ << ": " + +using namespace std; + +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 + for (const auto p : fs->mds_map.get_data_pools()) { + r = rados.pool_reverse_lookup(p, &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; + + r = process(mode, ino, out, in, confirm); + cout << "executing for rank " << rank << " op[" <<mode<< "] ret : " << r << 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); + r = process(mode, ino, out, in, confirm); + cout << "op[" << mode << "] ret : " << r << 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 == "showfn") { + return show_fnode(ino, out); + } else if (mode == "listc") { + return list_meta_info(ino, out); + } else if (mode == "amend") { + return amend_meta_info(ino, in, confirm); + } else if (mode == "amendfn") { + return amend_fnode(in, confirm); + } else { + cerr << "bad command '" << mode << "'" << std::endl; + return -EINVAL; + } +} +int MetaTool::show_fnode(string& ino, string& out) +{ + if (ino != "0") { + inodeno_t i_ino = std::stoull(ino.c_str(), nullptr, 0); + meta_op op(_debug, out); + meta_op::sub_op* nsop = new meta_op::sub_op(&op); + nsop->sub_op_t = meta_op::OP_SHOW_FN; + 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::amend_fnode(string& in, bool confirm) +{ + 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_FN; + nsop->sub_ino_t = meta_op::INO_DIR; + nsop->ino = 0; + op.push_op(nsop); + return op_process(op); +} +int MetaTool::amend_meta_info(string& ino, string& in, bool confirm) +{ + if (ino != "0" && in != "") { + inodeno_t i_ino = std::stoull(ino.c_str(), nullptr, 0); + 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 = std::stoull(ino.c_str(), nullptr, 0); + 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 = std::stoull(ino.c_str(), nullptr, 0); + 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; + case meta_op::OP_SHOW_FN: + r = show_fn(op); + break; + case meta_op::OP_AMEND_FN: + r = amend_fn(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; + return -1; + } + + 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 -1; + 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_fn(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_fn(*(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_fn(inode_meta_t& inode_meta, const string& fn) +{ + std::list<frag_t> frags; + inode_meta.get_meta()->dirfragtree.get_leaves(frags); + std::stringstream ds; + std::string format = "json"; + std::string oids; + Formatter* f = Formatter::create(format); + f->enable_line_break(); + f->open_object_section("fnodes"); + for (const auto &frag : frags) { + bufferlist hbl; + string oid = obj_name(inode_meta.get_meta()->inode->ino, frag); + int ret = io_meta.omap_get_header(oid, &hbl); + if (ret < 0) { + std::cerr << __func__ << " : can't find oid("<< 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.what() << std::endl; + return -1; + } + if (!oids.empty()) + oids += ","; + oids += oid; + f->open_object_section(oid.c_str()); + got_fnode.dump(f); + f->close_section(); + } + } + f->dump_string("oids", oids.c_str()); + 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::amend_fn(meta_op &op) +{ + if (_amend_fn(op.infile(), op.confirm_chg()) < 0) + return -1; + return 0; +} +int MetaTool::_amend_fn(const string& fn, bool confirm) +{ + JSONParser parser; + if (!parser.parse(fn.c_str())) { + cout << "Error parsing create user response : " << fn << std::endl; + return -1; + } + if (!confirm) { + 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; + return -1; + } + try { + string tmp; + JSONDecoder::decode_json("oids", tmp, &parser, true); + string::size_type pos1, pos2; + vector<string> v; + string c = ","; + pos2 = tmp.find(c); + pos1 = 0; + while (string::npos != pos2) { + v.push_back(tmp.substr(pos1, pos2-pos1)); + pos1 = pos2 + c.size(); + pos2 = tmp.find(c, pos1); + } + if (pos1 != tmp.length()) + v.push_back(tmp.substr(pos1)); + int ret = 0; + for (auto i : v) { + cout << "amend frag : " << i << "..." << std::endl; + fnode_t fnode; + JSONDecoder::decode_json(i.c_str(), fnode, &parser, true); + bufferlist bl; + fnode.encode(bl); + ret = io_meta.omap_set_header(i, bl); + if (ret < 0) + return ret; + } + } catch (JSONDecoder::err& e) { + cout << "failed to decode JSON input: " << e.what() << std::endl; + return -1; + } + return 0; +} +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.what() << 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__ << " : can'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__ << "can'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.what() << 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.what() << "(" << "" << ")" << 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.what() << "(" << "" << ")" << dendl; + return -1; + } + } + } + + if (!list_all) { + cerr << __func__ << "miss obj(ino:" << ino << ")??? " << std::endl; + return -1; + } + return 0; +} + +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, can't process snap of obj + //if *(stale) + // dn = lookup_exact_snap(dname, last); + //else + // dn = lookup(dname, last); + if (type == 'L' || type == 'l') { + // hard link + inodeno_t ino; + unsigned char d_type; + mempool::mds_co::string alternate_name; + + CDentry::decode_remote(type, ino, d_type, alternate_name, 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' || type == 'i') { + // inode + // load inode data before lookuping up or constructing CInode + InodeStore& inode_data = *(new InodeStore); + if (type == 'i') { + mempool::mds_co::string alternate_name; + + DECODE_START(2, q); + if (struct_v >= 2) + decode(alternate_name, q); + inode_data.decode(q); + DECODE_FINISH(q); + } else { + inode_data.decode_bare(q); + } + + std::stringstream ds; + std::string format = "json"; + 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.what() << 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; +} |