]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: repair fragstat/rstat errors in inode
authorYan, Zheng <zyan@redhat.com>
Mon, 23 Nov 2015 13:57:24 +0000 (21:57 +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/CInode.cc
src/mds/CInode.h
src/mds/MDCache.cc
src/mds/MDCache.h

index fb5f2589b737c2885fcd523f9403166f0f2478d2..dab9ee159ebb1511016653c72b8c13ccc6bde652 100644 (file)
@@ -138,6 +138,7 @@ const char *ceph_mds_op_name(int op)
        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";
+       case CEPH_MDS_OP_REPAIR_INODESTATS: return "repair_inodestats";
        }
        return "???";
 }
index 455e656c183859396e68c6a64de40088b30b4d1d..5fab25961bca7523b839e2e2021dce1ae63c4ece 100644 (file)
@@ -356,7 +356,8 @@ enum {
        CEPH_MDS_OP_VALIDATE   = 0x01502,
        CEPH_MDS_OP_FLUSH      = 0x01503,
        CEPH_MDS_OP_ENQUEUE_SCRUB  = 0x01504,
-       CEPH_MDS_OP_REPAIR_FRAGSTATS = 0x01505
+       CEPH_MDS_OP_REPAIR_FRAGSTATS = 0x01505,
+       CEPH_MDS_OP_REPAIR_INODESTATS = 0x01506
 };
 
 extern const char *ceph_mds_op_name(int op);
index ec59997dccdd7d52334012f82a27dfdda5a1973b..aa8ba19a6dd3c9baecb5bbae620dadbb2c57cd76 100644 (file)
@@ -2044,9 +2044,13 @@ void CInode::finish_scatter_gather_update(int type)
            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;
@@ -2139,9 +2143,13 @@ void CInode::finish_scatter_gather_update(int type)
            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;
@@ -3948,6 +3956,7 @@ void CInode::validate_disk_state(CInode::validated_data *results,
          !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;
index 4408973a8e9bffd569861c754e0142ce76f9a533..65dd35b0792dc997ab7976e0d464f26df27cf435 100644 (file)
@@ -214,6 +214,7 @@ public:
   static const int STATE_STRAYPINNED = (1<<16);
   static const int STATE_FROZENAUTHPIN = (1<<17);
   static const int STATE_DIRTYPOOL =   (1<<18);
+  static const int STATE_REPAIRSTATS = (1<<19);
   // orphan inode needs notification of releasing reference
   static const int STATE_ORPHAN =      STATE_NOTIFYREF;
 
index c821966ecd9fffed58ccadda14b790dc92c3f90e..0f6649b2b2af1d41d44eef64fc192cc2196d4048 100644 (file)
@@ -8854,6 +8854,9 @@ void MDCache::dispatch_request(MDRequestRef& mdr)
     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);
     }
@@ -11950,6 +11953,101 @@ void MDCache::repair_dirfrag_stats_work(MDRequestRef& mdr)
   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()) {
index 999876ee6a112375f708c4605b31ceb9edfbf295..5b29cd6df5a205a4abca1ef2af1465cc6aeb428c 100644 (file)
@@ -1144,6 +1144,7 @@ protected:
    * long time)
    */
   void enqueue_scrub_work(MDRequestRef& mdr);
+  void repair_inode_stats_work(MDRequestRef& mdr);
   void repair_dirfrag_stats_work(MDRequestRef& mdr);
   friend class C_MDC_RepairDirfragStats;
 public:
@@ -1154,6 +1155,7 @@ public:
    */
   void enqueue_scrub(const string& path, const std::string &tag,
                      Formatter *f, Context *fin);
+  void repair_inode_stats(CInode *diri, Context *fin);
   void repair_dirfrag_stats(CDir *dir, Context *fin);
 };