]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: always make getattr wait for xlock to be released by the previous client 60691/head
authorXiubo Li <xiubli@redhat.com>
Mon, 11 Mar 2024 05:09:14 +0000 (13:09 +0800)
committerVenky Shankar <vshankar@redhat.com>
Mon, 11 Nov 2024 10:46:28 +0000 (16:16 +0530)
When the previous client's setattr request is still holding the xlock
for the linklock/authlock/xattrlock/filelock locks, if the same client
send a getattr request it will use the projected inode to fill the
reply, while for other clients the getattr requests will use the
non-projected inode to fill replies. This causes inconsistent file
mode across multiple clients.

This will just skip batching the ops when any of the xlock is held.

Fixes: https://tracker.ceph.com/issues/63906
Signed-off-by: Xiubo Li <xiubli@redhat.com>
(cherry picked from commit b1ea37c5a6cc7b2dad417128990a6403de9cb170)

src/mds/Server.cc

index bd8e1f11b1cfce5e0a607bb8ca387802ad8bfd09..dc52b56ec46816150a8931ece61dea5c8f56f37a 100644 (file)
@@ -4083,6 +4083,7 @@ CDir* Server::try_open_auth_dirfrag(CInode *diri, frag_t fg, const MDRequestRef&
 void Server::handle_client_getattr(const MDRequestRef& mdr, bool is_lookup)
 {
   const cref_t<MClientRequest> &req = mdr->client_request;
+  client_t client = mdr->get_client();
 
   if (req->get_filepath().depth() == 0 && is_lookup) {
     // refpath can't be empty for lookup but it can for
@@ -4104,6 +4105,17 @@ void Server::handle_client_getattr(const MDRequestRef& mdr, bool is_lookup)
     if (r > 0)
       return; // delayed
 
+    // Do not batch if any xlock is held
+    if (!r) {
+      CInode *in = mdr->in[0];
+      if (((mask & CEPH_CAP_LINK_SHARED) && (in->linklock.is_xlocked_by_client(client))) ||
+          ((mask & CEPH_CAP_AUTH_SHARED) && (in->authlock.is_xlocked_by_client(client))) ||
+          ((mask & CEPH_CAP_XATTR_SHARED) && (in->xattrlock.is_xlocked_by_client(client))) ||
+          ((mask & CEPH_CAP_FILE_SHARED) && (in->filelock.is_xlocked_by_client(client)))) {
+       r = -1;
+      }
+    }
+
     if (r < 0) {
       // fall-thru. let rdlock_path_pin_ref() check again.
     } else if (is_lookup) {
@@ -4145,7 +4157,6 @@ void Server::handle_client_getattr(const MDRequestRef& mdr, bool is_lookup)
    * handling this case here is easier than weakening rdlock
    * semantics... that would cause problems elsewhere.
    */
-  client_t client = mdr->get_client();
   int issued = 0;
   Capability *cap = ref->get_client_cap(client);
   if (cap && (mdr->snapid == CEPH_NOSNAP ||