]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: handle MDirUpdate race
authorYan, Zheng <zyan@redhat.com>
Mon, 19 Jun 2017 08:28:41 +0000 (16:28 +0800)
committerJohn Spray <john.spray@redhat.com>
Fri, 23 Jun 2017 16:07:33 +0000 (17:07 +0100)
mds may try discover several times for MDirUpdate, rename may kick
in and cause MDCache::path_traverse() to return error.

Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
src/mds/MDCache.cc
src/messages/MDirUpdate.h

index ebecf6583110c10c03134d34c249d1c6c7e57e75..8ed3a7200208154870b5f2af6a61deadf76b1e93 100644 (file)
@@ -10302,15 +10302,16 @@ int MDCache::send_dir_updates(CDir *dir, bool bcast)
 /* This function DOES put the passed message before returning */
 void MDCache::handle_dir_update(MDirUpdate *m)
 {
-  CDir *dir = get_dirfrag(m->get_dirfrag());
+  dirfrag_t df = m->get_dirfrag();
+  CDir *dir = get_dirfrag(df);
   if (!dir) {
-    dout(5) << "dir_update on " << m->get_dirfrag() << ", don't have it" << dendl;
+    dout(5) << "dir_update on " << df << ", don't have it" << dendl;
 
     // discover it?
     if (m->should_discover()) {
       // only try once! 
       // this is key to avoid a fragtree update race, among other things.
-      m->tried_discover();        
+      m->inc_tried_discover();
       vector<CDentry*> trace;
       CInode *in;
       filepath path = m->get_path();
@@ -10319,21 +10320,25 @@ void MDCache::handle_dir_update(MDirUpdate *m)
       int r = path_traverse(null_ref, m, NULL, path, &trace, &in, MDS_TRAVERSE_DISCOVER);
       if (r > 0)
         return;
-      assert(r == 0);
-      open_remote_dirfrag(in, m->get_dirfrag().frag, 
-                         new C_MDS_RetryMessage(mds, m));
-      return;
+      if (r == 0 &&
+         in->ino() == df.ino &&
+         in->get_approx_dirfrag(df.frag) == NULL) {
+       open_remote_dirfrag(in, df.frag, new C_MDS_RetryMessage(mds, m));
+       return;
+      }
     }
 
     m->put();
     return;
   }
 
-  // update
-  dout(5) << "dir_update on " << *dir << dendl;
-  dir->dir_rep = m->get_dir_rep();
-  dir->dir_rep_by = m->get_dir_rep_by();
-  
+  if (!m->has_tried_discover()) {
+    // Update if it already exists. Othwerwise it got updated by discover reply.
+    dout(5) << "dir_update on " << *dir << dendl;
+    dir->dir_rep = m->get_dir_rep();
+    dir->dir_rep_by = m->get_dir_rep_by();
+  }
+
   // done
   m->put();
 }
index e282b04d386d0dc19b95e7b7682ce7aea85838d9..5752d34c68f744f29948a111532905fbe583e9ae 100644 (file)
@@ -25,33 +25,32 @@ class MDirUpdate : public Message {
   int32_t discover;
   compact_set<int32_t> dir_rep_by;
   filepath path;
+  int tried_discover;
 
  public:
   mds_rank_t get_source_mds() const { return from_mds; }
   dirfrag_t get_dirfrag() const { return dirfrag; }
   int get_dir_rep() const { return dir_rep; }
   const compact_set<int>& get_dir_rep_by() const { return dir_rep_by; }
-  bool should_discover() const { return discover > 0; }
+  bool should_discover() const { return discover > tried_discover; }
   const filepath& get_path() const { return path; }
 
-  void tried_discover() {
-    if (discover) discover--;
-  }
+  bool has_tried_discover() const { return tried_discover > 0; }
+  void inc_tried_discover() { ++tried_discover; }
 
-  MDirUpdate() : Message(MSG_MDS_DIRUPDATE) {}
+  MDirUpdate() : Message(MSG_MDS_DIRUPDATE), tried_discover(0) {}
   MDirUpdate(mds_rank_t f, 
             dirfrag_t dirfrag,
              int dir_rep,
              compact_set<int>& dir_rep_by,
              filepath& path,
              bool discover = false) :
-    Message(MSG_MDS_DIRUPDATE) {
+    Message(MSG_MDS_DIRUPDATE), tried_discover(0) {
     this->from_mds = f;
     this->dirfrag = dirfrag;
     this->dir_rep = dir_rep;
     this->dir_rep_by = dir_rep_by;
-    if (discover) this->discover = 5;
-    else this->discover = 0;
+    this->discover = discover ? 5 : 0;
     this->path = path;
   }
 private: