]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: repair fragstat/rstat errors in dirfrag
authorYan, Zheng <zyan@redhat.com>
Fri, 20 Nov 2015 04:13:16 +0000 (12:13 +0800)
committerYan, Zheng <zyan@redhat.com>
Mon, 7 Mar 2016 07:59:12 +0000 (15:59 +0800)
Signed-off-by: Yan, Zheng <zyan@redhat.com>
src/common/ceph_strings.cc
src/include/ceph_fs.h
src/mds/CDir.cc
src/mds/MDCache.cc
src/mds/MDCache.h

index 6f262e18d4cff9ae37612952d1785b18a660899a..fb5f2589b737c2885fcd523f9403166f0f2478d2 100644 (file)
@@ -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 "???";
 }
index 744c3ce8a573068598031d53892146525c61a026..455e656c183859396e68c6a64de40088b30b4d1d 100644 (file)
@@ -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);
index 7cb38be4771b9d0032440a3fde126ea9b209f141..37c592c40c9f431c3d3bc2ee601301c8b0f470fe 100644 (file)
@@ -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;
 }
index 6c5d1e3cbd53147ea3dc346c9898d9ab314f1c3a..c821966ecd9fffed58ccadda14b790dc92c3f90e 100644 (file)
@@ -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<CDir*>(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<SimpleLock*> 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)
 {
index 36ec842be7c7e2f974d5c2f661aef50b2cab65b8..999876ee6a112375f708c4605b31ceb9edfbf295 100644 (file)
@@ -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 {