ceph: fix race between cap issue and revoke
authorYan, Zheng <zheng.z.yan@intel.com>
Tue, 2 Jul 2013 04:40:21 +0000 (12:40 +0800)
committerSage Weil <sage@inktank.com>
Wed, 3 Jul 2013 22:32:57 +0000 (15:32 -0700)
If we receive new caps from the auth MDS and the non-auth MDS is
revoking the newly issued caps, we should release the caps from
the non-auth MDS. The scenario is filelock's state changes from
SYNC to LOCK. Non-auth MDS revokes Fc cap, the client gets Fc cap
from the auth MDS at the same time.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
Reviewed-by: Sage Weil <sage@inktank.com>
fs/ceph/caps.c

index 7045a8dfaad402b7f08d17e63a8a6d87064ec763..25442b40c25a71761596e071612140f01279fb69 100644 (file)
@@ -806,22 +806,28 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch)
 /*
  * Return true if mask caps are currently being revoked by an MDS.
  */
-int ceph_caps_revoking(struct ceph_inode_info *ci, int mask)
+int __ceph_caps_revoking_other(struct ceph_inode_info *ci,
+                              struct ceph_cap *ocap, int mask)
 {
-       struct inode *inode = &ci->vfs_inode;
        struct ceph_cap *cap;
        struct rb_node *p;
-       int ret = 0;
 
-       spin_lock(&ci->i_ceph_lock);
        for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
                cap = rb_entry(p, struct ceph_cap, ci_node);
-               if (__cap_is_valid(cap) &&
-                   (cap->implemented & ~cap->issued & mask)) {
-                       ret = 1;
-                       break;
-               }
+               if (cap != ocap && __cap_is_valid(cap) &&
+                   (cap->implemented & ~cap->issued & mask))
+                       return 1;
        }
+       return 0;
+}
+
+int ceph_caps_revoking(struct ceph_inode_info *ci, int mask)
+{
+       struct inode *inode = &ci->vfs_inode;
+       int ret;
+
+       spin_lock(&ci->i_ceph_lock);
+       ret = __ceph_caps_revoking_other(ci, NULL, mask);
        spin_unlock(&ci->i_ceph_lock);
        dout("ceph_caps_revoking %p %s = %d\n", inode,
             ceph_cap_string(mask), ret);
@@ -2488,6 +2494,11 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
        } else {
                dout("grant: %s -> %s\n", ceph_cap_string(cap->issued),
                     ceph_cap_string(newcaps));
+               /* non-auth MDS is revoking the newly grant caps ? */
+               if (cap == ci->i_auth_cap &&
+                   __ceph_caps_revoking_other(ci, cap, newcaps))
+                   check_caps = 2;
+
                cap->issued = newcaps;
                cap->implemented |= newcaps; /* add bits only, to
                                              * avoid stepping on a