summaryrefslogtreecommitdiffstats
path: root/src/tools/cephfs
diff options
context:
space:
mode:
authorYan, Zheng <ukernel@gmail.com>2015-12-03 15:10:26 +0100
committerYan, Zheng <ukernel@gmail.com>2015-12-03 15:10:26 +0100
commit72691dd9a0589dfd9f02225e76ce49538d677e7b (patch)
tree568676a61bde1954896d4bfd568a4406aac21c0d /src/tools/cephfs
parentMerge pull request #6777 from dillaman/wip-librbd-lockdep (diff)
parenttools: fix cephfs-data-scan scan_frags vs. nlink (diff)
downloadceph-72691dd9a0589dfd9f02225e76ce49538d677e7b.tar.xz
ceph-72691dd9a0589dfd9f02225e76ce49538d677e7b.zip
Merge pull request #5941 from jcsp/wip-12137
#12137: cephfs-data-scan scan_frags
Diffstat (limited to 'src/tools/cephfs')
-rw-r--r--src/tools/cephfs/DataScan.cc420
-rw-r--r--src/tools/cephfs/DataScan.h92
2 files changed, 394 insertions, 118 deletions
diff --git a/src/tools/cephfs/DataScan.cc b/src/tools/cephfs/DataScan.cc
index 96f09ce9cb9..965ab52804c 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();
@@ -205,11 +207,31 @@ int DataScan::main(const std::vector<const char*> &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 {
@@ -694,6 +716,223 @@ 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());
+ 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 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.mtime, loaded_layout, &dentry);
+
// Inject inode to the metadata pool
if (have_backtrace) {
inode_backpointer_t root_bp = *(backtrace.ancestors.rbegin());
@@ -701,8 +940,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;
@@ -713,8 +951,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;
@@ -727,7 +964,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;
@@ -742,7 +979,7 @@ int DataScan::scan_inodes()
return 0;
}
-int MetadataDriver::read_fnode(
+int MetadataTool::read_fnode(
inodeno_t ino, frag_t frag, fnode_t *fnode,
uint64_t *last_version)
{
@@ -766,7 +1003,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);
@@ -817,8 +1054,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;
@@ -832,19 +1069,16 @@ int MetadataDriver::inject_lost_and_found(inodeno_t ino, uint64_t file_size,
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, 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;
@@ -864,31 +1098,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);
}
@@ -1000,8 +1215,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)
{
@@ -1110,53 +1324,42 @@ 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;
-
- // 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;
+ << " with size=" << dentry.inode.size << " bytes" << dendl;
- 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;
}
@@ -1355,9 +1558,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;
@@ -1375,7 +1576,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) {
@@ -1391,9 +1592,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);
@@ -1404,7 +1603,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)
@@ -1442,3 +1641,60 @@ int LocalFileDriver::check_roots(bool *result)
return 0;
}
+void MetadataTool::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;
+}
+
+void MetadataTool::build_dir_dentry(
+ inodeno_t ino, uint64_t nfiles,
+ 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 = 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 03a4b64943d..cc9e39e3774 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);
@@ -136,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,
+ 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
*/
@@ -154,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,
@@ -193,27 +209,23 @@ 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);
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;
@@ -231,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
@@ -256,6 +274,8 @@ class DataScan : public MDSUtility
const std::vector<const char*> &arg,
std::vector<const char *>::const_iterator &i);
+
+
public:
void usage();
int main(const std::vector<const char *> &args);