1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 #include "common/debug.h"
19 #include "DamageTable.h"
21 #define dout_context g_ceph_context
22 #define dout_subsys ceph_subsys_mds
24 #define dout_prefix *_dout << "mds." << rank << ".damage " << __func__ << " "
28 * Record damage to a particular dirfrag, implicitly affecting
29 * any dentries within it.
31 class DirFragDamage
: public DamageEntry
37 DirFragDamage(inodeno_t ino_
, frag_t frag_
)
38 : ino(ino_
), frag(frag_
)
41 damage_entry_type_t
get_type() const override
43 return DAMAGE_ENTRY_DIRFRAG
;
46 void dump(Formatter
*f
) const override
48 f
->open_object_section("dir_frag_damage");
49 f
->dump_string("damage_type", "dir_frag");
50 f
->dump_int("id", id
);
51 f
->dump_int("ino", ino
);
52 f
->dump_stream("frag") << frag
;
53 f
->dump_string("path", path
);
60 * Record damage to a particular dname within a particular dirfrag
62 class DentryDamage
: public DamageEntry
73 std::string_view dname_
,
75 : ino(ino_
), frag(frag_
), dname(dname_
), snap_id(snap_id_
)
78 damage_entry_type_t
get_type() const override
80 return DAMAGE_ENTRY_DENTRY
;
83 void dump(Formatter
*f
) const override
85 f
->open_object_section("dentry_damage");
86 f
->dump_string("damage_type", "dentry");
87 f
->dump_int("id", id
);
88 f
->dump_int("ino", ino
);
89 f
->dump_stream("frag") << frag
;
90 f
->dump_string("dname", dname
);
91 f
->dump_stream("snap_id") << snap_id
;
92 f
->dump_string("path", path
);
99 * Record damage to our ability to look up an ino by number
101 class BacktraceDamage
: public DamageEntry
106 BacktraceDamage(inodeno_t ino_
)
110 damage_entry_type_t
get_type() const override
112 return DAMAGE_ENTRY_BACKTRACE
;
115 void dump(Formatter
*f
) const override
117 f
->open_object_section("backtrace_damage");
118 f
->dump_string("damage_type", "backtrace");
119 f
->dump_int("id", id
);
120 f
->dump_int("ino", ino
);
121 f
->dump_string("path", path
);
127 DamageEntry::~DamageEntry()
130 bool DamageTable::notify_dentry(
131 inodeno_t ino
, frag_t frag
,
132 snapid_t snap_id
, std::string_view dname
, std::string_view path
)
138 // Special cases: damage to these dirfrags is considered fatal to
139 // the MDS rank that owns them.
141 (MDS_INO_IS_MDSDIR(ino
) && MDS_INO_MDSDIR_OWNER(ino
) == rank
)
143 (MDS_INO_IS_STRAY(ino
) && MDS_INO_STRAY_OWNER(ino
) == rank
)
145 derr
<< "Damage to dentries in fragment " << frag
<< " of ino " << ino
146 << "is fatal because it is a system directory for this rank" << dendl
;
150 auto key
= DirFragIdent(ino
, frag
);
151 if (dentries
.count(key
) == 0) {
152 DamageEntryRef entry
= std::make_shared
<DentryDamage
>(
153 ino
, frag
, dname
, snap_id
);
155 dentries
[key
][DentryIdent(dname
, snap_id
)] = entry
;
156 by_id
[entry
->id
] = std::move(entry
);
162 bool DamageTable::notify_dirfrag(inodeno_t ino
, frag_t frag
,
163 std::string_view path
)
165 // Special cases: damage to these dirfrags is considered fatal to
166 // the MDS rank that owns them.
167 if ((MDS_INO_IS_STRAY(ino
) && MDS_INO_STRAY_OWNER(ino
) == rank
)
168 || (ino
== CEPH_INO_ROOT
)) {
169 derr
<< "Damage to fragment " << frag
<< " of ino " << ino
170 << " is fatal because it is a system directory for this rank" << dendl
;
178 auto key
= DirFragIdent(ino
, frag
);
179 if (dirfrags
.count(key
) == 0) {
180 DamageEntryRef entry
= std::make_shared
<DirFragDamage
>(ino
, frag
);
182 dirfrags
[key
] = entry
;
183 by_id
[entry
->id
] = std::move(entry
);
189 bool DamageTable::notify_remote_damaged(inodeno_t ino
, std::string_view path
)
195 if (remotes
.count(ino
) == 0) {
196 auto entry
= std::make_shared
<BacktraceDamage
>(ino
);
198 remotes
[ino
] = entry
;
199 by_id
[entry
->id
] = std::move(entry
);
205 bool DamageTable::oversized() const
207 return by_id
.size() > (size_t)(g_conf()->mds_damage_table_max_entries
);
210 bool DamageTable::is_dentry_damaged(
211 const CDir
*dir_frag
,
212 std::string_view dname
,
213 const snapid_t snap_id
) const
216 DirFragIdent(dir_frag
->inode
->ino(), dir_frag
->frag
)
221 const std::map
<DentryIdent
, DamageEntryRef
> &frag_dentries
=
222 dentries
.at(DirFragIdent(dir_frag
->inode
->ino(), dir_frag
->frag
));
224 return frag_dentries
.count(DentryIdent(dname
, snap_id
)) > 0;
227 bool DamageTable::is_dirfrag_damaged(
228 const CDir
*dir_frag
) const
230 return dirfrags
.count(
231 DirFragIdent(dir_frag
->inode
->ino(), dir_frag
->frag
)) > 0;
234 bool DamageTable::is_remote_damaged(
235 const inodeno_t ino
) const
237 return remotes
.count(ino
) > 0;
240 void DamageTable::dump(Formatter
*f
) const
242 f
->open_array_section("damage_table");
243 for (const auto &i
: by_id
)
250 void DamageTable::erase(damage_entry_id_t damage_id
)
252 auto by_id_entry
= by_id
.find(damage_id
);
253 if (by_id_entry
== by_id
.end()) {
257 DamageEntryRef entry
= by_id_entry
->second
;
258 ceph_assert(entry
->id
== damage_id
); // Sanity
260 const auto type
= entry
->get_type();
261 if (type
== DAMAGE_ENTRY_DIRFRAG
) {
262 auto dirfrag_entry
= std::static_pointer_cast
<DirFragDamage
>(entry
);
263 dirfrags
.erase(DirFragIdent(dirfrag_entry
->ino
, dirfrag_entry
->frag
));
264 } else if (type
== DAMAGE_ENTRY_DENTRY
) {
265 auto dentry_entry
= std::static_pointer_cast
<DentryDamage
>(entry
);
266 dentries
.erase(DirFragIdent(dentry_entry
->ino
, dentry_entry
->frag
));
267 } else if (type
== DAMAGE_ENTRY_BACKTRACE
) {
268 auto backtrace_entry
= std::static_pointer_cast
<BacktraceDamage
>(entry
);
269 remotes
.erase(backtrace_entry
->ino
);
271 derr
<< "Invalid type " << type
<< dendl
;
275 by_id
.erase(by_id_entry
);