From: Yan, Zheng Date: Tue, 21 Oct 2014 18:02:21 +0000 (+0000) Subject: mds: verify backtrace when fetching dirfrag X-Git-Tag: v0.90~34^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=a79ba32d2444c58c47bde1785d3d08138d87c5d4;p=ceph.git mds: verify backtrace when fetching dirfrag Fixes: #9557 Signed-off-by: Yan, Zheng --- diff --git a/src/common/config_opts.h b/src/common/config_opts.h index 9060d8eb1a1f..f70ea2940fd2 100644 --- a/src/common/config_opts.h +++ b/src/common/config_opts.h @@ -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) diff --git a/src/mds/CDir.cc b/src/mds/CDir.cc index 7c07c8d9db9c..ec270769dbed 100644 --- a/src/mds/CDir.cc +++ b/src/mds/CDir.cc @@ -1427,10 +1427,14 @@ class C_IO_Dir_OMAP_Fetched : public CDirIOContext { public: bufferlist hdrbl; map 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)); } diff --git a/src/mds/CInode.cc b/src/mds/CInode.cc index 5b3e94f25564..d84ef5f9e2f4 100644 --- a/src/mds/CInode.cc +++ b/src/mds/CInode.cc @@ -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 diff --git a/src/mds/CInode.h b/src/mds/CInode.h index 2e520d26c5a2..b2ed8cff19d4 100644 --- a/src/mds/CInode.h +++ b/src/mds/CInode.h @@ -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); }