summaryrefslogtreecommitdiffstats
path: root/src/mds/DamageTable.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/mds/DamageTable.cc')
-rw-r--r--src/mds/DamageTable.cc275
1 files changed, 275 insertions, 0 deletions
diff --git a/src/mds/DamageTable.cc b/src/mds/DamageTable.cc
new file mode 100644
index 000000000..22802079d
--- /dev/null
+++ b/src/mds/DamageTable.cc
@@ -0,0 +1,275 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#include "common/debug.h"
+
+#include "mds/CDir.h"
+
+#include "DamageTable.h"
+
+#define dout_context g_ceph_context
+#define dout_subsys ceph_subsys_mds
+#undef dout_prefix
+#define dout_prefix *_dout << "mds." << rank << ".damage " << __func__ << " "
+
+namespace {
+/**
+ * Record damage to a particular dirfrag, implicitly affecting
+ * any dentries within it.
+ */
+class DirFragDamage : public DamageEntry
+{
+ public:
+ inodeno_t ino;
+ frag_t frag;
+
+ DirFragDamage(inodeno_t ino_, frag_t frag_)
+ : ino(ino_), frag(frag_)
+ {}
+
+ damage_entry_type_t get_type() const override
+ {
+ return DAMAGE_ENTRY_DIRFRAG;
+ }
+
+ void dump(Formatter *f) const override
+ {
+ f->open_object_section("dir_frag_damage");
+ f->dump_string("damage_type", "dir_frag");
+ f->dump_int("id", id);
+ f->dump_int("ino", ino);
+ f->dump_stream("frag") << frag;
+ f->dump_string("path", path);
+ f->close_section();
+ }
+};
+
+
+/**
+ * Record damage to a particular dname within a particular dirfrag
+ */
+class DentryDamage : public DamageEntry
+{
+ public:
+ inodeno_t ino;
+ frag_t frag;
+ std::string dname;
+ snapid_t snap_id;
+
+ DentryDamage(
+ inodeno_t ino_,
+ frag_t frag_,
+ std::string_view dname_,
+ snapid_t snap_id_)
+ : ino(ino_), frag(frag_), dname(dname_), snap_id(snap_id_)
+ {}
+
+ damage_entry_type_t get_type() const override
+ {
+ return DAMAGE_ENTRY_DENTRY;
+ }
+
+ void dump(Formatter *f) const override
+ {
+ f->open_object_section("dentry_damage");
+ f->dump_string("damage_type", "dentry");
+ f->dump_int("id", id);
+ f->dump_int("ino", ino);
+ f->dump_stream("frag") << frag;
+ f->dump_string("dname", dname);
+ f->dump_stream("snap_id") << snap_id;
+ f->dump_string("path", path);
+ f->close_section();
+ }
+};
+
+
+/**
+ * Record damage to our ability to look up an ino by number
+ */
+class BacktraceDamage : public DamageEntry
+{
+ public:
+ inodeno_t ino;
+
+ BacktraceDamage(inodeno_t ino_)
+ : ino(ino_)
+ {}
+
+ damage_entry_type_t get_type() const override
+ {
+ return DAMAGE_ENTRY_BACKTRACE;
+ }
+
+ void dump(Formatter *f) const override
+ {
+ f->open_object_section("backtrace_damage");
+ f->dump_string("damage_type", "backtrace");
+ f->dump_int("id", id);
+ f->dump_int("ino", ino);
+ f->dump_string("path", path);
+ f->close_section();
+ }
+};
+}
+
+DamageEntry::~DamageEntry()
+{}
+
+bool DamageTable::notify_dentry(
+ inodeno_t ino, frag_t frag,
+ snapid_t snap_id, std::string_view dname, std::string_view path)
+{
+ if (oversized()) {
+ return true;
+ }
+
+ // Special cases: damage to these dirfrags is considered fatal to
+ // the MDS rank that owns them.
+ if (
+ (MDS_INO_IS_MDSDIR(ino) && MDS_INO_MDSDIR_OWNER(ino) == rank)
+ ||
+ (MDS_INO_IS_STRAY(ino) && MDS_INO_STRAY_OWNER(ino) == rank)
+ ) {
+ derr << "Damage to dentries in fragment " << frag << " of ino " << ino
+ << "is fatal because it is a system directory for this rank" << dendl;
+ return true;
+ }
+
+ auto& df_dentries = dentries[DirFragIdent(ino, frag)];
+ if (auto [it, inserted] = df_dentries.try_emplace(DentryIdent(dname, snap_id)); inserted) {
+ auto entry = std::make_shared<DentryDamage>(ino, frag, dname, snap_id);
+ entry->path = path;
+ it->second = entry;
+ by_id[entry->id] = std::move(entry);
+ }
+
+ return false;
+}
+
+bool DamageTable::notify_dirfrag(inodeno_t ino, frag_t frag,
+ std::string_view path)
+{
+ // Special cases: damage to these dirfrags is considered fatal to
+ // the MDS rank that owns them.
+ if ((MDS_INO_IS_STRAY(ino) && MDS_INO_STRAY_OWNER(ino) == rank)
+ || (ino == CEPH_INO_ROOT)) {
+ derr << "Damage to fragment " << frag << " of ino " << ino
+ << " is fatal because it is a system directory for this rank" << dendl;
+ return true;
+ }
+
+ if (oversized()) {
+ return true;
+ }
+
+ if (auto [it, inserted] = dirfrags.try_emplace(DirFragIdent(ino, frag)); inserted) {
+ DamageEntryRef entry = std::make_shared<DirFragDamage>(ino, frag);
+ entry->path = path;
+ it->second = entry;
+ by_id[entry->id] = std::move(entry);
+ }
+
+ return false;
+}
+
+bool DamageTable::notify_remote_damaged(inodeno_t ino, std::string_view path)
+{
+ if (oversized()) {
+ return true;
+ }
+
+ if (auto [it, inserted] = remotes.try_emplace(ino); inserted) {
+ auto entry = std::make_shared<BacktraceDamage>(ino);
+ entry->path = path;
+ it->second = entry;
+ by_id[entry->id] = std::move(entry);
+ }
+
+ return false;
+}
+
+bool DamageTable::oversized() const
+{
+ return by_id.size() > (size_t)(g_conf()->mds_damage_table_max_entries);
+}
+
+bool DamageTable::is_dentry_damaged(
+ const CDir *dir_frag,
+ std::string_view dname,
+ const snapid_t snap_id) const
+{
+ if (dentries.count(
+ DirFragIdent(dir_frag->inode->ino(), dir_frag->frag)
+ ) == 0) {
+ return false;
+ }
+
+ const std::map<DentryIdent, DamageEntryRef> &frag_dentries =
+ dentries.at(DirFragIdent(dir_frag->inode->ino(), dir_frag->frag));
+
+ return frag_dentries.count(DentryIdent(dname, snap_id)) > 0;
+}
+
+bool DamageTable::is_dirfrag_damaged(
+ const CDir *dir_frag) const
+{
+ return dirfrags.count(
+ DirFragIdent(dir_frag->inode->ino(), dir_frag->frag)) > 0;
+}
+
+bool DamageTable::is_remote_damaged(
+ const inodeno_t ino) const
+{
+ return remotes.count(ino) > 0;
+}
+
+void DamageTable::dump(Formatter *f) const
+{
+ f->open_array_section("damage_table");
+ for (const auto &i : by_id)
+ {
+ i.second->dump(f);
+ }
+ f->close_section();
+}
+
+void DamageTable::erase(damage_entry_id_t damage_id)
+{
+ auto by_id_entry = by_id.find(damage_id);
+ if (by_id_entry == by_id.end()) {
+ return;
+ }
+
+ DamageEntryRef entry = by_id_entry->second;
+ ceph_assert(entry->id == damage_id); // Sanity
+
+ const auto type = entry->get_type();
+ if (type == DAMAGE_ENTRY_DIRFRAG) {
+ auto dirfrag_entry = std::static_pointer_cast<DirFragDamage>(entry);
+ dirfrags.erase(DirFragIdent(dirfrag_entry->ino, dirfrag_entry->frag));
+ } else if (type == DAMAGE_ENTRY_DENTRY) {
+ auto dentry_entry = std::static_pointer_cast<DentryDamage>(entry);
+ dentries.erase(DirFragIdent(dentry_entry->ino, dentry_entry->frag));
+ } else if (type == DAMAGE_ENTRY_BACKTRACE) {
+ auto backtrace_entry = std::static_pointer_cast<BacktraceDamage>(entry);
+ remotes.erase(backtrace_entry->ino);
+ } else {
+ derr << "Invalid type " << type << dendl;
+ ceph_abort();
+ }
+
+ by_id.erase(by_id_entry);
+}
+