]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
osd: Add automatic repair for DBObjectMap bug
authorDavid Zafman <dzafman@redhat.com>
Wed, 15 Feb 2017 23:02:33 +0000 (15:02 -0800)
committerDavid Zafman <dzafman@redhat.com>
Tue, 28 Mar 2017 16:33:26 +0000 (09:33 -0700)
Add repair command to ceph-osdomap-tool too

Under some situations the previous rm_keys() code would
generated a corrupt complete table.  There is no way to
figure out what the table should look like now.  By removing
the entries we fix the corruption and aren't much worse off
because the corruption caused some deleted keys to re-appear.

This doesn't breaking the parent/child relationship during
repair because some of the keys may still be contained
in the parent.

Signed-off-by: David Zafman <dzafman@redhat.com>
(cherry picked from commit 4cd3c74c928a32e065ed9543d6c91d8718a6ae3d)

Conflicts:
src/os/filestore/DBObjectMap.h (trivial)

src/os/ObjectMap.h
src/os/filestore/DBObjectMap.cc
src/os/filestore/DBObjectMap.h
src/tools/ceph_osdomap_tool.cc

index a07142a09c48149e323ce779408a11135fe66953..961c3b24be9fc3f4e3fcbd026aae5682a6650a36 100644 (file)
@@ -137,7 +137,7 @@ public:
     const SequencerPosition *spos=0   ///< [in] Sequencer
     ) { return 0; }
 
-  virtual int check(std::ostream &out) { return 0; }
+  virtual int check(std::ostream &out, bool repair = false) { return 0; }
 
   typedef KeyValueDB::GenericIteratorImpl ObjectMapIteratorImpl;
   typedef ceph::shared_ptr<ObjectMapIteratorImpl> ObjectMapIterator;
index 96f2280491a63d225169751454218eb1772244ea..36105bb1778d7deaff289a076a74e8489a57c6db 100644 (file)
@@ -54,7 +54,7 @@ static void append_escaped(const string &in, string *out)
   }
 }
 
-int DBObjectMap::check(std::ostream &out)
+int DBObjectMap::check(std::ostream &out, bool repair)
 {
   int errors = 0;
   map<uint64_t, uint64_t> parent_to_num_children;
@@ -77,18 +77,25 @@ int DBObjectMap::check(std::ostream &out)
            complete_iter->next()) {
          if (prev && prev >= complete_iter->key()) {
              out << "Bad complete for " << header.oid << std::endl;
-             errors++;
              complete_error = true;
              break;
          }
          prev = string(complete_iter->value().c_str(), complete_iter->value().length() - 1);
       }
       if (complete_error) {
-        out << "Complete mapping:" << std::endl;
+        out << "Complete mapping for " << header.seq << " :" << std::endl;
         for (complete_iter->seek_to_first(); complete_iter->valid();
              complete_iter->next()) {
           out << complete_iter->key() << " -> " << string(complete_iter->value().c_str(), complete_iter->value().length() - 1) << std::endl;
         }
+        if (repair) {
+          KeyValueDB::Transaction t = db->get_transaction();
+          t->rmkeys_by_prefix(USER_PREFIX + header_key(header.seq) + COMPLETE_PREFIX);
+          db->submit_transaction(t);
+          out << "Cleared complete mapping to repair" << std::endl;
+        } else {
+          errors++;  // Only count when not repaired
+        }
       }
 
       if (header.parent == 0)
@@ -1049,6 +1056,12 @@ int DBObjectMap::init(bool do_upgrade)
     state.v = 2;
     state.seq = 1;
   }
+  ostringstream ss;
+  int errors = check(ss, true);
+  if (errors) {
+    dout(5) << ss.str() << dendl;
+    return -EINVAL;
+  }
   dout(20) << "(init)dbobjectmap: seq is " << state.seq << dendl;
   return 0;
 }
index af504b70cfa75ba80386545d908fe714c52f5772..0f2fd4ecbc75aca34d9d3bc9c9db15aee3599255 100644 (file)
@@ -212,7 +212,7 @@ public:
   int upgrade_to_v2();
 
   /// Consistency check, debug, there must be no parallel writes
-  int check(std::ostream &out);
+  int check(std::ostream &out, bool repair = false);
 
   /// Ensure that all previous operations are durable
   int sync(const ghobject_t *oid=0, const SequencerPosition *spos=0);
index b2f231641d5ffc7776cdab6ec2f6ed284ecb5dff..11d984e330522458d07db5fb3c1f9ec0cc2bf437 100644 (file)
@@ -37,7 +37,7 @@ int main(int argc, char **argv) {
     ("debug", "Additional debug output from DBObjectMap")
     ("oid", po::value<string>(&oid), "Restrict to this object id when dumping objects")
     ("command", po::value<string>(&cmd),
-     "command arg is one of [dump-raw-keys, dump-raw-key-vals, dump-objects, dump-objects-with-keys, check, dump-headers], mandatory")
+     "command arg is one of [dump-raw-keys, dump-raw-key-vals, dump-objects, dump-objects-with-keys, check, dump-headers, repair], mandatory")
     ;
   po::positional_options_description p;
   p.add("command", 1);
@@ -109,6 +109,9 @@ int main(int argc, char **argv) {
     std::cerr << "Output: " << out.str() << std::endl;
     goto done;
   }
+  // We don't call omap.init() here because it will repair
+  // the DBObjectMap which we might want to examine for diagnostic
+  // reasons.  Instead use --command repair.
   r = 0;
 
 
@@ -157,14 +160,15 @@ int main(int argc, char **argv) {
        j->value().hexdump(std::cout);
       }
     }
-  } else if (cmd == "check") {
-    r = omap.check(std::cout);
+  } else if (cmd == "check" || cmd == "repair") {
+    bool repair = (cmd == "repair");
+    r = omap.check(std::cout, repair);
     if (r > 0) {
       std::cerr << "check got " << r << " error(s)" << std::endl;
       r = 1;
       goto done;
     }
-    std::cout << "check succeeded" << std::endl;
+    std::cout << (repair ? "repair" : "check") << " succeeded" << std::endl;
   } else if (cmd == "dump-headers") {
     vector<DBObjectMap::_Header> headers;
     r = omap.list_object_headers(&headers);