]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: handle no flushsnap
authorSage Weil <sage@newdream.net>
Tue, 17 Aug 2010 23:38:20 +0000 (16:38 -0700)
committerSage Weil <sage@newdream.net>
Tue, 17 Aug 2010 23:38:20 +0000 (16:38 -0700)
We won't get a flushsnap when the client has EXCL/WR caps but no dirty
data.  The MDS needs to release the snapped inode's locks when it gets a
normal update but no FLUSHSNAP.

src/mds/CInode.cc
src/mds/CInode.h
src/mds/Locker.cc
src/mds/MDCache.cc

index 206c7bca4b310643b32ca3984a0cd29f872c05d8..f5ea2e43fc0e64ecf677f5be7de38794b14357ad 100644 (file)
@@ -144,6 +144,10 @@ ostream& operator<<(ostream& out, CInode& in)
   if (!(in.inode.rstat == in.inode.accounted_rstat))
     out << "/" << in.inode.accounted_rstat;
 
+  if (!in.client_need_snapflush.empty())
+    out << " needsnapflush=" << in.client_need_snapflush;
+
+
   // locks
   out << " " << in.authlock;
   out << " " << in.linklock;
index 202c8cf95ae86f92ebb97f2a6331e82ef914d398..bfef15713135259ad9decf096d0edf58ed226109 100644 (file)
@@ -98,6 +98,7 @@ public:
   static const int PIN_OPENINGSNAPPARENTS = 17;
   static const int PIN_TRUNCATING =       18;
   static const int PIN_STRAY =            19;  // we pin our stray inode while active
+  static const int PIN_NEEDSNAPFLUSH =    20;
 
   const char *pin_name(int p) {
     switch (p) {
@@ -119,6 +120,7 @@ public:
     case PIN_OPENINGSNAPPARENTS: return "openingsnapparents";
     case PIN_TRUNCATING: return "truncating";
     case PIN_STRAY: return "stray";
+    case PIN_NEEDSNAPFLUSH: return "needsnapflush";
     default: return generic_pin_name(p);
     }
   }
@@ -280,6 +282,9 @@ protected:
   utime_t               replica_caps_wanted_keep_until;
 
   map<int, set<client_t> > client_snap_caps;     // [auth] [snap] dirty metadata we still need from the head
+public:
+  map<snapid_t, set<client_t> > client_need_snapflush;
+protected:
 
   ceph_lock_state_t fcntl_locks;
   ceph_lock_state_t flock_locks;
index f7a005c95e53193b10a7e433e566ae09783924b9..9ff496e4ed8fa0f457d4aeb641fff1c50756e610 100644 (file)
@@ -1114,7 +1114,7 @@ void Locker::file_update_finish(CInode *in, Mutation *mut, bool share, client_t
   mut->cleanup();
   delete mut;
 
-  if (!in->is_head()) {
+  if (!in->is_head() && in->client_snap_caps.size()) {
     dout(10) << " client_snap_caps " << in->client_snap_caps << dendl;
     // check for snap writeback completion
     bool gather = false;
@@ -1125,6 +1125,7 @@ void Locker::file_update_finish(CInode *in, Mutation *mut, bool share, client_t
       dout(10) << " completing client_snap_caps for " << ccap_string(p->first)
               << " lock " << *lock << " on " << *in << dendl;
       lock->put_wrlock();
+
       p->second.erase(client);
       if (p->second.empty()) {
        gather = true;
@@ -1796,7 +1797,14 @@ void Locker::handle_client_caps(MClientCaps *m)
 
   // flushsnap?
   if (op == CEPH_CAP_OP_FLUSHSNAP) {
-    if (in->is_auth()) {
+    if (!in->is_auth()) {
+      dout(7) << " not auth, ignoring flushsnap on " << *in << dendl;
+      goto out;
+    }
+
+    if (in == head_in ||
+       (head_in->client_need_snapflush.count(in->last) &&
+        head_in->client_need_snapflush[in->last].count(client))) {
       dout(7) << " flushsnap follows " << follows
              << " client" << client << " on " << *in << dendl;
       // this cap now follows a later snap (i.e. the one initiating this flush, or later)
@@ -1813,8 +1821,18 @@ void Locker::handle_client_caps(MClientCaps *m)
       }
 
       _do_snap_update(in, m->get_dirty(), follows, m, ack);
+
+      if (in != head_in) {
+       head_in->client_need_snapflush[in->last].erase(client);
+       if (head_in->client_need_snapflush[in->last].empty()) {
+         head_in->client_need_snapflush.erase(in->last);
+         if (head_in->client_need_snapflush.empty())
+           head_in->put(CInode::PIN_NEEDSNAPFLUSH);
+       }
+      }
+      
     } else
-      dout(7) << " not auth, ignoring flushsnap on " << *in << dendl;
+      dout(7) << " not expecting flushsnap from client" << client << " on " << *in << dendl;
     goto out;
   }
 
@@ -1830,7 +1848,7 @@ void Locker::handle_client_caps(MClientCaps *m)
       }
       in = mdcache->pick_inode_snap(in, in->last);
     }
-    
     // head inode, and cap
     MClientCaps *ack = 0;
     
@@ -1839,6 +1857,38 @@ void Locker::handle_client_caps(MClientCaps *m)
             << " retains " << ccap_string(m->get_caps())
             << " dirty " << ccap_string(m->get_caps())
             << " on " << *in << dendl;
+
+
+    // missing/skipped snapflush?
+    //  ** only if the client has completed all revocations.  if we
+    //     are still revoking, it's possible the client is waiting for
+    //     data writeback and hasn't sent the flushsnap yet.  **
+    if (head_in->client_need_snapflush.size()) {
+      if ((cap->pending() & ~cap->issued()) == 0) {
+       map<snapid_t, set<client_t> >::iterator p = head_in->client_need_snapflush.begin();
+       while (p != head_in->client_need_snapflush.end()) {
+         // p->first is the snap inode's ->last
+         if (follows > p->first)
+           break;
+         if (p->second.count(client)) {
+           dout(10) << " doing async NULL snapflush on " << p->first << " from client" << p->second << dendl;
+           CInode *sin = mdcache->pick_inode_snap(head_in, p->first - 1);
+           assert(sin != head_in);
+           _do_snap_update(sin, 0, sin->first - 1, m, NULL);
+           head_in->client_need_snapflush[in->last].erase(client);
+           if (head_in->client_need_snapflush[in->last].empty()) {
+             head_in->client_need_snapflush.erase(p++);
+             if (head_in->client_need_snapflush.empty())
+               head_in->put(CInode::PIN_NEEDSNAPFLUSH);
+             continue;
+           }
+         }
+         p++;
+       }
+      } else {
+       dout(10) << " revocation in progress, not making any conclusions about null snapflushes" << dendl;
+      }
+    }
     
     if (m->get_dirty() && in->is_auth()) {
       dout(7) << " flush client" << client << " dirty " << ccap_string(m->get_dirty()) 
index 3aa0b82a683b1437458f0a9fc8c5bad9a078a845..5c75be7a2b0d7abf54183abf8d4c200dca7b8437 100644 (file)
@@ -1291,6 +1291,9 @@ CInode *MDCache::cow_inode(CInode *in, snapid_t last)
        }
       }
       cap->client_follows = last;
+      if (in->client_need_snapflush.empty())
+       in->get(CInode::PIN_NEEDSNAPFLUSH);
+      in->client_need_snapflush[last].insert(client);
     } else {
       dout(10) << " ignoring client" << client << " cap follows " << cap->client_follows << dendl;
     }