ceph: issue a cap release immediately if no cap exists
authorXiubo Li <xiubli@redhat.com>
Tue, 13 Jun 2023 04:49:59 +0000 (12:49 +0800)
committerIlya Dryomov <idryomov@gmail.com>
Fri, 30 Jun 2023 10:08:55 +0000 (12:08 +0200)
In case:

           mds                             client
                                - Releases cap and put Inode
  - Increase cap->seq and sends
    revokes req to the client
  - Receives release req and    - Receives & drops the revoke req
    skip removing the cap and
    then eval the CInode and
    issue or revoke caps again.
                                - Receives & drops the caps update
                                  or revoke req
  - Health warning for client
    isn't responding to
    mclientcaps(revoke)

All the IMPORT/REVOKE/GRANT cap ops will increase the session seq
in MDS side and then the client need to issue a cap release to
unblock MDS to remove the corresponding cap to unblock possible
waiters.

Link: https://tracker.ceph.com/issues/61332
Signed-off-by: Xiubo Li <xiubli@redhat.com>
Reviewed-by: Milind Changire <mchangir@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/caps.c

index 6fb73e3..cef91dd 100644 (file)
@@ -4092,6 +4092,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        struct cap_extra_info extra_info = {};
        bool queue_trunc;
        bool close_sessions = false;
+       bool do_cap_release = false;
 
        dout("handle_caps from mds%d\n", session->s_mds);
 
@@ -4198,17 +4199,14 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        if (!inode) {
                dout(" i don't have ino %llx\n", vino.ino);
 
-               if (op == CEPH_CAP_OP_IMPORT) {
-                       cap = ceph_get_cap(mdsc, NULL);
-                       cap->cap_ino = vino.ino;
-                       cap->queue_release = 1;
-                       cap->cap_id = le64_to_cpu(h->cap_id);
-                       cap->mseq = mseq;
-                       cap->seq = seq;
-                       cap->issue_seq = seq;
-                       spin_lock(&session->s_cap_lock);
-                       __ceph_queue_cap_release(session, cap);
-                       spin_unlock(&session->s_cap_lock);
+               switch (op) {
+               case CEPH_CAP_OP_IMPORT:
+               case CEPH_CAP_OP_REVOKE:
+               case CEPH_CAP_OP_GRANT:
+                       do_cap_release = true;
+                       break;
+               default:
+                       break;
                }
                goto flush_cap_releases;
        }
@@ -4258,6 +4256,14 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                     inode, ceph_ino(inode), ceph_snap(inode),
                     session->s_mds);
                spin_unlock(&ci->i_ceph_lock);
+               switch (op) {
+               case CEPH_CAP_OP_REVOKE:
+               case CEPH_CAP_OP_GRANT:
+                       do_cap_release = true;
+                       break;
+               default:
+                       break;
+               }
                goto flush_cap_releases;
        }
 
@@ -4308,6 +4314,18 @@ flush_cap_releases:
         * along for the mds (who clearly thinks we still have this
         * cap).
         */
+       if (do_cap_release) {
+               cap = ceph_get_cap(mdsc, NULL);
+               cap->cap_ino = vino.ino;
+               cap->queue_release = 1;
+               cap->cap_id = le64_to_cpu(h->cap_id);
+               cap->mseq = mseq;
+               cap->seq = seq;
+               cap->issue_seq = seq;
+               spin_lock(&session->s_cap_lock);
+               __ceph_queue_cap_release(session, cap);
+               spin_unlock(&session->s_cap_lock);
+       }
        ceph_flush_cap_releases(mdsc, session);
        goto done;