Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / mds / DamageTable.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7  *
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.
12  *
13  */
14
15 #include "common/debug.h"
16
17 #include "mds/CDir.h"
18
19 #include "DamageTable.h"
20
21 #define dout_context g_ceph_context
22 #define dout_subsys ceph_subsys_mds
23 #undef dout_prefix
24 #define dout_prefix *_dout << "mds." << rank << ".damage " << __func__ << " "
25
26 namespace {
27 /**
28  * Record damage to a particular dirfrag, implicitly affecting
29  * any dentries within it.
30  */
31 class DirFragDamage : public DamageEntry
32 {
33   public:
34   inodeno_t ino;
35   frag_t frag;
36
37   DirFragDamage(inodeno_t ino_, frag_t frag_)
38     : ino(ino_), frag(frag_)
39   {}
40
41   damage_entry_type_t get_type() const override
42   {
43     return DAMAGE_ENTRY_DIRFRAG;
44   }
45
46   void dump(Formatter *f) const override
47   {
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);
54     f->close_section();
55   }
56 };
57
58
59 /**
60  * Record damage to a particular dname within a particular dirfrag
61  */
62 class DentryDamage : public DamageEntry
63 {
64   public:
65   inodeno_t ino;
66   frag_t frag;
67   std::string dname;
68   snapid_t snap_id;
69
70   DentryDamage(
71       inodeno_t ino_,
72       frag_t frag_,
73       std::string dname_,
74       snapid_t snap_id_)
75     : ino(ino_), frag(frag_), dname(dname_), snap_id(snap_id_)
76   {}
77
78   damage_entry_type_t get_type() const override
79   {
80     return DAMAGE_ENTRY_DENTRY;
81   }
82
83   void dump(Formatter *f) const override
84   {
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);
93     f->close_section();
94   }
95 };
96
97
98 /**
99  * Record damage to our ability to look up an ino by number
100  */
101 class BacktraceDamage : public DamageEntry
102 {
103   public:
104   inodeno_t ino;
105
106   BacktraceDamage(inodeno_t ino_)
107     : ino(ino_)
108   {}
109
110   damage_entry_type_t get_type() const override
111   {
112     return DAMAGE_ENTRY_BACKTRACE;
113   }
114
115   void dump(Formatter *f) const override
116   {
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);
122     f->close_section();
123   }
124 };
125 }
126
127 DamageEntry::~DamageEntry()
128 {}
129
130 bool DamageTable::notify_dentry(
131     inodeno_t ino, frag_t frag,
132     snapid_t snap_id, const std::string &dname, const std::string &path)
133 {
134   if (oversized()) {
135     return true;
136   }
137
138   // Special cases: damage to these dirfrags is considered fatal to
139   // the MDS rank that owns them.
140   if (
141       (MDS_INO_IS_MDSDIR(ino) && MDS_INO_MDSDIR_OWNER(ino) == rank)
142       ||
143       (MDS_INO_IS_STRAY(ino) && MDS_INO_STRAY_OWNER(ino) == rank)
144      ) {
145     derr << "Damage to dentries in fragment " << frag << " of ino " << ino
146          << "is fatal because it is a system directory for this rank" << dendl;
147     return true;
148   }
149
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);
154     entry->path = path;
155     dentries[key][DentryIdent(dname, snap_id)] = entry;
156     by_id[entry->id] = std::move(entry);
157   }
158
159   return false;
160 }
161
162 bool DamageTable::notify_dirfrag(inodeno_t ino, frag_t frag,
163                                  const std::string &path)
164 {
165   // Special cases: damage to these dirfrags is considered fatal to
166   // the MDS rank that owns them.
167   if (
168       (MDS_INO_IS_STRAY(ino) && MDS_INO_STRAY_OWNER(ino) == rank)
169       ||
170       (ino == MDS_INO_ROOT)
171      ) {
172     derr << "Damage to fragment " << frag << " of ino " << ino
173          << " is fatal because it is a system directory for this rank" << dendl;
174     return true;
175   }
176
177   if (oversized()) {
178     return true;
179   }
180
181   auto key = DirFragIdent(ino, frag);
182   if (dirfrags.count(key) == 0) {
183     DamageEntryRef entry = std::make_shared<DirFragDamage>(ino, frag);
184     entry->path = path;
185     dirfrags[key] = entry;
186     by_id[entry->id] = std::move(entry);
187   }
188
189   return false;
190 }
191
192 bool DamageTable::notify_remote_damaged(inodeno_t ino, const std::string &path)
193 {
194   if (oversized()) {
195     return true;
196   }
197
198   if (remotes.count(ino) == 0) {
199     auto entry = std::make_shared<BacktraceDamage>(ino);
200     entry->path = path;
201     remotes[ino] = entry;
202     by_id[entry->id] = std::move(entry);
203   }
204
205   return false;
206 }
207
208 bool DamageTable::oversized() const
209 {
210   return by_id.size() > (size_t)(g_conf->mds_damage_table_max_entries);
211 }
212
213 bool DamageTable::is_dentry_damaged(
214         const CDir *dir_frag,
215         const std::string &dname,
216         const snapid_t snap_id) const
217 {
218   if (dentries.count(
219         DirFragIdent(dir_frag->inode->ino(), dir_frag->frag)
220         ) == 0) {
221     return false;
222   }
223
224   const std::map<DentryIdent, DamageEntryRef> &frag_dentries =
225     dentries.at(DirFragIdent(dir_frag->inode->ino(), dir_frag->frag));
226
227   return frag_dentries.count(DentryIdent(dname, snap_id)) > 0;
228 }
229
230 bool DamageTable::is_dirfrag_damaged(
231     const CDir *dir_frag) const
232 {
233   return dirfrags.count(
234       DirFragIdent(dir_frag->inode->ino(), dir_frag->frag)) > 0;
235 }
236
237 bool DamageTable::is_remote_damaged(
238     const inodeno_t ino) const
239 {
240   return remotes.count(ino) > 0;
241 }
242
243 void DamageTable::dump(Formatter *f) const
244 {
245   f->open_array_section("damage_table");
246   for (const auto &i : by_id)
247   {
248     i.second->dump(f);
249   }
250   f->close_section();
251 }
252
253 void DamageTable::erase(damage_entry_id_t damage_id)
254 {
255   auto by_id_entry = by_id.find(damage_id);
256   if (by_id_entry == by_id.end()) {
257     return;
258   }
259
260   DamageEntryRef entry = by_id_entry->second;
261   assert(entry->id == damage_id);  // Sanity
262
263   const auto type = entry->get_type();
264   if (type == DAMAGE_ENTRY_DIRFRAG) {
265     auto dirfrag_entry = std::static_pointer_cast<DirFragDamage>(entry);
266     dirfrags.erase(DirFragIdent(dirfrag_entry->ino, dirfrag_entry->frag));
267   } else if (type == DAMAGE_ENTRY_DENTRY) {
268     auto dentry_entry = std::static_pointer_cast<DentryDamage>(entry);
269     dentries.erase(DirFragIdent(dentry_entry->ino, dentry_entry->frag));
270   } else if (type == DAMAGE_ENTRY_BACKTRACE) {
271     auto backtrace_entry = std::static_pointer_cast<BacktraceDamage>(entry);
272     remotes.erase(backtrace_entry->ino);
273   } else {
274     derr << "Invalid type " << type << dendl;
275     ceph_abort();
276   }
277
278   by_id.erase(by_id_entry);
279 }
280