]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mds: properly setup need_snapflush for flushsnap messages
authorYan, Zheng <zyan@redhat.com>
Thu, 17 Aug 2017 06:28:16 +0000 (14:28 +0800)
committerYan, Zheng <zyan@redhat.com>
Tue, 5 Dec 2017 07:00:04 +0000 (15:00 +0800)
When processing a cap flush message that is re-sent, it's possble
that the sender has already released all WR caps. So can't rely on
CEPH_CAP_ANY_WR check in MDCache:cow_inode().

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

index 0aaeda5c203e5cc9748c5a93eb2fbe15aa269466..e3ada8411c43e798ad9f09745ed0a8f805ce8b14 100644 (file)
@@ -109,6 +109,7 @@ public:
   const static unsigned STATE_STALE            = (1<<0);
   const static unsigned STATE_NEW              = (1<<1);
   const static unsigned STATE_IMPORTING                = (1<<2);
+  const static unsigned STATE_NEEDSNAPFLUSH    = (1<<3);
 
 
   Capability(CInode *i = NULL, uint64_t id = 0, client_t c = 0) :
@@ -242,6 +243,9 @@ public:
   bool is_importing() { return state & STATE_IMPORTING; }
   void mark_importing() { state |= STATE_IMPORTING; }
   void clear_importing() { state &= ~STATE_IMPORTING; }
+  bool need_snapflush() { return state & STATE_NEEDSNAPFLUSH; }
+  void mark_needsnapflush() { state |= STATE_NEEDSNAPFLUSH; }
+  void clear_needsnapflush() { state &= ~STATE_NEEDSNAPFLUSH; }
 
   CInode *get_inode() { return inode; }
   client_t get_client() const { return client; }
index 388f6a58bcf43bfd6377226cef16954ef5fd4db3..7b214eadb6f90096416429de92c21a75967b4c2d 100644 (file)
@@ -2633,10 +2633,11 @@ void Locker::handle_client_caps(MClientCaps *m)
       m->put();
       return;
     }
-    if (mds->is_reconnect() &&
+    if ((mds->is_reconnect() || mds->get_want_state() == MDSMap::STATE_RECONNECT) &&
        m->get_dirty() && m->get_client_tid() > 0 &&
        !session->have_completed_flush(m->get_client_tid())) {
-      mdcache->set_reconnected_dirty_caps(client, m->get_ino(), m->get_dirty());
+      mdcache->set_reconnected_dirty_caps(client, m->get_ino(), m->get_dirty(),
+                                         m->get_op() == CEPH_CAP_OP_FLUSHSNAP);
     }
     mds->wait_for_replay(new C_MDS_RetryMessage(mds, m));
     return;
@@ -2850,6 +2851,8 @@ void Locker::handle_client_caps(MClientCaps *m)
        dout(10) << " revocation in progress, not making any conclusions about null snapflushes" << dendl;
       }
     }
+    if (cap->need_snapflush() && (m->flags & MClientCaps::FLAG_NO_CAPSNAP))
+      cap->clear_needsnapflush();
     
     if (m->get_dirty() && in->is_auth()) {
       dout(7) << " flush client." << client << " dirty " << ccap_string(m->get_dirty()) 
index a82485e0078f649d48006b20cb65cb34364967fe..dbb0dbc7f2e385898fa88a92868f225c46ca0376 100644 (file)
@@ -1531,7 +1531,7 @@ CInode *MDCache::cow_inode(CInode *in, snapid_t last)
     for (auto p : in->client_caps) {
       client_t client = p.first;
       Capability *cap = p.second;
-      int issued = cap->issued();
+      int issued = cap->need_snapflush() ? CEPH_CAP_ANY_WR : cap->issued();
       if ((issued & CEPH_CAP_ANY_WR) &&
          cap->client_follows < last) {
        // note in oldin
@@ -5782,8 +5782,17 @@ void MDCache::open_snap_parents()
        auto q = reconnected_caps.find(child->ino());
        assert(q != reconnected_caps.end());
        for (auto r = q->second.begin(); r != q->second.end(); ++r) {
-         if (r->second.snap_follows > 0 && r->second.snap_follows < in->first - 1) {
-           rebuild_need_snapflush(child, in->snaprealm, r->first, r->second.snap_follows);
+         if (r->second.snap_follows > 0) {
+           if (r->second.snap_follows < child->first - 1) {
+             rebuild_need_snapflush(child, in->snaprealm, r->first, r->second.snap_follows);
+           } else if (r->second.snapflush) {
+             // When processing a cap flush message that is re-sent, it's possble
+             // that the sender has already released all WR caps. So we should
+             // force MDCache::cow_inode() to setup CInode::client_need_snapflush.
+             Capability *cap = child->get_client_cap(r->first);
+             if (cap)
+               cap->mark_needsnapflush();
+           }
          }
          // make sure client's cap is in the correct snaprealm.
          if (r->second.realm_ino != in->ino()) {
index 8fd8472e378e8798de4d8d26c4a747ce15d7dd9b..8d5bda64834443b983f604afa8879086931726e9 100644 (file)
@@ -616,8 +616,9 @@ public:
     inodeno_t realm_ino;
     snapid_t snap_follows;
     int dirty_caps;
+    bool snapflush;
     reconnected_cap_info_t() :
-      realm_ino(0), snap_follows(0), dirty_caps(0) {}
+      realm_ino(0), snap_follows(0), dirty_caps(0), snapflush(false) {}
   };
   map<inodeno_t,map<client_t, reconnected_cap_info_t> >  reconnected_caps;   // inode -> client -> snap_follows,realmino
   map<inodeno_t,map<client_t, snapid_t> > reconnected_snaprealms;  // realmino -> client -> realmseq
@@ -627,9 +628,11 @@ public:
     info.realm_ino = inodeno_t(icr.capinfo.snaprealm);
     info.snap_follows = icr.snap_follows;
   }
-  void set_reconnected_dirty_caps(client_t client, inodeno_t ino, int dirty) {
+  void set_reconnected_dirty_caps(client_t client, inodeno_t ino, int dirty, bool snapflush) {
     reconnected_cap_info_t &info = reconnected_caps[ino][client];
     info.dirty_caps |= dirty;
+    if (snapflush)
+      info.snapflush = snapflush;
   }
   void add_reconnected_snaprealm(client_t client, inodeno_t ino, snapid_t seq) {
     reconnected_snaprealms[ino][client] = seq;