summaryrefslogtreecommitdiffstats
path: root/src/mds/ScrubStack.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/mds/ScrubStack.cc')
-rw-r--r--src/mds/ScrubStack.cc183
1 files changed, 181 insertions, 2 deletions
diff --git a/src/mds/ScrubStack.cc b/src/mds/ScrubStack.cc
index 28392f53366..7ec77a31de3 100644
--- a/src/mds/ScrubStack.cc
+++ b/src/mds/ScrubStack.cc
@@ -17,6 +17,7 @@
#include "mds/MDSRank.h"
#include "mds/MDCache.h"
#include "mds/MDSContinuation.h"
+#include "osdc/Objecter.h"
#define dout_context g_ceph_context
#define dout_subsys ceph_subsys_mds
@@ -75,6 +76,7 @@ int ScrubStack::_enqueue(MDSCacheObject *obj, ScrubHeaderRef& header, bool top)
dout(10) << __func__ << " with {" << *in << "}" << ", top=" << top << dendl;
in->scrub_initialize(header);
+ in->uninline_initialize();
} else if (CDir *dir = dynamic_cast<CDir*>(obj)) {
if (dir->scrub_is_in_progress()) {
dout(10) << __func__ << " with {" << *dir << "}" << ", already in scrubbing" << dendl;
@@ -106,6 +108,55 @@ int ScrubStack::_enqueue(MDSCacheObject *obj, ScrubHeaderRef& header, bool top)
return 0;
}
+void ScrubStack::purge_scrub_counters(std::string_view tag)
+{
+ for (auto& stat : mds_scrub_stats) {
+ if (tag == "all") {
+ stat.counters.clear();
+ } else {
+ auto it = stat.counters.find(std::string(tag));
+ if (it != stat.counters.end()) {
+ stat.counters.erase(it);
+ }
+ }
+ }
+}
+
+// called from tick
+void ScrubStack::purge_old_scrub_counters()
+{
+ // "mds_scrub_stats_review_period" must be in number of days
+ auto review_period = ceph::make_timespan(_mds_scrub_stats_review_period * 24 * 60 * 60);
+ auto now = coarse_real_clock::now();
+
+ dout(20) << __func__ << " review_period:" << review_period << dendl;
+
+ for (mds_rank_t rank = 0; rank < (mds_rank_t)mds_scrub_stats.size(); rank++) {
+ auto& counters = mds_scrub_stats[rank].counters;
+ for (auto it = counters.begin(); it != counters.end(); ) {
+ auto curr = it;
+ auto c = (*it).second;
+ auto elapsed = now - c.start_time;
+ dout(20) << __func__
+ << " rank(" << rank << ") :"
+ << " elapsed:" << elapsed
+ << dendl;
+ ++it;
+ if (elapsed >= review_period) {
+ counters.erase(curr);
+ }
+ }
+ }
+}
+
+void ScrubStack::init_scrub_counters(std::string_view path, std::string_view tag)
+{
+ scrub_counters_t sc{coarse_real_clock::now(), std::string(path), 0, 0, 0};
+ for (auto& stat : mds_scrub_stats) {
+ stat.counters[std::string(tag)] = sc;
+ }
+}
+
int ScrubStack::enqueue(CInode *in, ScrubHeaderRef& header, bool top)
{
// abort in progress
@@ -133,6 +184,10 @@ int ScrubStack::enqueue(CInode *in, ScrubHeaderRef& header, bool top)
//to make sure mdsdir is always on the top
top = false;
}
+
+ std::string path;
+ in->make_path_string(path);
+ init_scrub_counters(path, header->get_tag());
int r = _enqueue(in, header, top);
if (r < 0)
return r;
@@ -227,6 +282,7 @@ void ScrubStack::kick_off_scrubs()
// it's a regular file, symlink, or hard link
dequeue(in); // we only touch it this once, so remove from stack
+ uninline_data(in, new C_MDSInternalNoop);
scrub_file_inode(in);
} else {
bool added_children = false;
@@ -235,6 +291,7 @@ void ScrubStack::kick_off_scrubs()
if (done) {
dout(20) << __func__ << " dir inode, done" << dendl;
dequeue(in);
+ in->uninline_finished();
}
if (added_children) {
// dirfrags were queued at top of stack
@@ -707,6 +764,43 @@ void ScrubStack::scrub_status(Formatter *f) {
f->close_section(); // scrub id
}
f->close_section(); // scrubs
+
+ if (mds_scrub_stats.size()) {
+ f->open_object_section("scrub_stats");
+ for (auto& [tag, ctrs] : mds_scrub_stats[0].counters) {
+ uint64_t started = 0;
+ uint64_t passed = 0;
+ uint64_t failed = 0;
+ uint64_t skipped = 0;
+ for (auto& stats : mds_scrub_stats) {
+ if (auto it = stats.counters.find(tag); it != stats.counters.end()) {
+ auto& [t, c] = *it;
+ started += c.uninline_started;
+ passed += c.uninline_passed;
+ failed += c.uninline_failed;
+ skipped += c.uninline_skipped;
+ }
+ }
+ f->open_object_section(tag);
+ {
+ f->dump_stream("start_time") << ctrs.start_time;
+ std::string path = ctrs.origin_path;
+ if (path == "") {
+ path = "/";
+ } else if (path.starts_with("~mds")) {
+ path = "~mdsdir";
+ }
+ f->dump_string("path", path);
+ f->dump_int("uninline_started", started);
+ f->dump_int("uninline_passed", passed);
+ f->dump_int("uninline_failed", failed);
+ f->dump_int("uninline_skipped", skipped);
+ }
+ f->close_section(); // tag
+ }
+ f->close_section(); // scrub_stats
+ }
+
f->close_section(); // result
}
@@ -936,6 +1030,7 @@ void ScrubStack::handle_scrub(const cref_t<MMDSScrub> &m)
header->set_origin(m->get_origin());
scrubbing_map.emplace(header->get_tag(), header);
}
+
for (auto dir : dfs) {
queued.insert_raw(dir->get_frag());
_enqueue(dir, header, true);
@@ -1016,6 +1111,7 @@ void ScrubStack::handle_scrub(const cref_t<MMDSScrub> &m)
const auto& header = in->get_scrub_header();
header->set_epoch_last_forwarded(scrub_epoch);
in->scrub_finished();
+ in->uninline_finished();
kick_off_scrubs();
}
@@ -1052,6 +1148,10 @@ void ScrubStack::handle_scrub_stats(const cref_t<MMDSScrubStats> &m)
bool any_finished = false;
bool any_repaired = false;
std::set<std::string> scrubbing_tags;
+ std::unordered_map<std::string, unordered_map<int, std::vector<_inodeno_t>>> uninline_failed_meta_info;
+ std::unordered_map<_inodeno_t, std::string> paths;
+ std::unordered_map<std::string, std::vector<uint64_t>> counters;
+
for (auto it = scrubbing_map.begin(); it != scrubbing_map.end(); ) {
auto& header = it->second;
if (header->get_num_pending() ||
@@ -1062,6 +1162,17 @@ void ScrubStack::handle_scrub_stats(const cref_t<MMDSScrubStats> &m)
any_finished = true;
if (header->get_repaired())
any_repaired = true;
+ auto& ufi = header->get_uninline_failed_info();
+ uninline_failed_meta_info[it->first] = ufi;
+ ufi.clear();
+ paths.merge(header->get_paths());
+ ceph_assert(header->get_paths().size() == 0);
+ std::vector<uint64_t> c{header->get_uninline_started(),
+ header->get_uninline_passed(),
+ header->get_uninline_failed(),
+ header->get_uninline_skipped()
+ };
+ counters[header->get_tag()] = c;
scrubbing_map.erase(it++);
} else {
++it;
@@ -1071,7 +1182,11 @@ void ScrubStack::handle_scrub_stats(const cref_t<MMDSScrubStats> &m)
scrub_epoch = m->get_epoch();
auto ack = make_message<MMDSScrubStats>(scrub_epoch,
- std::move(scrubbing_tags), clear_stack);
+ std::move(scrubbing_tags),
+ std::move(uninline_failed_meta_info),
+ std::move(paths),
+ std::move(counters),
+ clear_stack);
mdcache->mds->send_message_mds(ack, 0);
if (any_finished)
@@ -1085,7 +1200,40 @@ void ScrubStack::handle_scrub_stats(const cref_t<MMDSScrubStats> &m)
stat.epoch_acked = m->get_epoch();
stat.scrubbing_tags = m->get_scrubbing_tags();
stat.aborting = m->is_aborting();
+ for (auto& [scrub_tag, errno_map] : m->get_uninline_failed_meta_info()) {
+ stat.uninline_failed_meta_info[scrub_tag] = errno_map;
+ }
+ stat.paths.insert(m->get_paths().begin(), m->get_paths().end());;
+ for (auto& [tag, v] : m->get_counters()) {
+ stat.counters[tag].uninline_started = v[0];
+ stat.counters[tag].uninline_passed = v[1];
+ stat.counters[tag].uninline_failed = v[2];
+ stat.counters[tag].uninline_skipped = v[3];
+ }
+ }
+ }
+}
+
+void ScrubStack::move_uninline_failures_to_damage_table()
+{
+ auto mds = mdcache->mds;
+
+ for (mds_rank_t rank = 0; rank < (mds_rank_t)mds_scrub_stats.size(); rank++) {
+ auto& ufmi = mds_scrub_stats[rank].uninline_failed_meta_info;
+ auto& paths = mds_scrub_stats[rank].paths;
+
+ for (const auto& [scrub_tag, errno_ino_vec_map] : ufmi) {
+ for (const auto& [errno_, ino_vec] : errno_ino_vec_map) {
+ for (auto ino : ino_vec) {
+ mds->damage_table.notify_uninline_failed(ino, rank, errno_, scrub_tag, paths[ino]);
+ }
+ }
}
+ ufmi.clear();
+ paths.clear();
+ // do not clear the counters map; we'll clear them later:
+ // - on user request or
+ // - after a grace period
}
}
@@ -1152,6 +1300,18 @@ void ScrubStack::advance_scrub_status()
any_finished = true;
if (header->get_repaired())
any_repaired = true;
+ auto& ufmi = mds_scrub_stats[0].uninline_failed_meta_info;
+ ufmi[it->first] = header->get_uninline_failed_info();
+ mds_scrub_stats[0].paths.merge(header->get_paths());
+ move_uninline_failures_to_damage_table();
+
+ auto& c = mds_scrub_stats[0].counters;
+ auto& sc = c[header->get_tag()];
+ sc.uninline_started = header->get_uninline_started();
+ sc.uninline_passed = header->get_uninline_passed();
+ sc.uninline_failed = header->get_uninline_failed();
+ sc.uninline_skipped = header->get_uninline_skipped();
+
scrubbing_map.erase(it++);
} else {
++it;
@@ -1159,7 +1319,6 @@ void ScrubStack::advance_scrub_status()
}
++scrub_epoch;
-
for (auto& r : up_mds) {
if (r == 0)
continue;
@@ -1197,3 +1356,23 @@ void ScrubStack::handle_mds_failure(mds_rank_t mds)
if (kick)
kick_off_scrubs();
}
+
+void ScrubStack::uninline_data(CInode *in, Context *fin)
+{
+ dout(10) << "(uninline_data) starting data uninlining for " << *in << dendl;
+
+ MDRequestRef mdr = in->mdcache->request_start_internal(CEPH_MDS_OP_UNINLINE_DATA);
+ mdr->set_filepath(filepath(in->ino()));
+ mdr->snapid = CEPH_NOSNAP;
+ mdr->no_early_reply = true;
+ mdr->internal_op_finish = fin;
+
+ in->mdcache->dispatch_request(mdr);
+}
+
+void ScrubStack::handle_conf_change(const std::set<std::string>& changed)
+{
+ if (changed.count("mds_scrub_stats_review_period")) {
+ _mds_scrub_stats_review_period = g_conf().get_val<uint64_t>("mds_scrub_stats_review_period");
+ }
+}