From: Xiubo Li Date: Mon, 11 Mar 2024 05:09:14 +0000 (+0800) Subject: mds: always make getattr wait for xlock to be released by the previous client X-Git-Tag: v19.2.3~455^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=c6ce4c1f379fddb2ae3bdadb0bbc0b3dccace6a3;p=ceph.git mds: always make getattr wait for xlock to be released by the previous client 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 (cherry picked from commit b1ea37c5a6cc7b2dad417128990a6403de9cb170) --- diff --git a/src/mds/Server.cc b/src/mds/Server.cc index bd8e1f11b1cf..dc52b56ec468 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -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 &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 ||