ceph: update wanted caps after resuming stale session
authorYan, Zheng <zyan@redhat.com>
Mon, 10 Dec 2018 08:35:09 +0000 (16:35 +0800)
committerIlya Dryomov <idryomov@gmail.com>
Wed, 26 Dec 2018 15:08:36 +0000 (16:08 +0100)
mds contains an optimization, it does not re-issue stale caps if
client does not want any cap.

A special case of the optimization is that client wants some caps,
but skipped updating 'wanted'. For this case, client needs to update
'wanted' when stale session get renewed.

Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/caps.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h

index 92643b8..94c026b 100644 (file)
@@ -657,6 +657,9 @@ void ceph_add_cap(struct inode *inode,
                session->s_nr_caps++;
                spin_unlock(&session->s_cap_lock);
        } else {
+               if (cap->cap_gen < session->s_cap_gen)
+                       cap->issued = cap->implemented = CEPH_CAP_PIN;
+
                /*
                 * auth mds of the inode changed. we received the cap export
                 * message, but still haven't received the cap import message.
@@ -3065,21 +3068,6 @@ static void handle_cap_grant(struct inode *inode,
                inode->i_size);
 
 
-       /*
-        * auth mds of the inode changed. we received the cap export message,
-        * but still haven't received the cap import message. handle_cap_export
-        * updated the new auth MDS' cap.
-        *
-        * "ceph_seq_cmp(seq, cap->seq) <= 0" means we are processing a message
-        * that was sent before the cap import message. So don't remove caps.
-        */
-       if (ceph_seq_cmp(seq, cap->seq) <= 0) {
-               WARN_ON(cap != ci->i_auth_cap);
-               WARN_ON(cap->cap_id != le64_to_cpu(grant->cap_id));
-               seq = cap->seq;
-               newcaps |= cap->issued;
-       }
-
        /*
         * If CACHE is being revoked, and we have no dirty buffers,
         * try to invalidate (once).  (If there are dirty buffers, we
@@ -3099,6 +3087,24 @@ static void handle_cap_grant(struct inode *inode,
                }
        }
 
+       if (was_stale)
+               cap->issued = cap->implemented = CEPH_CAP_PIN;
+
+       /*
+        * auth mds of the inode changed. we received the cap export message,
+        * but still haven't received the cap import message. handle_cap_export
+        * updated the new auth MDS' cap.
+        *
+        * "ceph_seq_cmp(seq, cap->seq) <= 0" means we are processing a message
+        * that was sent before the cap import message. So don't remove caps.
+        */
+       if (ceph_seq_cmp(seq, cap->seq) <= 0) {
+               WARN_ON(cap != ci->i_auth_cap);
+               WARN_ON(cap->cap_id != le64_to_cpu(grant->cap_id));
+               seq = cap->seq;
+               newcaps |= cap->issued;
+       }
+
        /* side effects now are allowed */
        cap->cap_gen = session->s_cap_gen;
        cap->seq = seq;
@@ -3549,9 +3555,9 @@ retry:
                goto out_unlock;
 
        if (target < 0) {
-               __ceph_remove_cap(cap, false);
-               if (!ci->i_auth_cap)
+               if (cap->mds_wanted | cap->issued)
                        ci->i_ceph_flags |= CEPH_I_CAP_DROPPED;
+               __ceph_remove_cap(cap, false);
                goto out_unlock;
        }
 
index bd13a32..977e38f 100644 (file)
@@ -1232,13 +1232,13 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
        dout("removing cap %p, ci is %p, inode is %p\n",
             cap, ci, &ci->vfs_inode);
        spin_lock(&ci->i_ceph_lock);
+       if (cap->mds_wanted | cap->issued)
+               ci->i_ceph_flags |= CEPH_I_CAP_DROPPED;
        __ceph_remove_cap(cap, false);
        if (!ci->i_auth_cap) {
                struct ceph_cap_flush *cf;
                struct ceph_mds_client *mdsc = fsc->mdsc;
 
-               ci->i_ceph_flags |= CEPH_I_CAP_DROPPED;
-
                if (ci->i_wrbuffer_ref > 0 &&
                    READ_ONCE(fsc->mount_state) == CEPH_MOUNT_SHUTDOWN)
                        invalidate = true;
@@ -1355,6 +1355,12 @@ static void remove_session_caps(struct ceph_mds_session *session)
        dispose_cap_releases(session->s_mdsc, &dispose);
 }
 
+enum {
+       RECONNECT,
+       RENEWCAPS,
+       FORCE_RO,
+};
+
 /*
  * wake up any threads waiting on this session's caps.  if the cap is
  * old (didn't get renewed on the client reconnect), remove it now.
@@ -1365,23 +1371,34 @@ static int wake_up_session_cb(struct inode *inode, struct ceph_cap *cap,
                              void *arg)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
+       unsigned long ev = (unsigned long)arg;
 
-       if (arg) {
+       if (ev == RECONNECT) {
                spin_lock(&ci->i_ceph_lock);
                ci->i_wanted_max_size = 0;
                ci->i_requested_max_size = 0;
                spin_unlock(&ci->i_ceph_lock);
+       } else if (ev == RENEWCAPS) {
+               if (cap->cap_gen < cap->session->s_cap_gen) {
+                       /* mds did not re-issue stale cap */
+                       spin_lock(&ci->i_ceph_lock);
+                       cap->issued = cap->implemented = CEPH_CAP_PIN;
+                       /* make sure mds knows what we want */
+                       if (__ceph_caps_file_wanted(ci) & ~cap->mds_wanted)
+                               ci->i_ceph_flags |= CEPH_I_CAP_DROPPED;
+                       spin_unlock(&ci->i_ceph_lock);
+               }
+       } else if (ev == FORCE_RO) {
        }
        wake_up_all(&ci->i_cap_wq);
        return 0;
 }
 
-static void wake_up_session_caps(struct ceph_mds_session *session,
-                                int reconnect)
+static void wake_up_session_caps(struct ceph_mds_session *session, int ev)
 {
        dout("wake_up_session_caps %p mds%d\n", session, session->s_mds);
        iterate_session_caps(session, wake_up_session_cb,
-                            (void *)(unsigned long)reconnect);
+                            (void *)(unsigned long)ev);
 }
 
 /*
@@ -1466,7 +1483,7 @@ static void renewed_caps(struct ceph_mds_client *mdsc,
        spin_unlock(&session->s_cap_lock);
 
        if (wake)
-               wake_up_session_caps(session, 0);
+               wake_up_session_caps(session, RENEWCAPS);
 }
 
 /*
@@ -2847,7 +2864,7 @@ static void handle_session(struct ceph_mds_session *session,
                spin_lock(&session->s_cap_lock);
                session->s_readonly = true;
                spin_unlock(&session->s_cap_lock);
-               wake_up_session_caps(session, 0);
+               wake_up_session_caps(session, FORCE_RO);
                break;
 
        case CEPH_SESSION_REJECT:
@@ -3339,7 +3356,7 @@ static void check_new_map(struct ceph_mds_client *mdsc,
                                pr_info("mds%d recovery completed\n", s->s_mds);
                        kick_requests(mdsc, i);
                        ceph_kick_flushing_caps(mdsc, s);
-                       wake_up_session_caps(s, 1);
+                       wake_up_session_caps(s, RECONNECT);
                }
        }
 
index 32fcce0..729da15 100644 (file)
 #include <linux/ceph/auth.h>
 
 /* The first 8 bits are reserved for old ceph releases */
-#define CEPHFS_FEATURE_MIMIC    8
-
-#define CEPHFS_FEATURES_ALL {           \
-  0, 1, 2, 3, 4, 5, 6, 7,              \
-  CEPHFS_FEATURE_MIMIC,                 \
+#define CEPHFS_FEATURE_MIMIC           8
+#define CEPHFS_FEATURE_REPLY_ENCODING  9
+#define CEPHFS_FEATURE_RECLAIM_CLIENT  10
+#define CEPHFS_FEATURE_LAZY_CAP_WANTED 11
+
+#define CEPHFS_FEATURES_CLIENT_SUPPORTED {     \
+       0, 1, 2, 3, 4, 5, 6, 7,                 \
+       CEPHFS_FEATURE_MIMIC,                   \
+       CEPHFS_FEATURE_LAZY_CAP_WANTED,         \
 }
-
-#define CEPHFS_FEATURES_CLIENT_SUPPORTED CEPHFS_FEATURES_ALL
 #define CEPHFS_FEATURES_CLIENT_REQUIRED {}