From: Yan, Zheng Date: Fri, 20 Nov 2015 04:13:16 +0000 (+0800) Subject: mds: repair fragstat/rstat errors in dirfrag X-Git-Tag: v10.1.0~176^2~1^2~24 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=7760fc2bad9be57330d894d39eeaa2fda77bd82f;p=ceph.git mds: repair fragstat/rstat errors in dirfrag Signed-off-by: Yan, Zheng --- diff --git a/src/common/ceph_strings.cc b/src/common/ceph_strings.cc index 6f262e18d4c..fb5f2589b73 100644 --- a/src/common/ceph_strings.cc +++ b/src/common/ceph_strings.cc @@ -137,6 +137,7 @@ const char *ceph_mds_op_name(int op) case CEPH_MDS_OP_EXPORTDIR: return "exportdir"; case CEPH_MDS_OP_VALIDATE: return "validate_path"; case CEPH_MDS_OP_FLUSH: return "flush_path"; + case CEPH_MDS_OP_REPAIR_FRAGSTATS: return "repair_fragstats"; } return "???"; } diff --git a/src/include/ceph_fs.h b/src/include/ceph_fs.h index 744c3ce8a57..455e656c183 100644 --- a/src/include/ceph_fs.h +++ b/src/include/ceph_fs.h @@ -355,7 +355,8 @@ enum { CEPH_MDS_OP_EXPORTDIR = 0x01501, CEPH_MDS_OP_VALIDATE = 0x01502, CEPH_MDS_OP_FLUSH = 0x01503, - CEPH_MDS_OP_ENQUEUE_SCRUB = 0x01504 + CEPH_MDS_OP_ENQUEUE_SCRUB = 0x01504, + CEPH_MDS_OP_REPAIR_FRAGSTATS = 0x01505 }; extern const char *ceph_mds_op_name(int op); diff --git a/src/mds/CDir.cc b/src/mds/CDir.cc index 7cb38be4771..37c592c40c9 100644 --- a/src/mds/CDir.cc +++ b/src/mds/CDir.cc @@ -3089,6 +3089,8 @@ bool CDir::scrub_local() scrub_infop->last_local.time = ceph_clock_now(g_ceph_context); scrub_infop->last_local.version = get_projected_version(); scrub_infop->last_scrub_dirty = true; + } else { + cache->repair_dirfrag_stats(this, NULL); } return rval; } diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc index 6c5d1e3cbd5..c821966ecd9 100644 --- a/src/mds/MDCache.cc +++ b/src/mds/MDCache.cc @@ -8851,6 +8851,9 @@ void MDCache::dispatch_request(MDRequestRef& mdr) case CEPH_MDS_OP_FLUSH: flush_dentry_work(mdr); break; + case CEPH_MDS_OP_REPAIR_FRAGSTATS: + repair_dirfrag_stats_work(mdr); + break; default: assert(0); } @@ -11831,7 +11834,121 @@ void MDCache::enqueue_scrub_work(MDRequestRef& mdr) return; } +struct C_MDC_RepairDirfragStats : public MDSInternalContext { + MDRequestRef mdr; + C_MDC_RepairDirfragStats(MDSRank *_mds, MDRequestRef& m) : + MDSInternalContext(_mds), mdr(m) {} + void finish(int r) { + mdr->apply(); + mds->server->respond_to_request(mdr, r); + } +}; + +void MDCache::repair_dirfrag_stats(CDir *dir, Context *fin) +{ + if (!fin) + fin = new C_MDSInternalNoop; + MDRequestRef mdr = request_start_internal(CEPH_MDS_OP_REPAIR_FRAGSTATS); + mdr->pin(dir); + mdr->internal_op_private = dir; + mdr->internal_op_finish = fin; + repair_dirfrag_stats_work(mdr); +} + +void MDCache::repair_dirfrag_stats_work(MDRequestRef& mdr) +{ + CDir *dir = static_cast(mdr->internal_op_private); + dout(10) << __func__ << " " << *dir << dendl; + + if (!dir->is_auth()) { + mds->server->respond_to_request(mdr, -ESTALE); + return; + } + if (!mdr->is_auth_pinned(dir) && !dir->can_auth_pin()) { + mds->locker->drop_locks(mdr.get()); + mdr->drop_local_auth_pins(); + dir->add_waiter(CDir::WAIT_UNFREEZE, new C_MDS_RetryRequest(this, mdr)); + return; + } + + mdr->auth_pin(dir); + + set rdlocks, wrlocks, xlocks; + CInode *diri = dir->inode; + rdlocks.insert(&diri->dirfragtreelock); + wrlocks.insert(&diri->nestlock); + wrlocks.insert(&diri->filelock); + if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks)) + return; + + if (!dir->is_complete()) { + dir->fetch(new C_MDS_RetryRequest(this, mdr)); + return; + } + + frag_info_t frag_info; + nest_info_t nest_info; + for (CDir::map_t::iterator it = dir->begin(); it != dir->end(); ++it) { + CDentry *dn = it->second; + if (dn->last != CEPH_NOSNAP) + continue; + CDentry::linkage_t *dnl = dn->get_projected_linkage(); + if (dnl->is_primary()) { + CInode *in = dnl->get_inode(); + nest_info.add(in->get_projected_inode()->accounted_rstat); + if (in->is_dir()) + frag_info.nsubdirs++; + else + frag_info.nfiles++; + } else if (dnl->is_remote()) + frag_info.nfiles++; + } + + fnode_t *pf = dir->get_projected_fnode(); + bool bad_fragstat = false, bad_rstat = false; + if (frag_info.nfiles != pf->fragstat.nfiles || + frag_info.nsubdirs != pf->fragstat.nsubdirs) + bad_fragstat = true; + if (nest_info.rfiles != pf->rstat.rfiles || + nest_info.rsubdirs != pf->rstat.rsubdirs || + nest_info.rbytes != pf->rstat.rbytes) + bad_rstat = true; + + if (!bad_fragstat || !bad_rstat) { + dout(10) << __func__ << " no corruption found" << dendl; + mds->server->respond_to_request(mdr, 0); + return; + } + + pf = dir->project_fnode(); + pf->version = dir->pre_dirty(); + mdr->add_projected_fnode(dir); + + mdr->ls = mds->mdlog->get_current_segment(); + EUpdate *le = new EUpdate(mds->mdlog, "repair_dirfrag"); + mds->mdlog->start_entry(le); + + if (bad_fragstat) { + pf->fragstat.nfiles = frag_info.nfiles; + pf->fragstat.nsubdirs = frag_info.nsubdirs; + mds->locker->mark_updated_scatterlock(&diri->filelock); + mdr->ls->dirty_dirfrag_dir.push_back(&diri->item_dirty_dirfrag_dir); + mdr->add_updated_lock(&diri->filelock); + } + + if (bad_rstat) { + pf->rstat = nest_info; + mds->locker->mark_updated_scatterlock(&diri->nestlock); + mdr->ls->dirty_dirfrag_nest.push_back(&diri->item_dirty_dirfrag_nest); + mdr->add_updated_lock(&diri->nestlock); + } + + le->metablob.add_dir_context(dir); + le->metablob.add_dir(dir, true); + + mds->mdlog->submit_entry(le, new C_MDC_RepairDirfragStats(mds, mdr)); +} void MDCache::flush_dentry(const string& path, Context *fin) { diff --git a/src/mds/MDCache.h b/src/mds/MDCache.h index 36ec842be7c..999876ee6a1 100644 --- a/src/mds/MDCache.h +++ b/src/mds/MDCache.h @@ -1129,21 +1129,12 @@ public: return p->second; } - void scrub_dentry(const string& path, Formatter *f, Context *fin); +protected: /** * Scrub the named dentry only (skip the scrubstack) */ void scrub_dentry_work(MDRequestRef& mdr); - - void flush_dentry(const string& path, Context *fin); void flush_dentry_work(MDRequestRef& mdr); - - /** - * Create and start an OP_ENQUEUE_SCRUB - */ - void enqueue_scrub(const string& path, const std::string &tag, - Formatter *f, Context *fin); - /** * Resolve path to a dentry and pass it onto the ScrubStack. * @@ -1153,6 +1144,17 @@ public: * long time) */ void enqueue_scrub_work(MDRequestRef& mdr); + void repair_dirfrag_stats_work(MDRequestRef& mdr); + friend class C_MDC_RepairDirfragStats; +public: + void scrub_dentry(const string& path, Formatter *f, Context *fin); + void flush_dentry(const string& path, Context *fin); + /** + * Create and start an OP_ENQUEUE_SCRUB + */ + void enqueue_scrub(const string& path, const std::string &tag, + Formatter *f, Context *fin); + void repair_dirfrag_stats(CDir *dir, Context *fin); }; class C_MDS_RetryRequest : public MDSInternalContext {