From 0151feccf05887f2a89c3d55f216ebe850b06c75 Mon Sep 17 00:00:00 2001 From: John Spray Date: Mon, 14 Sep 2015 11:40:46 +0100 Subject: [PATCH 1/3] tools: refactor DataScan injection To take an InodeStore instead of size/mtime/layout args in injection fns. This is to enable use for injecting directories in subsequent commit. Signed-off-by: John Spray --- src/tools/cephfs/DataScan.cc | 129 +++++++++++++++++------------------ src/tools/cephfs/DataScan.h | 30 ++++---- 2 files changed, 73 insertions(+), 86 deletions(-) diff --git a/src/tools/cephfs/DataScan.cc b/src/tools/cephfs/DataScan.cc index ce083cefff23b..173e36b4127c0 100644 --- a/src/tools/cephfs/DataScan.cc +++ b/src/tools/cephfs/DataScan.cc @@ -626,6 +626,9 @@ int DataScan::scan_inodes() have_backtrace = false; } + InodeStore dentry; + build_file_dentry(obj_name_ino, file_size, file_mtime, guessed_layout, &dentry); + // Inject inode to the metadata pool if (have_backtrace) { inode_backpointer_t root_bp = *(backtrace.ancestors.rbegin()); @@ -633,8 +636,7 @@ int DataScan::scan_inodes() /* Special case for strays: even if we have a good backtrace, * don't put it in the stray dir, because while that would technically * give it linkage it would still be invisible to the user */ - r = driver->inject_lost_and_found( - obj_name_ino, file_size, file_mtime, guessed_layout); + r = driver->inject_lost_and_found(obj_name_ino, dentry); if (r < 0) { dout(4) << "Error injecting 0x" << std::hex << backtrace.ino << std::dec << " into lost+found: " << cpp_strerror(r) << dendl; @@ -645,8 +647,7 @@ int DataScan::scan_inodes() } } else { /* Happy case: we will inject a named dentry for this inode */ - r = driver->inject_with_backtrace( - backtrace, file_size, file_mtime, guessed_layout); + r = driver->inject_with_backtrace(backtrace, dentry); if (r < 0) { dout(4) << "Error injecting 0x" << std::hex << backtrace.ino << std::dec << " with backtrace: " << cpp_strerror(r) << dendl; @@ -659,7 +660,7 @@ int DataScan::scan_inodes() } else { /* Backtrace-less case: we will inject a lost+found dentry */ r = driver->inject_lost_and_found( - obj_name_ino, file_size, file_mtime, guessed_layout); + obj_name_ino, dentry); if (r < 0) { dout(4) << "Error injecting 0x" << std::hex << obj_name_ino << std::dec << " into lost+found: " << cpp_strerror(r) << dendl; @@ -749,8 +750,8 @@ int MetadataDriver::read_dentry(inodeno_t parent_ino, frag_t frag, return 0; } -int MetadataDriver::inject_lost_and_found(inodeno_t ino, uint64_t file_size, - time_t file_mtime, const ceph_file_layout &layout) +int MetadataDriver::inject_lost_and_found( + inodeno_t ino, const InodeStore &dentry) { // Create lost+found if doesn't exist bool created = false; @@ -796,31 +797,12 @@ int MetadataDriver::inject_lost_and_found(inodeno_t ino, uint64_t file_size, } InodeStore recovered_ino; - recovered_ino.inode.mode = 0500 | S_IFREG; - recovered_ino.inode.size = file_size; - recovered_ino.inode.max_size_ever = file_size; - recovered_ino.inode.mtime.tv.tv_sec = file_mtime; - recovered_ino.inode.atime.tv.tv_sec = file_mtime; - recovered_ino.inode.ctime.tv.tv_sec = file_mtime; - - recovered_ino.inode.layout = layout; - - recovered_ino.inode.truncate_seq = 1; - recovered_ino.inode.truncate_size = -1ull; - recovered_ino.inode.inline_data.version = CEPH_INLINE_NONE; - - recovered_ino.inode.nlink = 1; - recovered_ino.inode.ino = ino; - recovered_ino.inode.version = 1; - recovered_ino.inode.backtrace_version = 1; - recovered_ino.inode.uid = g_conf->mds_root_ino_uid; - recovered_ino.inode.gid = g_conf->mds_root_ino_gid; const std::string dname = lost_found_dname(ino); // Write dentry into lost+found dirfrag - return inject_linkage(lf_ino.inode.ino, dname, frag_t(), recovered_ino); + return inject_linkage(lf_ino.inode.ino, dname, frag_t(), dentry); } @@ -932,8 +914,7 @@ int MetadataDriver::get_frag_of( int MetadataDriver::inject_with_backtrace( - const inode_backtrace_t &backtrace, uint64_t file_size, time_t file_mtime, - const ceph_file_layout &layout) + const inode_backtrace_t &backtrace, const InodeStore &dentry) { @@ -1042,53 +1023,41 @@ int MetadataDriver::inject_with_backtrace( << dname << " already exists but points to 0x" << std::hex << existing_dentry.inode.ino << std::dec << dendl; // Fall back to lost+found! - return inject_lost_and_found(backtrace.ino, file_size, file_mtime, - layout); + return inject_lost_and_found(backtrace.ino, dentry); } } // Inject linkage // ============== + if (write_dentry) { - InodeStore dentry; if (i == backtrace.ancestors.begin()) { - // This is the linkage for a file - dentry.inode.mode = 0500 | S_IFREG; + // This is the linkage for the file of interest dout(10) << "Linking inode 0x" << std::hex << ino << " at 0x" << parent_ino << "/" << dname << std::dec - << " with size=" << file_size << " bytes" << dendl; + << " with size=" << dentry.inode.size << " bytes" << dendl; - // The file size and mtime we learned by scanning globally - dentry.inode.size = file_size; - dentry.inode.max_size_ever = file_size; - dentry.inode.mtime.tv.tv_sec = file_mtime; - dentry.inode.atime.tv.tv_sec = file_mtime; - dentry.inode.ctime.tv.tv_sec = file_mtime; - - dentry.inode.layout = layout; - - dentry.inode.truncate_seq = 1; - dentry.inode.truncate_size = -1ull; - - dentry.inode.inline_data.version = CEPH_INLINE_NONE; + r = inject_linkage(parent_ino, dname, fragment, dentry); } else { - // This is the linkage for a directory - dentry.inode.mode = 0755 | S_IFDIR; + // This is the linkage for an ancestor directory + InodeStore ancestor_dentry; + ancestor_dentry.inode.mode = 0755 | S_IFDIR; // Set nfiles to something non-zero, to fool any other code // that tries to ignore 'empty' directories. This won't be // accurate, but it should avoid functional issues. - dentry.inode.dirstat.nfiles = 1; - dentry.inode.size = 1; - + ancestor_dentry.inode.dirstat.nfiles = 1; + ancestor_dentry.inode.size = 1; + + ancestor_dentry.inode.nlink = 1; + ancestor_dentry.inode.ino = ino; + ancestor_dentry.inode.uid = g_conf->mds_root_ino_uid; + ancestor_dentry.inode.gid = g_conf->mds_root_ino_gid; + ancestor_dentry.inode.version = 1; + ancestor_dentry.inode.backtrace_version = 1; + r = inject_linkage(parent_ino, dname, fragment, ancestor_dentry); } - dentry.inode.nlink = 1; - dentry.inode.ino = ino; - dentry.inode.uid = g_conf->mds_root_ino_uid; - dentry.inode.gid = g_conf->mds_root_ino_gid; - dentry.inode.version = 1; - dentry.inode.backtrace_version = 1; - r = inject_linkage(parent_ino, dname, fragment, dentry); + if (r < 0) { return r; } @@ -1287,9 +1256,7 @@ int LocalFileDriver::inject_data( int LocalFileDriver::inject_with_backtrace( const inode_backtrace_t &bt, - uint64_t size, - time_t mtime, - const ceph_file_layout &layout) + const InodeStore &dentry) { std::string path_builder = path; @@ -1307,7 +1274,7 @@ int LocalFileDriver::inject_with_backtrace( if (is_file) { // FIXME: inject_data won't cope with interesting (i.e. striped) // layouts (need a librados-compatible Filer to read these) - inject_data(path_builder, size, layout.fl_object_size, bt.ino); + inject_data(path_builder, dentry.inode.size, dentry.inode.layout.fl_object_size, bt.ino); } else { int r = mkdir(path_builder.c_str(), 0755); if (r != 0 && r != -EPERM) { @@ -1323,9 +1290,7 @@ int LocalFileDriver::inject_with_backtrace( int LocalFileDriver::inject_lost_and_found( inodeno_t ino, - uint64_t size, - time_t mtime, - const ceph_file_layout &layout) + const InodeStore &dentry) { std::string lf_path = path + "/lost+found"; int r = mkdir(lf_path.c_str(), 0755); @@ -1336,7 +1301,7 @@ int LocalFileDriver::inject_lost_and_found( } std::string file_path = lf_path + "/" + lost_found_dname(ino); - return inject_data(file_path, size, layout.fl_object_size, ino); + return inject_data(file_path, dentry.inode.size, dentry.inode.layout.fl_object_size, ino); } int LocalFileDriver::init_roots(int64_t data_pool_id) @@ -1374,3 +1339,31 @@ int LocalFileDriver::check_roots(bool *result) return 0; } +void DataScan::build_file_dentry( + inodeno_t ino, uint64_t file_size, time_t file_mtime, + const ceph_file_layout &layout, InodeStore *out) +{ + assert(out != NULL); + + out->inode.mode = 0500 | S_IFREG; + out->inode.size = file_size; + out->inode.max_size_ever = file_size; + out->inode.mtime.tv.tv_sec = file_mtime; + out->inode.atime.tv.tv_sec = file_mtime; + out->inode.ctime.tv.tv_sec = file_mtime; + + out->inode.layout = layout; + + out->inode.truncate_seq = 1; + out->inode.truncate_size = -1ull; + + out->inode.inline_data.version = CEPH_INLINE_NONE; + + out->inode.nlink = 1; + out->inode.ino = ino; + out->inode.version = 1; + out->inode.backtrace_version = 1; + out->inode.uid = g_conf->mds_root_ino_uid; + out->inode.gid = g_conf->mds_root_ino_gid; +} + diff --git a/src/tools/cephfs/DataScan.h b/src/tools/cephfs/DataScan.h index 252e6e3284e0c..7cdc2d8a096e5 100644 --- a/src/tools/cephfs/DataScan.h +++ b/src/tools/cephfs/DataScan.h @@ -47,9 +47,7 @@ class RecoveryDriver { */ virtual int inject_with_backtrace( const inode_backtrace_t &bt, - uint64_t size, - time_t mtime, - const ceph_file_layout &layout) = 0; + const InodeStore &dentry) = 0; /** * Inject an inode + dentry into the lost+found directory, @@ -57,9 +55,7 @@ class RecoveryDriver { */ virtual int inject_lost_and_found( inodeno_t ino, - uint64_t size, - time_t mtime, - const ceph_file_layout &layout) = 0; + const InodeStore &dentry) = 0; /** * Create any missing roots (i.e. mydir, strays, root inode) @@ -120,15 +116,11 @@ class LocalFileDriver : public RecoveryDriver int inject_with_backtrace( const inode_backtrace_t &bt, - uint64_t size, - time_t mtime, - ceph_file_layout const &layout); + const InodeStore &dentry); int inject_lost_and_found( inodeno_t ino, - uint64_t size, - time_t mtime, - ceph_file_layout const &layout); + const InodeStore &dentry); int init_roots(int64_t data_pool_id); @@ -193,15 +185,11 @@ class MetadataDriver : public RecoveryDriver int inject_with_backtrace( const inode_backtrace_t &bt, - uint64_t size, - time_t mtime, - ceph_file_layout const &layout); + const InodeStore &dentry); int inject_lost_and_found( inodeno_t ino, - uint64_t size, - time_t mtime, - ceph_file_layout const &layout); + const InodeStore &dentry); int init_roots(int64_t data_pool_id); @@ -254,6 +242,12 @@ class DataScan : public MDSUtility const std::vector &arg, std::vector::const_iterator &i); + void build_file_dentry( + inodeno_t ino, uint64_t file_size, time_t file_mtime, + const ceph_file_layout &layout, + InodeStore *out); + + public: void usage(); int main(const std::vector &args); From ea41e48353dbd59b8dfe904d3ecb2046861ff99f Mon Sep 17 00:00:00 2001 From: John Spray Date: Mon, 14 Sep 2015 16:30:27 +0100 Subject: [PATCH 2/3] tools/cephfs: add scan_frags to DataScan This command is for injecting linkage for orphaned directory fragments. Currently does not support fragmented directories (i.e. ignores all but root dirfrags). Signed-off-by: John Spray --- src/tools/cephfs/DataScan.cc | 295 +++++++++++++++++++++++++++++++++-- src/tools/cephfs/DataScan.h | 70 ++++++--- 2 files changed, 327 insertions(+), 38 deletions(-) diff --git a/src/tools/cephfs/DataScan.cc b/src/tools/cephfs/DataScan.cc index 173e36b4127c0..619c69380b8fc 100644 --- a/src/tools/cephfs/DataScan.cc +++ b/src/tools/cephfs/DataScan.cc @@ -37,6 +37,8 @@ void DataScan::usage() << " --force-corrupt: overrite apparently corrupt structures\n" << " --force-init: write root inodes even if they exist\n" << " --force-pool: use data pool even if it is not in MDSMap\n" + << "\n" + << " cephfs-data-scan scan_frags [--force-corrupt]\n" << std::endl; generic_client_usage(); @@ -199,11 +201,31 @@ int DataScan::main(const std::vector &args) } } + if (command == "scan_frags") { + int const metadata_pool_id = mdsmap->get_metadata_pool(); + + dout(4) << "resolving metadata pool " << metadata_pool_id << dendl; + std::string metadata_pool_name; + int r = rados.pool_reverse_lookup(metadata_pool_id, &metadata_pool_name); + if (r < 0) { + std::cerr << "Pool " << metadata_pool_id + << " identified in MDS map not found in RADOS!" << std::endl; + return r; + } + + r = rados.ioctx_create(metadata_pool_name.c_str(), metadata_io); + if (r != 0) { + return r; + } + } + // Finally, dispatch command if (command == "scan_inodes") { return scan_inodes(); } else if (command == "scan_extents") { return scan_extents(); + } else if (command == "scan_frags") { + return scan_frags(); } else if (command == "init") { return driver->init_roots(mdsmap->get_first_data_pool()); } else { @@ -675,7 +697,221 @@ int DataScan::scan_inodes() return 0; } -int MetadataDriver::read_fnode( +int DataScan::scan_frags() +{ + librados::NObjectIterator i; + bool legacy_filtering = false; + + bufferlist filter_bl; + ClsCephFSClient::build_tag_filter(filter_tag, &filter_bl); + + // try/catch to deal with older OSDs that don't support + // the cephfs pgls filtering mode + try { + i = metadata_io.nobjects_begin(filter_bl); + dout(4) << "OSDs accepted cephfs object filtering" << dendl; + } catch (const std::runtime_error &e) { + // A little unfriendly, librados raises std::runtime_error + // on pretty much any unhandled I/O return value, such as + // the OSD saying -EINVAL because of our use of a filter + // mode that it doesn't know about. + std::cerr << "OSDs do not support cephfs object filtering: using " + "(slower) fallback mode" << std::endl; + legacy_filtering = true; + i = metadata_io.nobjects_begin(); + } + + librados::NObjectIterator i_end = metadata_io.nobjects_end(); + + bool roots_present; + int r = driver->check_roots(&roots_present); + if (r != 0) { + derr << "Unexpected error checking roots: '" + << cpp_strerror(r) << "'" << dendl; + return r; + } + + if (!roots_present) { + std::cerr << "Some or all system inodes are absent. Run 'init' from " + "one node before running 'scan_inodes'" << std::endl; + return -EIO; + } + + for (; i != i_end; ++i) { + const std::string oid = i->get_oid(); + uint64_t obj_name_ino = 0; + uint64_t obj_name_offset = 0; + r = parse_oid(oid, &obj_name_ino, &obj_name_offset); + if (r != 0) { + dout(4) << "Bad object name '" << oid << "', skipping" << dendl; + continue; + } + + if (obj_name_ino < (1ULL << 40)) { + // FIXME: we're skipping stray dirs here: if they're + // orphaned then we should be resetting them some other + // way + dout(10) << "Skipping system ino " << obj_name_ino << dendl; + continue; + } + + if (legacy_filtering) { + dout(20) << "Applying filter to " << oid << dendl; + + // We are only interested in 0th objects during this phase: we touched + // the other objects during scan_extents + if (obj_name_offset != 0) { + dout(20) << "Non-zeroth object" << dendl; + continue; + } + + bufferlist scrub_tag_bl; + int r = metadata_io.getxattr(oid, "scrub_tag", scrub_tag_bl); + if (r >= 0) { + std::string read_tag; + bufferlist::iterator q = scrub_tag_bl.begin(); + ::decode(read_tag, q); + if (read_tag == filter_tag) { + dout(20) << "skipping " << oid << " because it has the filter_tag" + << dendl; + continue; + } else { + dout(20) << "read non-matching tag '" << read_tag << "'" << dendl; + } + } else { + dout(20) << "no tag read (" << r << ")" << dendl; + } + + } else { + assert(obj_name_offset == 0); + dout(20) << "OSD matched oid " << oid << dendl; + } + + AccumulateResult accum_res; + inode_backtrace_t backtrace; + + // Default to inherit layout (i.e. no explicit layout on dir) which is + // expressed as a zeroed layout struct (see inode_t::has_layout) + ceph_file_layout loaded_layout; + memset(&loaded_layout, 0, sizeof(loaded_layout)); + + int parent_r = 0; + bufferlist parent_bl; + int layout_r = 0; + bufferlist layout_bl; + bufferlist op_bl; + + librados::ObjectReadOperation op; + op.getxattr("parent", &parent_bl, &parent_r); + op.getxattr("layout", &layout_bl, &layout_r); + int r = metadata_io.operate(oid, &op, &op_bl); + if (r != 0 && r != -ENODATA) { + derr << "Unexpected error reading backtrace: " << cpp_strerror(parent_r) << dendl; + continue; + } + + if (parent_r != -ENODATA) { + try { + bufferlist::iterator q = parent_bl.begin(); + backtrace.decode(q); + } catch (buffer::error &e) { + dout(4) << "Corrupt backtrace on '" << oid << "': " << e << dendl; + if (!force_corrupt) { + continue; + } else { + // Treat backtrace as absent: we'll inject into lost+found + backtrace = inode_backtrace_t(); + } + } + } + + if (layout_r != -ENODATA) { + try { + bufferlist::iterator q = layout_bl.begin(); + ::decode(loaded_layout, q); + } catch (buffer::error &e) { + dout(4) << "Corrupt layout on '" << oid << "': " << e << dendl; + if (!force_corrupt) { + continue; + } + } + } + + bool have_backtrace = !(backtrace.ancestors.empty()); + + // Santity checking backtrace ino against object name + if (have_backtrace && backtrace.ino != obj_name_ino) { + dout(4) << "Backtrace ino 0x" << std::hex << backtrace.ino + << " doesn't match object name ino 0x" << obj_name_ino + << std::dec << dendl; + have_backtrace = false; + } + + uint64_t fnode_version = 0; + fnode_t fnode; + r = read_fnode(obj_name_ino, frag_t(), &fnode, &fnode_version); + if (r == -EINVAL) { + derr << "Corrupt fnode on " << oid << dendl; + if (force_corrupt) { + fnode.fragstat.mtime = 0; + fnode.fragstat.nfiles = 1; + fnode.fragstat.nsubdirs = 0; + } else { + continue; + } + } + + InodeStore dentry; + build_dir_dentry(obj_name_ino, fnode.fragstat.nfiles, + fnode.fragstat.nsubdirs, fnode.fragstat.mtime, loaded_layout, &dentry); + + // Inject inode to the metadata pool + if (have_backtrace) { + inode_backpointer_t root_bp = *(backtrace.ancestors.rbegin()); + if (MDS_INO_IS_MDSDIR(root_bp.dirino)) { + /* Special case for strays: even if we have a good backtrace, + * don't put it in the stray dir, because while that would technically + * give it linkage it would still be invisible to the user */ + r = driver->inject_lost_and_found(obj_name_ino, dentry); + if (r < 0) { + dout(4) << "Error injecting 0x" << std::hex << backtrace.ino + << std::dec << " into lost+found: " << cpp_strerror(r) << dendl; + if (r == -EINVAL) { + dout(4) << "Use --force-corrupt to overwrite structures that " + "appear to be corrupt" << dendl; + } + } + } else { + /* Happy case: we will inject a named dentry for this inode */ + r = driver->inject_with_backtrace(backtrace, dentry); + if (r < 0) { + dout(4) << "Error injecting 0x" << std::hex << backtrace.ino + << std::dec << " with backtrace: " << cpp_strerror(r) << dendl; + if (r == -EINVAL) { + dout(4) << "Use --force-corrupt to overwrite structures that " + "appear to be corrupt" << dendl; + } + } + } + } else { + /* Backtrace-less case: we will inject a lost+found dentry */ + r = driver->inject_lost_and_found( + obj_name_ino, dentry); + if (r < 0) { + dout(4) << "Error injecting 0x" << std::hex << obj_name_ino + << std::dec << " into lost+found: " << cpp_strerror(r) << dendl; + if (r == -EINVAL) { + dout(4) << "Use --force-corrupt to overwrite structures that " + "appear to be corrupt" << dendl; + } + } + } + } + + return 0; +} + +int MetadataTool::read_fnode( inodeno_t ino, frag_t frag, fnode_t *fnode, uint64_t *last_version) { @@ -699,7 +935,7 @@ int MetadataDriver::read_fnode( return 0; } -int MetadataDriver::read_dentry(inodeno_t parent_ino, frag_t frag, +int MetadataTool::read_dentry(inodeno_t parent_ino, frag_t frag, const std::string &dname, InodeStore *inode) { assert(inode != NULL); @@ -765,19 +1001,16 @@ int MetadataDriver::inject_lost_and_found( if (r == -EINVAL && !force_corrupt) { return r; } - // Inject dentry - lf_ino.inode.mode = 0755 | S_IFDIR; - // Set nfiles to something non-zero, to fool any other code - // that tries to ignore 'empty' directories. This won't be - // accurate, but it should avoid functional issues. - lf_ino.inode.dirstat.nfiles = 1; - lf_ino.inode.size = 1; - lf_ino.inode.nlink = 1; - lf_ino.inode.ino = CEPH_INO_LOST_AND_FOUND; - lf_ino.inode.version = 1; - lf_ino.inode.backtrace_version = 1; - lf_ino.inode.uid = g_conf->mds_root_ino_uid; - lf_ino.inode.gid = g_conf->mds_root_ino_gid; + + // To have a directory not specify a layout, give it zeros (see + // inode_t::has_layout) + ceph_file_layout inherit_layout; + memset(&inherit_layout, 0, sizeof(inherit_layout)); + + // Construct LF inode + build_dir_dentry(CEPH_INO_LOST_AND_FOUND, 1, 0, 0, inherit_layout, &lf_ino); + + // Inject link to LF inode in the root dir r = inject_linkage(CEPH_INO_ROOT, "lost+found", frag_t(), lf_ino); if (r < 0) { return r; @@ -1046,6 +1279,7 @@ int MetadataDriver::inject_with_backtrace( // Set nfiles to something non-zero, to fool any other code // that tries to ignore 'empty' directories. This won't be // accurate, but it should avoid functional issues. + ancestor_dentry.inode.dirstat.nfiles = 1; ancestor_dentry.inode.size = 1; @@ -1339,7 +1573,7 @@ int LocalFileDriver::check_roots(bool *result) return 0; } -void DataScan::build_file_dentry( +void MetadataTool::build_file_dentry( inodeno_t ino, uint64_t file_size, time_t file_mtime, const ceph_file_layout &layout, InodeStore *out) { @@ -1367,3 +1601,32 @@ void DataScan::build_file_dentry( out->inode.gid = g_conf->mds_root_ino_gid; } +void MetadataTool::build_dir_dentry( + inodeno_t ino, uint64_t nfiles, uint64_t nsubdirs, + time_t mtime, const ceph_file_layout &layout, InodeStore *out) +{ + assert(out != NULL); + + out->inode.mode = 0755 | S_IFDIR; + out->inode.size = nfiles; + out->inode.dirstat.nfiles = nfiles; + out->inode.max_size_ever = nfiles; + out->inode.mtime.tv.tv_sec = mtime; + out->inode.atime.tv.tv_sec = mtime; + out->inode.ctime.tv.tv_sec = mtime; + + out->inode.layout = layout; + + out->inode.truncate_seq = 1; + out->inode.truncate_size = -1ull; + + out->inode.inline_data.version = CEPH_INLINE_NONE; + + out->inode.nlink = 2 + nsubdirs; + out->inode.ino = ino; + out->inode.version = 1; + out->inode.backtrace_version = 1; + out->inode.uid = g_conf->mds_root_ino_uid; + out->inode.gid = g_conf->mds_root_ino_gid; +} + diff --git a/src/tools/cephfs/DataScan.h b/src/tools/cephfs/DataScan.h index 7cdc2d8a096e5..2404d665a2df4 100644 --- a/src/tools/cephfs/DataScan.h +++ b/src/tools/cephfs/DataScan.h @@ -128,14 +128,51 @@ class LocalFileDriver : public RecoveryDriver }; /** - * A class that knows how to manipulate CephFS metadata pools + * A class that knows how to work with objects in a CephFS + * metadata pool. */ -class MetadataDriver : public RecoveryDriver +class MetadataTool { protected: - librados::IoCtx metadata_io; + librados::IoCtx metadata_io; + + /** + * Construct a synthetic InodeStore for a normal file + */ + void build_file_dentry( + inodeno_t ino, uint64_t file_size, time_t file_mtime, + const ceph_file_layout &layout, + InodeStore *out); + + /** + * Construct a synthetic InodeStore for a directory + */ + void build_dir_dentry( + inodeno_t ino, uint64_t nfiles, uint64_t nsubdirs, + time_t mtime, + const ceph_file_layout &layout, + InodeStore *out); + + /** + * Try and read an fnode from a dirfrag + */ + int read_fnode(inodeno_t ino, frag_t frag, + fnode_t *fnode, uint64_t *read_version); + + /** + * Try and read a dentry from a dirfrag + */ + int read_dentry(inodeno_t parent_ino, frag_t frag, + const std::string &dname, InodeStore *inode); +}; +/** + * A class that knows how to manipulate CephFS metadata pools + */ +class MetadataDriver : public RecoveryDriver, public MetadataTool +{ + protected: /** * Create a .inode object, i.e. root or mydir */ @@ -146,19 +183,6 @@ class MetadataDriver : public RecoveryDriver * trying to go ahead and inject metadata. */ int root_exists(inodeno_t ino, bool *result); - - /** - * Try and read an fnode from a dirfrag - */ - int read_fnode(inodeno_t ino, frag_t frag, - fnode_t *fnode, uint64_t *read_version); - - /** - * Try and read a dentry from a dirfrag - */ - int read_dentry(inodeno_t parent_ino, frag_t frag, - const std::string &dname, InodeStore *inode); - int find_or_create_dirfrag( inodeno_t ino, frag_t fragment, @@ -196,12 +220,12 @@ class MetadataDriver : public RecoveryDriver int check_roots(bool *result); }; -class DataScan : public MDSUtility +class DataScan : public MDSUtility, public MetadataTool { protected: RecoveryDriver *driver; - // IoCtx for data pool (where we scrape backtraces from) + // IoCtx for data pool (where we scrape file backtraces from) librados::IoCtx data_io; // Remember the data pool ID for use in layouts int64_t data_pool_id; @@ -219,6 +243,12 @@ class DataScan : public MDSUtility */ int scan_extents(); + /** + * Scan metadata pool for 0th dirfrags to link orphaned + * directory inodes. + */ + int scan_frags(); + // Accept pools which are not in the MDSMap bool force_pool; // Respond to decode errors by overwriting @@ -242,10 +272,6 @@ class DataScan : public MDSUtility const std::vector &arg, std::vector::const_iterator &i); - void build_file_dentry( - inodeno_t ino, uint64_t file_size, time_t file_mtime, - const ceph_file_layout &layout, - InodeStore *out); public: From 43c1ba7c40cd1fdabaf6bbb75c4155b98a038f84 Mon Sep 17 00:00:00 2001 From: John Spray Date: Sun, 29 Nov 2015 16:20:39 +0000 Subject: [PATCH 3/3] tools: fix cephfs-data-scan scan_frags vs. nlink Signed-off-by: John Spray --- src/tools/cephfs/DataScan.cc | 8 ++++---- src/tools/cephfs/DataScan.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/cephfs/DataScan.cc b/src/tools/cephfs/DataScan.cc index 619c69380b8fc..59fff63bc6ad2 100644 --- a/src/tools/cephfs/DataScan.cc +++ b/src/tools/cephfs/DataScan.cc @@ -863,7 +863,7 @@ int DataScan::scan_frags() InodeStore dentry; build_dir_dentry(obj_name_ino, fnode.fragstat.nfiles, - fnode.fragstat.nsubdirs, fnode.fragstat.mtime, loaded_layout, &dentry); + fnode.fragstat.mtime, loaded_layout, &dentry); // Inject inode to the metadata pool if (have_backtrace) { @@ -1008,7 +1008,7 @@ int MetadataDriver::inject_lost_and_found( memset(&inherit_layout, 0, sizeof(inherit_layout)); // Construct LF inode - build_dir_dentry(CEPH_INO_LOST_AND_FOUND, 1, 0, 0, inherit_layout, &lf_ino); + build_dir_dentry(CEPH_INO_LOST_AND_FOUND, 1, 0, inherit_layout, &lf_ino); // Inject link to LF inode in the root dir r = inject_linkage(CEPH_INO_ROOT, "lost+found", frag_t(), lf_ino); @@ -1602,7 +1602,7 @@ void MetadataTool::build_file_dentry( } void MetadataTool::build_dir_dentry( - inodeno_t ino, uint64_t nfiles, uint64_t nsubdirs, + inodeno_t ino, uint64_t nfiles, time_t mtime, const ceph_file_layout &layout, InodeStore *out) { assert(out != NULL); @@ -1622,7 +1622,7 @@ void MetadataTool::build_dir_dentry( out->inode.inline_data.version = CEPH_INLINE_NONE; - out->inode.nlink = 2 + nsubdirs; + out->inode.nlink = 1; out->inode.ino = ino; out->inode.version = 1; out->inode.backtrace_version = 1; diff --git a/src/tools/cephfs/DataScan.h b/src/tools/cephfs/DataScan.h index 2404d665a2df4..f3d29aa7aa5f5 100644 --- a/src/tools/cephfs/DataScan.h +++ b/src/tools/cephfs/DataScan.h @@ -149,7 +149,7 @@ class MetadataTool * Construct a synthetic InodeStore for a directory */ void build_dir_dentry( - inodeno_t ino, uint64_t nfiles, uint64_t nsubdirs, + inodeno_t ino, uint64_t nfiles, time_t mtime, const ceph_file_layout &layout, InodeStore *out);