]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: verify backtrace when fetching dirfrag
authorYan, Zheng <zyan@redhat.com>
Tue, 21 Oct 2014 18:02:21 +0000 (18:02 +0000)
committerYan, Zheng <zyan@redhat.com>
Thu, 20 Nov 2014 06:53:22 +0000 (14:53 +0800)
Fixes: #9557
Signed-off-by: Yan, Zheng <zyan@redhat.com>
src/common/config_opts.h
src/mds/CDir.cc
src/mds/CInode.cc
src/mds/CInode.h

index 9060d8eb1a1fe49880eece46f0753407483ab841..f70ea2940fd27bb0b8ed516a3b1a437c05d9e2e5 100644 (file)
@@ -404,6 +404,7 @@ OPTION(mds_op_complaint_time, OPT_FLOAT, 30) // how many seconds old makes an op
 OPTION(mds_op_log_threshold, OPT_INT, 5) // how many op log messages to show in one go
 OPTION(mds_snap_min_uid, OPT_U32, 0) // The minimum UID required to create a snapshot
 OPTION(mds_snap_max_uid, OPT_U32, 65536) // The maximum UID allowed to create a snapshot
+OPTION(mds_verify_backtrace, OPT_U32, 1)
 
 // If true, compact leveldb store on mount
 OPTION(osd_compact_leveldb_on_mount, OPT_BOOL, false)
index 7c07c8d9db9c0b2b3357be140b80f6b14c350d08..ec270769dbed6fb1b19ec0042b7143768f1cceef 100644 (file)
@@ -1427,10 +1427,14 @@ class C_IO_Dir_OMAP_Fetched : public CDirIOContext {
  public:
   bufferlist hdrbl;
   map<string, bufferlist> omap;
-  int ret1, ret2;
+  bufferlist btbl;
+  int ret1, ret2, ret3;
 
   C_IO_Dir_OMAP_Fetched(CDir *d, const string& w) : CDirIOContext(d), want_dn(w) { }
   void finish(int r) {
+    // check the correctness of backtrace
+    if (r >= 0 && ret3 != -ECANCELED)
+      dir->inode->verify_diri_backtrace(btbl, ret3);
     if (r >= 0) r = ret1;
     if (r >= 0) r = ret2;
     dir->_omap_fetched(hdrbl, omap, want_dn, r);
@@ -1445,6 +1449,14 @@ void CDir::_omap_fetch(const string& want_dn)
   ObjectOperation rd;
   rd.omap_get_header(&fin->hdrbl, &fin->ret1);
   rd.omap_get_vals("", "", (uint64_t)-1, &fin->omap, &fin->ret2);
+  // check the correctness of backtrace
+  if (g_conf->mds_verify_backtrace > 0 && frag == frag_t()) {
+    rd.getxattr("parent", &fin->btbl, &fin->ret3);
+    rd.set_last_op_flags(CEPH_OSD_OP_FLAG_FAILOK);
+  } else {
+    fin->ret3 = -ECANCELED;
+  }
+
   cache->mds->objecter->read(oid, oloc, rd, CEPH_NOSNAP, NULL, 0,
                             new C_OnFinisher(fin, &cache->mds->finisher));
 }
index 5b3e94f2556471ef36497903b4237a38ee76633f..d84ef5f9e2f4ce7049d6642840909df11de0504d 100644 (file)
@@ -1177,6 +1177,33 @@ void CInode::clear_dirty_parent()
   }
 }
 
+void CInode::verify_diri_backtrace(bufferlist &bl, int err)
+{
+  if (is_base() || is_dirty_parent())
+    return;
+
+  dout(10) << "verify_diri_backtrace" << dendl;
+
+  if (err == 0) {
+    inode_backtrace_t backtrace;
+    ::decode(backtrace, bl);
+    CDentry *pdn = get_parent_dn();
+    if (backtrace.ancestors.empty() ||
+       backtrace.ancestors[0].dname != pdn->name ||
+       backtrace.ancestors[0].dirino != pdn->get_dir()->ino())
+      err = -EINVAL;
+  }
+
+  if (err) {
+    MDS *mds = mdcache->mds;
+    mds->clog->error() << "bad backtrace on dir ino " << ino() << "\n";
+    assert(!"bad backtrace" == (g_conf->mds_verify_backtrace > 1));
+
+    _mark_dirty_parent(mds->mdlog->get_current_segment(), false);
+    mds->mdlog->flush();
+  }
+}
+
 // ------------------
 // parent dir
 
index 2e520d26c5a22190c89135dc9419dcbb6e63292c..b2ed8cff19d489e4ad163821391e900e48882e35 100644 (file)
@@ -563,6 +563,7 @@ public:
   void fetch_backtrace(Context *fin, bufferlist *backtrace);
   void _mark_dirty_parent(LogSegment *ls, bool dirty_pool=false);
   void clear_dirty_parent();
+  void verify_diri_backtrace(bufferlist &bl, int err);
   bool is_dirty_parent() { return state_test(STATE_DIRTYPARENT); }
   bool is_dirty_pool() { return state_test(STATE_DIRTYPOOL); }