break;
}
if (all) {
- clog->error() << "unmatched fragstat on " << ino() << ", inode has "
- << pi->dirstat << ", dirfrags have " << dirstat << "\n";
- assert(!"unmatched fragstat" == g_conf->mds_verify_scatter);
+ if (state_test(CInode::STATE_REPAIRSTATS)) {
+ dout(20) << " dirstat mismatch, fixing" << dendl;
+ } else {
+ clog->error() << "unmatched fragstat on " << ino() << ", inode has "
+ << pi->dirstat << ", dirfrags have " << dirstat << "\n";
+ assert(!"unmatched fragstat" == g_conf->mds_verify_scatter);
+ }
// trust the dirfrags for now
version_t v = pi->dirstat.version;
pi->dirstat = dirstat;
break;
}
if (all) {
- clog->error() << "unmatched rstat on " << ino() << ", inode has "
- << pi->rstat << ", dirfrags have " << rstat << "\n";
- assert(!"unmatched rstat" == g_conf->mds_verify_scatter);
+ if (state_test(CInode::STATE_REPAIRSTATS)) {
+ dout(20) << " rstat mismatch, fixinga" << dendl;
+ } else {
+ clog->error() << "unmatched rstat on " << ino() << ", inode has "
+ << pi->rstat << ", dirfrags have " << rstat << "\n";
+ assert(!"unmatched rstat" == g_conf->mds_verify_scatter);
+ }
// trust the dirfrag for now
version_t v = pi->rstat.version;
pi->rstat = rstat;
!nest_info.same_sums(in->inode.rstat)) {
results->raw_stats.error_str
<< "freshly-calculated rstats don't match existing ones";
+ in->mdcache->repair_inode_stats(in, NULL);
return true;
}
results->raw_stats.passed = true;
case CEPH_MDS_OP_REPAIR_FRAGSTATS:
repair_dirfrag_stats_work(mdr);
break;
+ case CEPH_MDS_OP_REPAIR_INODESTATS:
+ repair_inode_stats_work(mdr);
+ break;
default:
assert(0);
}
mds->mdlog->submit_entry(le, new C_MDC_RepairDirfragStats(mds, mdr));
}
+void MDCache::repair_inode_stats(CInode *diri, Context *fin)
+{
+ if (!fin)
+ fin = new C_MDSInternalNoop;
+ MDRequestRef mdr = request_start_internal(CEPH_MDS_OP_REPAIR_INODESTATS);
+ mdr->pin(diri);
+ mdr->internal_op_private = diri;
+ mdr->internal_op_finish = fin;
+ repair_inode_stats_work(mdr);
+}
+
+void MDCache::repair_inode_stats_work(MDRequestRef& mdr)
+{
+ CInode *diri = static_cast<CInode*>(mdr->internal_op_private);
+ dout(10) << __func__ << " " << *diri << dendl;
+
+ if (!diri->is_auth()) {
+ mds->server->respond_to_request(mdr, -ESTALE);
+ return;
+ }
+ if (!diri->is_dir()) {
+ mds->server->respond_to_request(mdr, -ENOTDIR);
+ return;
+ }
+
+ set<SimpleLock*> rdlocks, wrlocks, xlocks;
+ std::list<frag_t> frags;
+
+ if (mdr->ls) // already marked filelock/nestlock dirty ?
+ goto do_rdlocks;
+
+ rdlocks.insert(&diri->dirfragtreelock);
+ wrlocks.insert(&diri->nestlock);
+ wrlocks.insert(&diri->filelock);
+ if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks))
+ return;
+
+ // Fetch all dirfrags and mark filelock/nestlock dirty. This will tirgger
+ // the scatter-gather process, which will fix any fragstat/rstat errors.
+ diri->dirfragtree.get_leaves(frags);
+ for (list<frag_t>::iterator p = frags.begin(); p != frags.end(); ++p) {
+ CDir *dir = diri->get_dirfrag(*p);
+ if (!dir) {
+ assert(mdr->is_auth_pinned(diri));
+ dir = diri->get_or_open_dirfrag(this, *p);
+ }
+ if (dir->get_version() == 0) {
+ assert(dir->is_auth());
+ dir->fetch(new C_MDS_RetryRequest(this, mdr));
+ return;
+ }
+ }
+
+ diri->state_set(CInode::STATE_REPAIRSTATS);
+ mdr->ls = mds->mdlog->get_current_segment();
+ mds->locker->mark_updated_scatterlock(&diri->filelock);
+ mdr->ls->dirty_dirfrag_dir.push_back(&diri->item_dirty_dirfrag_dir);
+ mds->locker->mark_updated_scatterlock(&diri->nestlock);
+ mdr->ls->dirty_dirfrag_nest.push_back(&diri->item_dirty_dirfrag_nest);
+
+ mds->locker->drop_locks(mdr.get());
+
+do_rdlocks:
+ // force the scatter-gather process
+ rdlocks.insert(&diri->dirfragtreelock);
+ rdlocks.insert(&diri->nestlock);
+ rdlocks.insert(&diri->filelock);
+ wrlocks.clear();
+ if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks))
+ return;
+
+ diri->state_clear(CInode::STATE_REPAIRSTATS);
+
+ frag_info_t dir_info;
+ nest_info_t nest_info;
+ nest_info.rsubdirs++; // it gets one to account for self
+
+ diri->dirfragtree.get_leaves(frags);
+ for (list<frag_t>::iterator p = frags.begin(); p != frags.end(); ++p) {
+ CDir *dir = diri->get_dirfrag(*p);
+ assert(dir);
+ assert(dir->get_version() > 0);
+ dir_info.add(dir->fnode.accounted_fragstat);
+ nest_info.add(dir->fnode.accounted_rstat);
+ }
+
+ if (!dir_info.same_sums(diri->inode.dirstat) ||
+ !nest_info.same_sums(diri->inode.rstat)) {
+ dout(10) << __func__ << " failed to fix fragstat/rstat on "
+ << *diri << dendl;
+ }
+
+ mds->server->respond_to_request(mdr, 0);
+}
+
void MDCache::flush_dentry(const string& path, Context *fin)
{
if (is_readonly()) {