From nobody Sat Jul 25 18:01:21 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AE8592A1B2; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784087942; cv=none; b=q8mOK4K8HtpywHCMbgeTrXF/RkbfL1wiA2RTph/VNliba2kkJLNJ1Zn/LctHi3N/4NHdtFObW+6eymdL8Uaz3pTwhqAvxlnDCgGZMr3RQ2foCnHS97ex7AvIDXj3PpK+J2OkbCHSowCE92L0kWEnJSR+w2FVtV+eIqjZks6kwE8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784087942; c=relaxed/simple; bh=usXMJycNUqlqgmLibcqdwKEGzxpM8o0oSreTSQUb9aA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mqKEaAz8OyFgbM8CJE7gKYqsYdfKgXhSv15IER1/JsyYpOXZQ1tRKdNujDmAVV3JINEbPBvCDGdPGERQubz6IGrxDwcCfyKacvr3oANg4gZPtkQKYxS2UkVv0ao3/Qy5Rn+3gYrVLG5ALgKMGWNXmxaC0zkDfhj3zMkrWSbPeFI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Z7F/sAdz; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Z7F/sAdz" Received: by smtp.kernel.org (Postfix) with ESMTPS id 5B2C6C2BCF5; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1784087942; bh=usXMJycNUqlqgmLibcqdwKEGzxpM8o0oSreTSQUb9aA=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Z7F/sAdzvdm0iOYAvwNSVFd5oMaIrsPUG3jel2gNeFA5glcrB1MhAyEfni3QSfmpQ +fhiLU2Bc3CvcgL+lCr7iuvXelXMZE/45o+yVh/EpJpo6SPi7nrMySbxfQmGBJx0Fb Qfwe69Wf0t9FMqL3qYFo8oonThLk7zcet6uVnlll13gbCFy754KIC8S1oK8I29XL0r Et5h8weXNPNttpIft5Bl21hRaLb3/H2UiUdqGNe/bSl0tDRyklUaG8eW1RyKY9Jx+w iJWBV//o6qQvsrmXTdRrX/qrz2fZiX7o7CzyWdgKsac8lBSv2VJV05QwAjsjYPbBFe TSnNw0Bzp2Dow== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4B0B6C4450B; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) From: Xiubo Li via B4 Relay Date: Wed, 15 Jul 2026 11:58:41 +0800 Subject: [PATCH v2 1/5] ceph: convert oldest_tid to atomic64_t Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260715-ceph-mdsc-mutex-optimization-v2-1-90e81b726724@clyso.com> References: <20260715-ceph-mdsc-mutex-optimization-v2-0-90e81b726724@clyso.com> In-Reply-To: <20260715-ceph-mdsc-mutex-optimization-v2-0-90e81b726724@clyso.com> To: Ilya Dryomov , Alex Markuze , Viacheslav Dubeyko Cc: ceph-devel@vger.kernel.org, linux-kernel@vger.kernel.org, Xiubo Li X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1784087938; l=4251; i=xiubo.li@clyso.com; s=20260625; h=from:subject:message-id; bh=Ln313jfnyI9iEkGY4T3NBIW+U7Vyr9d7sWpnTOxEXz8=; b=l3ywj6I+ak12opOA5SQTGoS7YjH4j/e47k19/70QSNRmLOlPy/zc9zNIqEOPPvNsLLcv107f0 uHPkV89Pzg3ACE0HsNDBOgFKgMV5J5JOUXS72t82+hQVISqL/Gsf4Ki X-Developer-Key: i=xiubo.li@clyso.com; a=ed25519; pk=V3NGr0AgAopiUhaLY51ipBkLN5LlcLhjOEfLEq1RoZ8= X-Endpoint-Received: by B4 Relay for xiubo.li@clyso.com/20260625 with auth_id=840 X-Original-From: Xiubo Li Reply-To: xiubo.li@clyso.com From: Xiubo Li The oldest_client_tid sent in the MDS request header is advisory: a stale value is harmless -- at worst the MDS may resend a reply we already have, or skip one we still need (which will just be retried). With the plain u64 read, however, the compiler is free to split or cache the load, which is undefined behaviour when the write side runs under mdsc->mutex on a different CPU. Convert mdsc->oldest_tid from u64 to atomic64_t so that reads are guaranteed to be single-copy atomic on all architectures. This removes the one remaining reason __prepare_send_request() and __send_request() needed to be called under mdsc->mutex, so drop those comments as well. All write sites (__register_request, __unregister_request) still run under mdsc->mutex, so use atomic64_set() for clarity. Signed-off-by: Xiubo Li --- fs/ceph/mds_client.c | 21 ++++++++------------- fs/ceph/mds_client.h | 2 +- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 9f84ef2ac6e4..98d0a5baff70 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1235,8 +1235,9 @@ static void __register_request(struct ceph_mds_client= *mdsc, if (!req->r_mnt_idmap) req->r_mnt_idmap =3D &nop_mnt_idmap; =20 - if (mdsc->oldest_tid =3D=3D 0 && req->r_op !=3D CEPH_MDS_OP_SETFILELOCK) - mdsc->oldest_tid =3D req->r_tid; + if (atomic64_read(&mdsc->oldest_tid) =3D=3D 0 && + req->r_op !=3D CEPH_MDS_OP_SETFILELOCK) + atomic64_set(&mdsc->oldest_tid, req->r_tid); =20 if (dir) { struct ceph_inode_info *ci =3D ceph_inode(dir); @@ -1257,14 +1258,14 @@ static void __unregister_request(struct ceph_mds_cl= ient *mdsc, /* Never leave an unregistered request on an unsafe list! */ list_del_init(&req->r_unsafe_item); =20 - if (req->r_tid =3D=3D mdsc->oldest_tid) { + if (req->r_tid =3D=3D atomic64_read(&mdsc->oldest_tid)) { struct rb_node *p =3D rb_next(&req->r_node); - mdsc->oldest_tid =3D 0; + atomic64_set(&mdsc->oldest_tid, 0); while (p) { struct ceph_mds_request *next_req =3D rb_entry(p, struct ceph_mds_request, r_node); if (next_req->r_op !=3D CEPH_MDS_OP_SETFILELOCK) { - mdsc->oldest_tid =3D next_req->r_tid; + atomic64_set(&mdsc->oldest_tid, next_req->r_tid); break; } p =3D rb_next(p); @@ -1693,7 +1694,7 @@ create_session_full_msg(struct ceph_mds_client *mdsc,= int op, u64 seq) ceph_encode_32(&p, 0); =20 /* version =3D=3D 7, oldest_client_tid */ - ceph_encode_64(&p, mdsc->oldest_tid); + ceph_encode_64(&p, atomic64_read(&mdsc->oldest_tid)); =20 msg->front.iov_len =3D p - msg->front.iov_base; msg->hdr.front_len =3D cpu_to_le32(msg->front.iov_len); @@ -2759,7 +2760,7 @@ static struct ceph_mds_request *__get_oldest_req(stru= ct ceph_mds_client *mdsc) =20 static inline u64 __get_oldest_tid(struct ceph_mds_client *mdsc) { - return mdsc->oldest_tid; + return atomic64_read(&mdsc->oldest_tid); } =20 #if IS_ENABLED(CONFIG_FS_ENCRYPTION) @@ -3438,9 +3439,6 @@ static void complete_request(struct ceph_mds_client *= mdsc, complete_all(&req->r_completion); } =20 -/* - * called under mdsc->mutex - */ static int __prepare_send_request(struct ceph_mds_session *session, struct ceph_mds_request *req, bool drop_cap_releases) @@ -3555,9 +3553,6 @@ static int __prepare_send_request(struct ceph_mds_ses= sion *session, return 0; } =20 -/* - * called under mdsc->mutex - */ static int __send_request(struct ceph_mds_session *session, struct ceph_mds_request *req, bool drop_cap_releases) diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 731d6ad04956..3b614b5df18c 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -532,7 +532,7 @@ struct ceph_mds_client { spinlock_t snap_empty_lock; /* protect snap_empty */ =20 u64 last_tid; /* most recent mds request */ - u64 oldest_tid; /* oldest incomplete mds request, + atomic64_t oldest_tid; /* oldest incomplete mds request, excluding setfilelock requests */ struct rb_root request_tree; /* pending mds requests */ struct delayed_work delayed_work; /* delayed work */ --=20 2.53.0 From nobody Sat Jul 25 18:01:21 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AEAE63AF650; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784087942; cv=none; b=p0usOwcE4rr70JNBFK7Bl0JGiAEDrU338fkfNP680gurmmpM2SJ7Np4GDUgm9F6h2zPYrTumiZhZ7WpdbFFKOIYMYkxChQu+WP17TI9yfFkyIEfFobgxV9dJrJBs+Vii3uoWcCbum872ehQHAwIBqIe/k7ozL/5uRfZrihPZiEo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784087942; c=relaxed/simple; bh=9eHsghMnzELI9sWNOISdlWuD7sJFf2S5mG7+4lNAlhQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=uHF973Js64sGOZPeLFhQsnr7Y1nVavgVzy2fril5iH/TszW7ZW3Z7tm+bR8/aAG/ljXWqbz5WW159qPaJ4UmQczcN45NdbtvenBnnkdeKc3kTYiell2SUm94kJvSZEorpFXPcp3ge4qOiMCWSpDIHb2WTpLSU0WnmzozeZuL1Gw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=U8n1kg0G; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="U8n1kg0G" Received: by smtp.kernel.org (Postfix) with ESMTPS id 683A9C2BCC7; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1784087942; bh=9eHsghMnzELI9sWNOISdlWuD7sJFf2S5mG7+4lNAlhQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=U8n1kg0GQbWEH8luhlTzK4VHMjZcKnpC56k9fT8NACr57O52wDTOxuWdGqM4ceE6F JgpdVZZmXHfDdOL0yp96ngGC+4ZC8Hma3RUyrkk2NJjSi6Iiq7x5b0L3usmEIfRzYG vHGFhTt+hWM/gEpCT44dfJaBuvPrwbYnpnVJr0/WHB/lRj+/wcBvvV/Hf/CJ+AAoUy hwmd1hpXiKAzycRC7X788TBLp1+pIgWHjb1RneVVPvmeAxTCEdvMJDWuYq9LBpy+Gz 05HFz8kBa4q3Aa4YTX5rdGDMdusPwe+StVH8nuVkDddrvESBAG6iNNSLE+6h7vcJyW DVyismzkoqiUg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 57D79C44508; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) From: Xiubo Li via B4 Relay Date: Wed, 15 Jul 2026 11:58:42 +0800 Subject: [PATCH v2 2/5] ceph: replace the request_tree rbtree with an xarray keyed by r_tid. Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260715-ceph-mdsc-mutex-optimization-v2-2-90e81b726724@clyso.com> References: <20260715-ceph-mdsc-mutex-optimization-v2-0-90e81b726724@clyso.com> In-Reply-To: <20260715-ceph-mdsc-mutex-optimization-v2-0-90e81b726724@clyso.com> To: Ilya Dryomov , Alex Markuze , Viacheslav Dubeyko Cc: ceph-devel@vger.kernel.org, linux-kernel@vger.kernel.org, Xiubo Li X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1784087938; l=13290; i=xiubo.li@clyso.com; s=20260625; h=from:subject:message-id; bh=ukIc8+P1kl6gNpJzkfIpt3Q/+/0Seg+CITm/bgW4ghs=; b=VVsqLPQizoZ5TQVfkZI67wx8uyZPJH+xBPpa4YXNZix7aSw3+v1ADLL3B+JXjKBn3rXbYdxXk stGGslxi/wZCFd6GeUUZ5FHZajk90qTQJ2DR7AljKexXFDwE/U0P4xN X-Developer-Key: i=xiubo.li@clyso.com; a=ed25519; pk=V3NGr0AgAopiUhaLY51ipBkLN5LlcLhjOEfLEq1RoZ8= X-Endpoint-Received: by B4 Relay for xiubo.li@clyso.com/20260625 with auth_id=840 X-Original-From: Xiubo Li Reply-To: xiubo.li@clyso.com From: Xiubo Li The xarray gives O(1) lookups by tid (vs O(log N) rbtree) and uses internal RCU-based locking, eliminating mdsc->mutex as a precondition for tree access and paving the way for lockless xa_load() in the future. In practise this yields a 13x reduction of handle_reply mutex hold time, from 51-416us down to 10-32us, due to parse_reply_info() no longer being protected by the global mutex. Check xa_store() for allocation failure, which would otherwise be silent, and skip __do_request() in the submit path if registration failed. On 32-bit architectures xarray silently truncates u64 keys because its index type is unsigned long. Guard the entire conversion by BITS_PER_LONG=3D=3D64 and fall back to the original rbtree on 32-bit so there is no regression from the current code. Signed-off-by: Xiubo Li --- fs/ceph/debugfs.c | 9 +++ fs/ceph/mds_client.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++= ++-- fs/ceph/mds_client.h | 10 +++- 3 files changed, 173 insertions(+), 6 deletions(-) diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c index 18eb5da03411..f0d0b9b04b79 100644 --- a/fs/ceph/debugfs.c +++ b/fs/ceph/debugfs.c @@ -87,12 +87,21 @@ static int mdsc_show(struct seq_file *s, void *p) struct ceph_fs_client *fsc =3D s->private; struct ceph_mds_client *mdsc =3D fsc->mdsc; struct ceph_mds_request *req; +#if BITS_PER_LONG =3D=3D 64 + unsigned long idx; +#else struct rb_node *rp; +#endif char *path; =20 mutex_lock(&mdsc->mutex); +#if BITS_PER_LONG =3D=3D 64 + idx =3D 0; + xa_for_each(&mdsc->request_tree, idx, req) { +#else for (rp =3D rb_first(&mdsc->request_tree); rp; rp =3D rb_next(rp)) { req =3D rb_entry(rp, struct ceph_mds_request, r_node); +#endif =20 if (req->r_request && req->r_session) seq_printf(s, "%lld\tmds%d\t", req->r_tid, diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 98d0a5baff70..239ed34886f9 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1183,7 +1183,9 @@ void ceph_mdsc_release_request(struct kref *kref) kmem_cache_free(ceph_mds_request_cachep, req); } =20 +#if BITS_PER_LONG !=3D 64 DEFINE_RB_FUNCS(request, struct ceph_mds_request, r_tid, r_node) +#endif =20 /* * lookup session, bump ref if found. @@ -1195,7 +1197,11 @@ lookup_get_request(struct ceph_mds_client *mdsc, u64= tid) { struct ceph_mds_request *req; =20 +#if BITS_PER_LONG =3D=3D 64 + req =3D xa_load(&mdsc->request_tree, tid); +#else req =3D lookup_request(&mdsc->request_tree, tid); +#endif if (req) ceph_mdsc_get_request(req); =20 @@ -1229,7 +1235,17 @@ static void __register_request(struct ceph_mds_clien= t *mdsc, } doutc(cl, "%p tid %lld\n", req, req->r_tid); ceph_mdsc_get_request(req); +#if BITS_PER_LONG =3D=3D 64 + if (xa_is_err(xa_store(&mdsc->request_tree, req->r_tid, req, + GFP_NOFS))) { + pr_err_client(cl, "%p tid %lld: xa_store failed\n", + req, req->r_tid); + req->r_err =3D -ENOMEM; + return; + } +#else insert_request(&mdsc->request_tree, req); +#endif =20 req->r_cred =3D get_current_cred(); if (!req->r_mnt_idmap) @@ -1259,6 +1275,19 @@ static void __unregister_request(struct ceph_mds_cli= ent *mdsc, list_del_init(&req->r_unsafe_item); =20 if (req->r_tid =3D=3D atomic64_read(&mdsc->oldest_tid)) { +#if BITS_PER_LONG =3D=3D 64 + unsigned long tidx =3D req->r_tid + 1; + struct ceph_mds_request *next_req; + + atomic64_set(&mdsc->oldest_tid, 0); + xa_for_each_start(&mdsc->request_tree, tidx, next_req, tidx) { + if (next_req->r_op !=3D CEPH_MDS_OP_SETFILELOCK) { + atomic64_set(&mdsc->oldest_tid, + next_req->r_tid); + break; + } + } +#else struct rb_node *p =3D rb_next(&req->r_node); atomic64_set(&mdsc->oldest_tid, 0); while (p) { @@ -1270,9 +1299,14 @@ static void __unregister_request(struct ceph_mds_cli= ent *mdsc, } p =3D rb_next(p); } +#endif } =20 +#if BITS_PER_LONG =3D=3D 64 + xa_erase(&mdsc->request_tree, req->r_tid); +#else erase_request(&mdsc->request_tree, req); +#endif =20 if (req->r_unsafe_dir) { struct ceph_inode_info *ci =3D ceph_inode(req->r_unsafe_dir); @@ -1829,7 +1863,11 @@ static void cleanup_session_requests(struct ceph_mds= _client *mdsc, { struct ceph_client *cl =3D mdsc->fsc->client; struct ceph_mds_request *req; +#if BITS_PER_LONG =3D=3D 64 + unsigned long idx; +#else struct rb_node *p; +#endif =20 doutc(cl, "mds%d\n", session->s_mds); mutex_lock(&mdsc->mutex); @@ -1845,6 +1883,14 @@ static void cleanup_session_requests(struct ceph_mds= _client *mdsc, __unregister_request(mdsc, req); } /* zero r_attempts, so kick_requests() will re-send requests */ +#if BITS_PER_LONG =3D=3D 64 + idx =3D 0; + xa_for_each(&mdsc->request_tree, idx, req) { + if (req->r_session && + req->r_session->s_mds =3D=3D session->s_mds) + req->r_attempts =3D 0; + } +#else p =3D rb_first(&mdsc->request_tree); while (p) { req =3D rb_entry(p, struct ceph_mds_request, r_node); @@ -1853,6 +1899,7 @@ static void cleanup_session_requests(struct ceph_mds_= client *mdsc, req->r_session->s_mds =3D=3D session->s_mds) req->r_attempts =3D 0; } +#endif mutex_unlock(&mdsc->mutex); } =20 @@ -2732,7 +2779,9 @@ ceph_mdsc_create_request(struct ceph_mds_client *mdsc= , int op, int mode) req->r_fmode =3D -1; req->r_feature_needed =3D -1; kref_init(&req->r_kref); +#if BITS_PER_LONG !=3D 64 RB_CLEAR_NODE(&req->r_node); +#endif INIT_LIST_HEAD(&req->r_wait); init_completion(&req->r_completion); init_completion(&req->r_safe_completion); @@ -2752,10 +2801,16 @@ ceph_mdsc_create_request(struct ceph_mds_client *md= sc, int op, int mode) */ static struct ceph_mds_request *__get_oldest_req(struct ceph_mds_client *m= dsc) { +#if BITS_PER_LONG =3D=3D 64 + unsigned long idx =3D 0; + + return xa_find(&mdsc->request_tree, &idx, ULONG_MAX, XA_PRESENT); +#else if (RB_EMPTY_ROOT(&mdsc->request_tree)) return NULL; return rb_entry(rb_first(&mdsc->request_tree), struct ceph_mds_request, r_node); +#endif } =20 static inline u64 __get_oldest_tid(struct ceph_mds_client *mdsc) @@ -3816,12 +3871,20 @@ static void kick_requests(struct ceph_mds_client *m= dsc, int mds) { struct ceph_client *cl =3D mdsc->fsc->client; struct ceph_mds_request *req; - struct rb_node *p =3D rb_first(&mdsc->request_tree); +#if BITS_PER_LONG =3D=3D 64 + unsigned long idx; +#else + struct rb_node *p; +#endif =20 doutc(cl, "kick_requests mds%d\n", mds); - while (p) { +#if BITS_PER_LONG =3D=3D 64 + idx =3D 0; + xa_for_each(&mdsc->request_tree, idx, req) { +#else + for (p =3D rb_first(&mdsc->request_tree); p; p =3D rb_next(p)) { req =3D rb_entry(p, struct ceph_mds_request, r_node); - p =3D rb_next(p); +#endif if (test_bit(CEPH_MDS_R_GOT_UNSAFE, &req->r_req_flags)) continue; if (req->r_attempts > 0) @@ -3894,7 +3957,8 @@ int ceph_mdsc_submit_request(struct ceph_mds_client *= mdsc, struct inode *dir, mutex_lock(&mdsc->mutex); __register_request(mdsc, req, dir); trace_ceph_mdsc_submit_request(mdsc, req); - __do_request(mdsc, req); + if (!req->r_err) + __do_request(mdsc, req); err =3D req->r_err; mutex_unlock(&mdsc->mutex); return err; @@ -4654,7 +4718,11 @@ static void replay_unsafe_requests(struct ceph_mds_c= lient *mdsc, struct ceph_mds_session *session) { struct ceph_mds_request *req, *nreq; +#if BITS_PER_LONG =3D=3D 64 + unsigned long idx; +#else struct rb_node *p; +#endif =20 doutc(mdsc->fsc->client, "mds%d\n", session->s_mds); =20 @@ -4666,10 +4734,15 @@ static void replay_unsafe_requests(struct ceph_mds_= client *mdsc, * also re-send old requests when MDS enters reconnect stage. So that MDS * can process completed request in clientreplay stage. */ +#if BITS_PER_LONG =3D=3D 64 + idx =3D 0; + xa_for_each(&mdsc->request_tree, idx, req) { +#else p =3D rb_first(&mdsc->request_tree); while (p) { req =3D rb_entry(p, struct ceph_mds_request, r_node); p =3D rb_next(p); +#endif if (test_bit(CEPH_MDS_R_GOT_UNSAFE, &req->r_req_flags)) continue; if (req->r_attempts =3D=3D 0) @@ -5514,7 +5587,11 @@ static void ceph_mdsc_reset_workfn(struct work_struc= t *work) */ { struct ceph_mds_request *req; +#if BITS_PER_LONG =3D=3D 64 + unsigned long idx; +#else struct rb_node *rn; +#endif u64 last_tid; =20 mutex_lock(&mdsc->mutex); @@ -5522,14 +5599,24 @@ static void ceph_mdsc_reset_workfn(struct work_stru= ct *work) mutex_unlock(&mdsc->mutex); =20 mutex_lock(&mdsc->mutex); +#if BITS_PER_LONG =3D=3D 64 + idx =3D 0; + while ((req =3D xa_find(&mdsc->request_tree, &idx, last_tid, + XA_PRESENT))) { +#else rn =3D rb_first(&mdsc->request_tree); while (rn) { req =3D rb_entry(rn, struct ceph_mds_request, r_node); if (req->r_tid > last_tid) break; +#endif if (req->r_op =3D=3D CEPH_MDS_OP_SETFILELOCK || !(req->r_op & CEPH_MDS_OP_WRITE)) { +#if BITS_PER_LONG =3D=3D 64 + idx++; +#else rn =3D rb_next(rn); +#endif continue; } ceph_mdsc_get_request(req); @@ -5542,7 +5629,11 @@ static void ceph_mdsc_reset_workfn(struct work_struc= t *work) ceph_mdsc_put_request(req); if (time_after(jiffies, drain_deadline)) break; +#if BITS_PER_LONG =3D=3D 64 + idx =3D 0; /* restart: tree may have changed */ +#else rn =3D rb_first(&mdsc->request_tree); +#endif } mutex_unlock(&mdsc->mutex); =20 @@ -6268,7 +6359,11 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc) mdsc->snap_realms =3D RB_ROOT; INIT_LIST_HEAD(&mdsc->snap_empty); spin_lock_init(&mdsc->snap_empty_lock); +#if BITS_PER_LONG =3D=3D 64 + xa_init(&mdsc->request_tree); +#else mdsc->request_tree =3D RB_ROOT; +#endif INIT_DELAYED_WORK(&mdsc->delayed_work, delayed_work); mdsc->last_renew_caps =3D jiffies; INIT_LIST_HEAD(&mdsc->cap_delay_list); @@ -6590,8 +6685,59 @@ static void flush_mdlog_and_wait_mdsc_unsafe_request= s(struct ceph_mds_client *md u64 want_tid) { struct ceph_client *cl =3D mdsc->fsc->client; - struct ceph_mds_request *req =3D NULL, *nextreq; struct ceph_mds_session *last_session =3D NULL; +#if BITS_PER_LONG =3D=3D 64 + struct ceph_mds_request *req; + unsigned long idx; + + mutex_lock(&mdsc->mutex); + doutc(cl, "want %lld\n", want_tid); + idx =3D 0; + while ((req =3D xa_find(&mdsc->request_tree, &idx, want_tid, + XA_PRESENT))) { + u64 next_tid =3D req->r_tid + 1; + + if (req->r_op =3D=3D CEPH_MDS_OP_SETFILELOCK || + !(req->r_op & CEPH_MDS_OP_WRITE)) { + idx =3D next_tid; + continue; + } + + { + struct ceph_mds_session *s =3D req->r_session; + + if (!s) { + idx =3D next_tid; + continue; + } + + /* write op */ + ceph_mdsc_get_request(req); + s =3D ceph_get_mds_session(s); + mutex_unlock(&mdsc->mutex); + + /* send flush mdlog request to MDS */ + if (last_session !=3D s) { + send_flush_mdlog(s); + ceph_put_mds_session(last_session); + last_session =3D s; + } else { + ceph_put_mds_session(s); + } + doutc(cl, "wait on %llu (want %llu)\n", + req->r_tid, want_tid); + wait_for_completion(&req->r_safe_completion); + + mutex_lock(&mdsc->mutex); + ceph_mdsc_put_request(req); + idx =3D next_tid; + } + } + mutex_unlock(&mdsc->mutex); + ceph_put_mds_session(last_session); + doutc(cl, "done\n"); +#else /* BITS_PER_LONG !=3D 64 =E2=80=94 rbtree fallback */ + struct ceph_mds_request *req =3D NULL, *nextreq; struct rb_node *n; =20 mutex_lock(&mdsc->mutex); @@ -6649,6 +6795,7 @@ static void flush_mdlog_and_wait_mdsc_unsafe_requests= (struct ceph_mds_client *md mutex_unlock(&mdsc->mutex); ceph_put_mds_session(last_session); doutc(cl, "done\n"); +#endif } =20 void ceph_mdsc_sync(struct ceph_mds_client *mdsc) @@ -6803,6 +6950,9 @@ static void ceph_mdsc_stop(struct ceph_mds_client *md= sc) if (mdsc->mdsmap) ceph_mdsmap_destroy(mdsc->mdsmap); kfree(mdsc->sessions); +#if BITS_PER_LONG =3D=3D 64 + xa_destroy(&mdsc->request_tree); +#endif ceph_caps_finalize(mdsc); =20 if (mdsc->s_cap_auths) { diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 3b614b5df18c..c2de551607e3 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -329,7 +329,11 @@ typedef int (*ceph_mds_request_wait_callback_t) (struc= t ceph_mds_client *mdsc, */ struct ceph_mds_request { u64 r_tid; /* transaction id */ +#if BITS_PER_LONG =3D=3D 64 + /* embedded in mdsc->request_tree xarray */ +#else struct rb_node r_node; +#endif struct ceph_mds_client *r_mdsc; =20 struct kref r_kref; @@ -534,7 +538,11 @@ struct ceph_mds_client { u64 last_tid; /* most recent mds request */ atomic64_t oldest_tid; /* oldest incomplete mds request, excluding setfilelock requests */ - struct rb_root request_tree; /* pending mds requests */ +#if BITS_PER_LONG =3D=3D 64 + struct xarray request_tree; /* pending mds requests */ +#else + struct rb_root request_tree; /* pending mds requests */ +#endif struct delayed_work delayed_work; /* delayed work */ unsigned long last_renew_caps; /* last time we renewed our caps */ struct list_head cap_delay_list; /* caps with delayed release */ --=20 2.53.0 From nobody Sat Jul 25 18:01:21 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AE9BC3A9619; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784087942; cv=none; b=Oj+xDNy1ngYkvQNJ9PO4ZfYJWFzUZoPgJZphks3+rOe02U5CBwMONkt8qiZvcK5pyT29alNMzNZqNp0Sv6Fl5u8S/a0GjGzkq+dUJknTrbXP1dkB9qvbHdVvVuHLQhGdG8AZdJkDuro5E3b0S4l+wald4+upX4wA0qZRPKStIaw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784087942; c=relaxed/simple; bh=9ZVzrx+cAqVCn/tO58rBI8AofKnKMlLa6UyXiCkHSyM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=bImgHmfBY2Ft1zDWdriodRyqUm1kmU7p+yZC2rRTA+SK/qCZ+1M9eP82+Qp9KmJaiGuuk4LSILwBelumBpk0GoQtXydcMFRGr0RkjqC+Fpzf/MGDCya7D2FcqKfx1qUgs2y2LPMNW7cNlbp3p5GM4BV0WwCusgDOEVSoCttGOOw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=aKLg6DGu; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="aKLg6DGu" Received: by smtp.kernel.org (Postfix) with ESMTPS id 74F5DC2BCF6; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1784087942; bh=9ZVzrx+cAqVCn/tO58rBI8AofKnKMlLa6UyXiCkHSyM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=aKLg6DGuuUFLUYj4kVohcE8W3Eu79f+h9pAgAV+aDnVFiWI7AX6KMuqTYNaloAunL CbzYqX8d7DoUUD3P/1hL82az/qzoOe32dcDGSaW4nYZpV1Z/+940kfyzMe3J6JJ8HX BcXQxxZr2y+16/8KNfTghkM6C/7BuzkrrI7gjxykS6BwN6c29ktlYlhG/WvLI775pU +uHrlzMOjEKzfC/lQeQQPeSe6Q//NP8w1TsBihS4bxUejpfQzbsuDSBLm+N4ur9GF/ SUUqTdV/QdhiFYwwrnU4wX2XwJY3IoKutJTS8B4pqLLlGzNOerpEf1Pi3rNdhfpphs qf7XqvrjiiLoA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 64E6DC4450D; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) From: Xiubo Li via B4 Relay Date: Wed, 15 Jul 2026 11:58:43 +0800 Subject: [PATCH v2 3/5] ceph: add wait_list_lock for wait-list serialization Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260715-ceph-mdsc-mutex-optimization-v2-3-90e81b726724@clyso.com> References: <20260715-ceph-mdsc-mutex-optimization-v2-0-90e81b726724@clyso.com> In-Reply-To: <20260715-ceph-mdsc-mutex-optimization-v2-0-90e81b726724@clyso.com> To: Ilya Dryomov , Alex Markuze , Viacheslav Dubeyko Cc: ceph-devel@vger.kernel.org, linux-kernel@vger.kernel.org, Xiubo Li X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1784087938; l=4321; i=xiubo.li@clyso.com; s=20260625; h=from:subject:message-id; bh=ZM5+rqFiltYRAU5IPZZD6s0Tq42PaxLa1hlAMloRIAw=; b=LMmXuh/AuXGC5uVA1bUJB0tXaWuHoaf4eKvfIQIwZouT1Kl7uT+CKq8wEeWYF+u5hJ+EAxSJ6 eooP2nu8Eg4BSoO+zFav9I+S237NCubV+2PPtaW9xIMX7Q2vgidl/uX X-Developer-Key: i=xiubo.li@clyso.com; a=ed25519; pk=V3NGr0AgAopiUhaLY51ipBkLN5LlcLhjOEfLEq1RoZ8= X-Endpoint-Received: by B4 Relay for xiubo.li@clyso.com/20260625 with auth_id=840 X-Original-From: Xiubo Li Reply-To: xiubo.li@clyso.com From: Xiubo Li Add a dedicated spinlock to protect the waiting_for_map and s_waiting lists, which are currently serialized by mdsc->mutex. This is a preparatory step for removing mdsc->mutex from the kick_requests() path: xa_for_each() is internally locked and the per-request filter checks are lockless, so only list_del_init() needs external protection. Signed-off-by: Xiubo Li --- fs/ceph/mds_client.c | 18 +++++++++++++++++- fs/ceph/mds_client.h | 3 +++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 239ed34886f9..a250938f32d3 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -3669,7 +3669,9 @@ static void __do_request(struct ceph_mds_client *mdsc, doutc(cl, "no mdsmap, waiting for map\n"); trace_ceph_mdsc_suspend_request(mdsc, session, req, ceph_mdsc_suspend_reason_no_mdsmap); + spin_lock(&mdsc->wait_list_lock); list_add(&req->r_wait, &mdsc->waiting_for_map); + spin_unlock(&mdsc->wait_list_lock); return; } if (!(mdsc->fsc->mount_options->flags & @@ -3692,7 +3694,9 @@ static void __do_request(struct ceph_mds_client *mdsc, doutc(cl, "no mds or not active, waiting for map\n"); trace_ceph_mdsc_suspend_request(mdsc, session, req, ceph_mdsc_suspend_reason_no_active_mds); + spin_lock(&mdsc->wait_list_lock); list_add(&req->r_wait, &mdsc->waiting_for_map); + spin_unlock(&mdsc->wait_list_lock); return; } =20 @@ -3740,9 +3744,12 @@ static void __do_request(struct ceph_mds_client *mds= c, if (ceph_test_mount_opt(mdsc->fsc, CLEANRECOVER)) { trace_ceph_mdsc_suspend_request(mdsc, session, req, ceph_mdsc_suspend_reason_rejected); + spin_lock(&mdsc->wait_list_lock); list_add(&req->r_wait, &mdsc->waiting_for_map); - } else + spin_unlock(&mdsc->wait_list_lock); + } else { err =3D -EACCES; + } goto out_session; } =20 @@ -3757,7 +3764,9 @@ static void __do_request(struct ceph_mds_client *mdsc, } trace_ceph_mdsc_suspend_request(mdsc, session, req, ceph_mdsc_suspend_reason_session); + spin_lock(&mdsc->wait_list_lock); list_add(&req->r_wait, &session->s_waiting); + spin_unlock(&mdsc->wait_list_lock); goto out_session; } =20 @@ -3850,7 +3859,9 @@ static void __wake_requests(struct ceph_mds_client *m= dsc, struct ceph_mds_request *req; LIST_HEAD(tmp_list); =20 + spin_lock(&mdsc->wait_list_lock); list_splice_init(head, &tmp_list); + spin_unlock(&mdsc->wait_list_lock); =20 while (!list_empty(&tmp_list)) { req =3D list_entry(tmp_list.next, @@ -3892,7 +3903,9 @@ static void kick_requests(struct ceph_mds_client *mds= c, int mds) if (req->r_session && req->r_session->s_mds =3D=3D mds) { doutc(cl, " kicking tid %llu\n", req->r_tid); + spin_lock(&mdsc->wait_list_lock); list_del_init(&req->r_wait); + spin_unlock(&mdsc->wait_list_lock); trace_ceph_mdsc_resume_request(mdsc, req); __do_request(mdsc, req); } @@ -6359,6 +6372,7 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc) mdsc->snap_realms =3D RB_ROOT; INIT_LIST_HEAD(&mdsc->snap_empty); spin_lock_init(&mdsc->snap_empty_lock); + spin_lock_init(&mdsc->wait_list_lock); #if BITS_PER_LONG =3D=3D 64 xa_init(&mdsc->request_tree); #else @@ -6445,7 +6459,9 @@ static void wait_requests(struct ceph_mds_client *mds= c) mutex_lock(&mdsc->mutex); while ((req =3D __get_oldest_req(mdsc))) { doutc(cl, "timed out on tid %llu\n", req->r_tid); + spin_lock(&mdsc->wait_list_lock); list_del_init(&req->r_wait); + spin_unlock(&mdsc->wait_list_lock); __unregister_request(mdsc, req); } } diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index c2de551607e3..0a9f89498604 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -534,6 +534,9 @@ struct ceph_mds_client { struct list_head snap_empty; int num_snap_realms; spinlock_t snap_empty_lock; /* protect snap_empty */ + spinlock_t wait_list_lock; /* protect waiting_for_map + * and s_waiting lists + */ =20 u64 last_tid; /* most recent mds request */ atomic64_t oldest_tid; /* oldest incomplete mds request, --=20 2.53.0 From nobody Sat Jul 25 18:01:21 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AEA4C3ACA70; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784087942; cv=none; b=nIrdpwvPo4dQlHVSlNGe3D6yvXImBeyHkZxHzmTMvjkzXMYil3j7+4cWRRjFkla2HVH/EVTKnLNd19GoNHTVsBcmj/uPkRHyU27QOZy2A9KJUuJxiP/u5DpGffHZT5GirCNSwRkQS/Vv2JwvzOZkBFl5MnGX/08cx8P7cj5dOds= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784087942; c=relaxed/simple; bh=deIkzA9YGSUEZyCI4TAvpObRFXohX3jVU4/b6fTYbZI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Ak11CBElLSZOkDOnATb/hbg+NCFpQjMhQj+KBV3uWhVHckp531wItatVWSFmGhYjUjjtdsqlNju56L/f2jNB0m7ScrJLX8kGAhAwD8zhh/AVqmF0kwf2g3hUuIs8UwCVDfmMG59/h1OqX7azwJ7jP1Cnn74bwoN93A9K69ZeMrU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kUxemRxg; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kUxemRxg" Received: by smtp.kernel.org (Postfix) with ESMTPS id 7F160C2BCF7; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1784087942; bh=deIkzA9YGSUEZyCI4TAvpObRFXohX3jVU4/b6fTYbZI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=kUxemRxgux9q8lai9dxE0oPK8NKdbU2a2ZtFSkW3NEf/KinkrghxdPPTf0kYpNHID 0g7EB8UjgX8mR1cLK28tFIEPHyFrhur4A0nyOM2yvQaqEECpT9wpjEY0GrDR9sxBjd UQjfWd1JkckwSHmJ8QYeXzuiDGQhBj45K5GMzSOUpczh08KdSB2uijUCKINlv6eUp1 W09XEz2FzqUYQnR64JAqW5kC7F1fPKev6E+5ummsHNohd/OHwzf+X14wQkR76f13KF EgdOqvi9eApUa1ESl+hWjz0IdkbeCn3y2Qgnd/Og3tUlvl/9tG46rTTlhTm3zbwfqG 2dSUp0VE3BMjg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 70EA1C4450A; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) From: Xiubo Li via B4 Relay Date: Wed, 15 Jul 2026 11:58:44 +0800 Subject: [PATCH v2 4/5] ceph: move mdsc->mutex into __do_request() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260715-ceph-mdsc-mutex-optimization-v2-4-90e81b726724@clyso.com> References: <20260715-ceph-mdsc-mutex-optimization-v2-0-90e81b726724@clyso.com> In-Reply-To: <20260715-ceph-mdsc-mutex-optimization-v2-0-90e81b726724@clyso.com> To: Ilya Dryomov , Alex Markuze , Viacheslav Dubeyko Cc: ceph-devel@vger.kernel.org, linux-kernel@vger.kernel.org, Xiubo Li X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1784087938; l=8538; i=xiubo.li@clyso.com; s=20260625; h=from:subject:message-id; bh=NnDJ68VidiftOOlT17UxoqIitRdN5cgavA36gfJL014=; b=REV96JWmxzIeiexTmdhnBzIudmEGj692GmP4M1OEOwZaAhFatZTobX4U8p+UZ1h8EQV74dunt 5PYZGmjOxPaCHDB+X16Ikd7vzBwPylVuNam99Bo5ZNk3GXt8q2P6YiH X-Developer-Key: i=xiubo.li@clyso.com; a=ed25519; pk=V3NGr0AgAopiUhaLY51ipBkLN5LlcLhjOEfLEq1RoZ8= X-Endpoint-Received: by B4 Relay for xiubo.li@clyso.com/20260625 with auth_id=840 X-Original-From: Xiubo Li Reply-To: xiubo.li@clyso.com From: Xiubo Li __do_request() now acquires mdsc->mutex on entry and unlocks at every exit point, so callers no longer need to hold it. As a result kick_requests() is now completely free of mdsc->mutex: xa_for_each() is internally locked, list_del_init() is guarded by wait_list_lock, and __do_request() manages its own serialization. Remove the no-longer-needed mutex_lock/unlock around __do_request() in ceph_mdsc_submit_request() and handle_forward(). The do_request() wrapper introduced in the previous commit is no longer necessary and is dropped. Signed-off-by: Xiubo Li --- fs/ceph/mds_client.c | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index a250938f32d3..be0dae919d69 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -3637,9 +3637,12 @@ static void __do_request(struct ceph_mds_client *mds= c, int err =3D 0; bool random; =20 + mutex_lock(&mdsc->mutex); + if (req->r_err || test_bit(CEPH_MDS_R_GOT_RESULT, &req->r_req_flags)) { if (test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) __unregister_request(mdsc, req); + mutex_unlock(&mdsc->mutex); return; } =20 @@ -3672,6 +3675,7 @@ static void __do_request(struct ceph_mds_client *mdsc, spin_lock(&mdsc->wait_list_lock); list_add(&req->r_wait, &mdsc->waiting_for_map); spin_unlock(&mdsc->wait_list_lock); + mutex_unlock(&mdsc->mutex); return; } if (!(mdsc->fsc->mount_options->flags & @@ -3697,6 +3701,7 @@ static void __do_request(struct ceph_mds_client *mdsc, spin_lock(&mdsc->wait_list_lock); list_add(&req->r_wait, &mdsc->waiting_for_map); spin_unlock(&mdsc->wait_list_lock); + mutex_unlock(&mdsc->mutex); return; } =20 @@ -3770,6 +3775,8 @@ static void __do_request(struct ceph_mds_client *mdsc, goto out_session; } =20 + mutex_unlock(&mdsc->mutex); + /* send request */ req->r_resend_mds =3D -1; /* forget any previous mds hint */ =20 @@ -3800,6 +3807,7 @@ static void __do_request(struct ceph_mds_client *mdsc, err =3D wait_on_bit(&di->flags, CEPH_DENTRY_ASYNC_CREATE_BIT, TASK_KILLABLE); if (err) { + mutex_lock(&mdsc->mutex); mutex_lock(&req->r_fill_mutex); set_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags); mutex_unlock(&req->r_fill_mutex); @@ -3837,6 +3845,8 @@ static void __do_request(struct ceph_mds_client *mdsc, =20 err =3D __send_request(session, req, false); =20 + mutex_lock(&mdsc->mutex); + out_session: ceph_put_mds_session(session); finish: @@ -3846,12 +3856,10 @@ static void __do_request(struct ceph_mds_client *md= sc, complete_request(mdsc, req); __unregister_request(mdsc, req); } + mutex_unlock(&mdsc->mutex); return; } =20 -/* - * called under mdsc->mutex - */ static void __wake_requests(struct ceph_mds_client *mdsc, struct list_head *head) { @@ -3969,11 +3977,12 @@ int ceph_mdsc_submit_request(struct ceph_mds_client= *mdsc, struct inode *dir, doutc(cl, "submit_request on %p for inode %p\n", req, dir); mutex_lock(&mdsc->mutex); __register_request(mdsc, req, dir); + mutex_unlock(&mdsc->mutex); + trace_ceph_mdsc_submit_request(mdsc, req); if (!req->r_err) __do_request(mdsc, req); err =3D req->r_err; - mutex_unlock(&mdsc->mutex); return err; } =20 @@ -4346,13 +4355,14 @@ static void handle_forward(struct ceph_mds_client *= mdsc, req->r_num_fwd =3D fwd_seq; req->r_resend_mds =3D next_mds; put_request_session(req); - __do_request(mdsc, req); } mutex_unlock(&mdsc->mutex); =20 /* kick calling process */ if (aborted) complete_request(mdsc, req); + else if (!test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) + __do_request(mdsc, req); ceph_mdsc_put_request(req); return; =20 @@ -4676,11 +4686,9 @@ static void handle_session(struct ceph_mds_session *= session, =20 mutex_unlock(&session->s_mutex); if (wake) { - mutex_lock(&mdsc->mutex); __wake_requests(mdsc, &session->s_waiting); if (wake =3D=3D 2) kick_requests(mdsc, mds); - mutex_unlock(&mdsc->mutex); } if (op =3D=3D CEPH_SESSION_CLOSE) ceph_put_mds_session(session); @@ -5326,9 +5334,7 @@ static int send_mds_reconnect(struct ceph_mds_client = *mdsc, =20 mutex_unlock(&session->s_mutex); =20 - mutex_lock(&mdsc->mutex); __wake_requests(mdsc, &session->s_waiting); - mutex_unlock(&mdsc->mutex); =20 up_read(&mdsc->snap_rwsem); ceph_pagelist_release(recon_state.pagelist); @@ -5773,8 +5779,8 @@ static void ceph_mdsc_reset_workfn(struct work_struct= *work) } sessions[i]->s_state =3D CEPH_MDS_SESSION_CLOSED; __unregister_session(mdsc, sessions[i]); - __wake_requests(mdsc, &sessions[i]->s_waiting); mutex_unlock(&mdsc->mutex); + __wake_requests(mdsc, &sessions[i]->s_waiting); =20 mutex_lock(&sessions[i]->s_mutex); cleanup_session_requests(mdsc, sessions[i]); @@ -5785,9 +5791,7 @@ static void ceph_mdsc_reset_workfn(struct work_struct= *work) =20 ceph_put_mds_session(sessions[i]); =20 - mutex_lock(&mdsc->mutex); kick_requests(mdsc, mds); - mutex_unlock(&mdsc->mutex); =20 torn_down++; pr_info_client(cl, "mds%d session reset complete\n", mds); @@ -5903,8 +5907,8 @@ static void check_new_map(struct ceph_mds_client *mds= c, /* force close session for stopped mds */ ceph_get_mds_session(s); __unregister_session(mdsc, s); - __wake_requests(mdsc, &s->s_waiting); mutex_unlock(&mdsc->mutex); + __wake_requests(mdsc, &s->s_waiting); =20 mutex_lock(&s->s_mutex); cleanup_session_requests(mdsc, s); @@ -5913,8 +5917,8 @@ static void check_new_map(struct ceph_mds_client *mds= c, =20 ceph_put_mds_session(s); =20 - mutex_lock(&mdsc->mutex); kick_requests(mdsc, i); + mutex_lock(&mdsc->mutex); continue; } =20 @@ -5958,8 +5962,8 @@ static void check_new_map(struct ceph_mds_client *mds= c, oldstate !=3D CEPH_MDS_STATE_STARTING) pr_info_client(cl, "mds%d recovery completed\n", s->s_mds); - kick_requests(mdsc, i); mutex_unlock(&mdsc->mutex); + kick_requests(mdsc, i); mutex_lock(&s->s_mutex); mutex_lock(&mdsc->mutex); ceph_kick_flushing_caps(mdsc, s); @@ -6931,8 +6935,8 @@ void ceph_mdsc_force_umount(struct ceph_mds_client *m= dsc) =20 if (session->s_state =3D=3D CEPH_MDS_SESSION_REJECTED) __unregister_session(mdsc, session); - __wake_requests(mdsc, &session->s_waiting); mutex_unlock(&mdsc->mutex); + __wake_requests(mdsc, &session->s_waiting); =20 mutex_lock(&session->s_mutex); __close_session(mdsc, session); @@ -6943,11 +6947,11 @@ void ceph_mdsc_force_umount(struct ceph_mds_client = *mdsc) mutex_unlock(&session->s_mutex); ceph_put_mds_session(session); =20 - mutex_lock(&mdsc->mutex); kick_requests(mdsc, mds); + mutex_lock(&mdsc->mutex); } - __wake_requests(mdsc, &mdsc->waiting_for_map); mutex_unlock(&mdsc->mutex); + __wake_requests(mdsc, &mdsc->waiting_for_map); } =20 static void ceph_mdsc_stop(struct ceph_mds_client *mdsc) @@ -7091,8 +7095,8 @@ void ceph_mdsc_handle_fsmap(struct ceph_mds_client *m= dsc, struct ceph_msg *msg) err_out: mutex_lock(&mdsc->mutex); mdsc->mdsmap_err =3D err; - __wake_requests(mdsc, &mdsc->waiting_for_map); mutex_unlock(&mdsc->mutex); + __wake_requests(mdsc, &mdsc->waiting_for_map); } =20 /* @@ -7143,11 +7147,11 @@ void ceph_mdsc_handle_mdsmap(struct ceph_mds_client= *mdsc, struct ceph_msg *msg) mdsc->fsc->max_file_size =3D min((loff_t)mdsc->mdsmap->m_max_file_size, MAX_LFS_FILESIZE); =20 + mutex_unlock(&mdsc->mutex); __wake_requests(mdsc, &mdsc->waiting_for_map); ceph_monc_got_map(&mdsc->fsc->client->monc, CEPH_SUB_MDSMAP, mdsc->mdsmap->m_epoch); =20 - mutex_unlock(&mdsc->mutex); schedule_delayed(mdsc, 0); return; =20 @@ -7245,8 +7249,8 @@ static void mds_peer_reset(struct ceph_connection *co= n) ceph_get_mds_session(s); s->s_state =3D CEPH_MDS_SESSION_CLOSED; __unregister_session(mdsc, s); - __wake_requests(mdsc, &s->s_waiting); mutex_unlock(&mdsc->mutex); + __wake_requests(mdsc, &s->s_waiting); =20 mutex_lock(&s->s_mutex); cleanup_session_requests(mdsc, s); @@ -7255,9 +7259,7 @@ static void mds_peer_reset(struct ceph_connection *co= n) =20 wake_up_all(&mdsc->session_close_wq); =20 - mutex_lock(&mdsc->mutex); kick_requests(mdsc, s->s_mds); - mutex_unlock(&mdsc->mutex); =20 ceph_put_mds_session(s); break; --=20 2.53.0 From nobody Sat Jul 25 18:01:21 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DE7133B38AB; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784087943; cv=none; b=ZlY5JmRbSPmg+6wl6PfMdN/RL+2owM043yMTrpkJEHBTKcAqQZ6MWulhi8JJq1Kvq9jUshhjhgE88Pa8b0+ZN+LutIgIE4YlE+Td1TVyLzdAyKpv8zxTX6BIdowFDo5VWmfoIguYZBTwX6Z95SG6sVRfVpOhSmDn5+y6gUvDjoQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784087943; c=relaxed/simple; bh=+SUkPvvWUO23/3Jx1OpKd8z7wdxbHpC6y/xTMeP6aI0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jm1t8c8AXRpOoY22yqHZvkEotSpPitRRaCm9wCqkr8kIlTQvmcy3QKkPh/JqNnRLGonMuYRu3QhdyGTk3wi+kLCnOxT93knVAt9QqS79rRzNtKZDe9R9keU2I1+819Vz/D3FGUAsND/EfZnQLhIfQgUuceXCb+oxPmF6HmS8c+Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=VeJd9Qrx; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="VeJd9Qrx" Received: by smtp.kernel.org (Postfix) with ESMTPS id 8C67EC2BCFB; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1784087942; bh=+SUkPvvWUO23/3Jx1OpKd8z7wdxbHpC6y/xTMeP6aI0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=VeJd9QrxoTCnleYCP1vdpqyFfDhom4fw4yVVQ7ZMJmw1ghlY0Sni3wb4PAr+Yklwf fSqwbyFsPQKXxkZ9aLfHXFy5tx9zignG1l7zQax7syai8m16/BwJ+64lrMPLOY/8cK vNbSi7H9FfS/rv41X7AUft2ySnCQprwzEae8geGPfVKl2kJWFM+O9YAoD4K5uj+h6W /zEo7JdwLOKxxQGvV1dvCz6dCSRJQoDBuPMcwBnxdRqFSGMeLForVXESxaC8uDegV4 vJ3ZJAPi+fEgX9hjc2HpfTnxoLW+mB+f83/5EGu7+YwtXv+Pkf0Q6+IHR43CAjhTQv lzNn/msT73A1w== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7CA47C4450B; Wed, 15 Jul 2026 03:59:02 +0000 (UTC) From: Xiubo Li via B4 Relay Date: Wed, 15 Jul 2026 11:58:45 +0800 Subject: [PATCH v2 5/5] ceph: narrow mdsc->mutex scope in replay_unsafe_requests Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260715-ceph-mdsc-mutex-optimization-v2-5-90e81b726724@clyso.com> References: <20260715-ceph-mdsc-mutex-optimization-v2-0-90e81b726724@clyso.com> In-Reply-To: <20260715-ceph-mdsc-mutex-optimization-v2-0-90e81b726724@clyso.com> To: Ilya Dryomov , Alex Markuze , Viacheslav Dubeyko Cc: ceph-devel@vger.kernel.org, linux-kernel@vger.kernel.org, Xiubo Li X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1784087938; l=3210; i=xiubo.li@clyso.com; s=20260625; h=from:subject:message-id; bh=V6Rwu7aHfIW8x0x76qZaMXOB1fkfzmlqcq+V2RGl5oI=; b=FIsjpUqPWfrOuyahZ7cKIGiLoVTn4OvhNnZBI/JH4w3nt8Jq6+7SmkDzSBcAf6eJF39Wp8ojZ K5qkHU0/IIKCp8tzchKuWbrw4R2JqsGy7C3gSHjeTRdkVqCSy+0YU8L X-Developer-Key: i=xiubo.li@clyso.com; a=ed25519; pk=V3NGr0AgAopiUhaLY51ipBkLN5LlcLhjOEfLEq1RoZ8= X-Endpoint-Received: by B4 Relay for xiubo.li@clyso.com/20260625 with auth_id=840 X-Original-From: Xiubo Li Reply-To: xiubo.li@clyso.com From: Xiubo Li __send_request() is lockless so holding mdsc->mutex across the replay loop only serializes the list iteration itself. Collect the unsafe list entries under the mutex, then replay them without it. The old-request tree walk uses xa_for_each() which is internally locked. Signed-off-by: Xiubo Li --- fs/ceph/mds_client.c | 51 ++++++++++++++++++++++++++++++++++++++++++++----= --- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index be0dae919d69..c313574def74 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -4744,30 +4744,66 @@ static void replay_unsafe_requests(struct ceph_mds_= client *mdsc, #else struct rb_node *p; #endif + LIST_HEAD(replay_list); =20 doutc(mdsc->fsc->client, "mds%d\n", session->s_mds); =20 +#if BITS_PER_LONG =3D=3D 64 + /* collect unsafe requests under the mutex */ mutex_lock(&mdsc->mutex); - list_for_each_entry_safe(req, nreq, &session->s_unsafe, r_unsafe_item) + list_for_each_entry_safe(req, nreq, &session->s_unsafe, + r_unsafe_item) { + ceph_mdsc_get_request(req); + list_move(&req->r_unsafe_item, &replay_list); + } + mutex_unlock(&mdsc->mutex); + + /* replay unsafe requests (local list, no mutex needed) */ + list_for_each_entry_safe(req, nreq, &replay_list, r_unsafe_item) { __send_request(session, req, true); + list_del_init(&req->r_unsafe_item); + ceph_mdsc_put_request(req); + } =20 /* - * also re-send old requests when MDS enters reconnect stage. So that MDS - * can process completed request in clientreplay stage. + * also re-send old requests when MDS enters reconnect stage. + * xa_for_each() is internally locked. */ -#if BITS_PER_LONG =3D=3D 64 idx =3D 0; xa_for_each(&mdsc->request_tree, idx, req) { -#else + if (test_bit(CEPH_MDS_R_GOT_UNSAFE, &req->r_req_flags)) + continue; + if (req->r_attempts =3D=3D 0) + continue; + if (!req->r_session) + continue; + if (req->r_session->s_mds !=3D session->s_mds) + continue; + + ceph_mdsc_release_dir_caps_async(req); + + ceph_mdsc_get_request(req); + __send_request(session, req, true); + ceph_mdsc_put_request(req); + } +#else /* BITS_PER_LONG !=3D 64 =E2=80=94 keep mutex for rb-tree iteration = */ + mutex_lock(&mdsc->mutex); + list_for_each_entry_safe(req, nreq, &session->s_unsafe, + r_unsafe_item) + __send_request(session, req, true); + + /* + * also re-send old requests when MDS enters reconnect stage. + * Must hold mutex for rb_first()/rb_next(). + */ p =3D rb_first(&mdsc->request_tree); while (p) { req =3D rb_entry(p, struct ceph_mds_request, r_node); p =3D rb_next(p); -#endif if (test_bit(CEPH_MDS_R_GOT_UNSAFE, &req->r_req_flags)) continue; if (req->r_attempts =3D=3D 0) - continue; /* only old requests */ + continue; if (!req->r_session) continue; if (req->r_session->s_mds !=3D session->s_mds) @@ -4778,6 +4814,7 @@ static void replay_unsafe_requests(struct ceph_mds_cl= ient *mdsc, __send_request(session, req, true); } mutex_unlock(&mdsc->mutex); +#endif } =20 static int send_reconnect_partial(struct ceph_reconnect_state *recon_state) --=20 2.53.0