From nobody Sun Apr 5 16:21:07 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 591E0344030; Fri, 20 Feb 2026 12:26:19 +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=1771590379; cv=none; b=PrGOPY3QJUe2YdMgMTbjq+y72F/dAcsMck9OX761a9a7ZEvzFUkovAkTg1susJdyx/ZbYfrA4Z4I64zYTjYUaOlDyGtYwkF/OoLeDjXTByqFFJzgOYYHo2zeoulf3Jcn9dW20KMGDKncD4PwjpY1zlK/HbbHaK/xyH4peQU5m3Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771590379; c=relaxed/simple; bh=m1c8dJhQxsPdS1HZ45hz/jGJrNNSoR81GQDVypuwaNE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=bFkpgviVv0b9PYbjn+7/dRTjMd+MvYSPdsPgTPIWWVZYKLZULo0NQ53W2+xitcXUMaTsGiNYF/vyarFlxNmDX4hQ0tFrRo+rOhu9DamCg79q3/dFHpuP0WkjM4SgQy6JVGlmygo+qxyDA5hqxBj7jxxyAWPAqF0079oZwgU7YYg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=LQ8UB1WR; 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="LQ8UB1WR" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 54B8DC116D0; Fri, 20 Feb 2026 12:26:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1771590379; bh=m1c8dJhQxsPdS1HZ45hz/jGJrNNSoR81GQDVypuwaNE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=LQ8UB1WRQ9hSOJJww9QnQhOpAtg9AFnRcF1SvhV0ALhT7QSK6EwNI3EFEtDtPHE9b McxPHggVSZ2j8tRro75nwcHsu0t30SqItmX52oMnIQ2ED7ufUvHFK2n1eZaVIfzzm/ AwAMpKQw8feWB8Y1X2jRrpyNMDjSg22QwkTkI4R7j7OuewGy5aSkNtKMvsAvl6LCaZ X1SI+5+lwq8FsFLbb7Lc//8UA8LvSIENA+YmHWOB5HittfuZdG9d1TTRs95hBJfuWo RsSRWI6qwOOt2tDBN5mylwBRGV0hHa4npQktbKjoRCKC5ZLyGNl7fKJpv5YbtrVTA0 Ej/1U2MV3hLEQ== From: Jeff Layton Date: Fri, 20 Feb 2026 07:26:03 -0500 Subject: [PATCH 1/3] sunrpc: convert queue_lock from global spinlock to per-cache_detail lock 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: <20260220-sunrpc-cache-v1-1-47d04014c245@kernel.org> References: <20260220-sunrpc-cache-v1-0-47d04014c245@kernel.org> In-Reply-To: <20260220-sunrpc-cache-v1-0-47d04014c245@kernel.org> To: Chuck Lever , NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker Cc: linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=7381; i=jlayton@kernel.org; h=from:subject:message-id; bh=m1c8dJhQxsPdS1HZ45hz/jGJrNNSoR81GQDVypuwaNE=; b=kA0DAAoBAA5oQRlWghUByyZiAGmYUuiiozk78cE9mBaz/DRpzSO/YrWNR8yN2072G6z/dhI1E 4kCMwQAAQoAHRYhBEvA17JEcbKhhOr10wAOaEEZVoIVBQJpmFLoAAoJEAAOaEEZVoIVjGoQAKAL Iq4fJFDFUWAaEt+A6N3DaL/CeTzmrvTGteqjjRNXIUE+12jA1/ygUibi8lSbytuuRGNwKF9sqPN aXYTxRbCh81RaepK2iSC8ofdBMFezCSydqOmTru34RecuAJoX8Nio07zQdDVavYkh2WmCyKQaDI cr1D2f1czPdp5PhWDha9WhpR420izQOiPq6fB47NxQa37PoM23gCmVFb08ot2Ira7Nwj9kZMI9T V7x+TvEbxmneQvf1fWaljes06jugRkvfgAR6MTII2jEgEF0mL/AgSa0rSO7UwS4c+0Tdr8hO8wB ZkaIaPfoceAZbxTL6TJZspjBqfP0/+riyA4GT1e3BKFSiHKQtu2eAtIomyA9IriCGgDl/lXTvpF qG7WJU4RsRQDVGM3SPbrlSlD76y5sUWW5vgKkA2VXc+Sp6BE7ze28q9T9Z5iHfqqcyEBPyh/maJ T6nLXmIoUFRTWVwm6zqW+Scp31Zu/0L5l7fDP8An4mrrQAUk5I8Cg7RlhwS/eY4tpjaTkRxAEo2 Wdi6/GAzIGJc/Nb/wNMTGHxjkp+XkzmwJZUjCvXFkelWsy1/Ne6TxLG48V67ZmqRbXHWcPxa7gI Jz/1kj1gfGjHO/ny/wCTlTb9sYB9Z6VR5Lnval+bshRNWj7+tZZ6U+DcCec7SEhU6FsJWMs2stW PijiS X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 The global queue_lock serializes all upcall queue operations across every cache_detail instance. Convert it to a per-cache_detail spinlock so that different caches (e.g. auth.unix.ip vs nfsd.fh) no longer contend with each other on queue operations. Signed-off-by: Jeff Layton --- include/linux/sunrpc/cache.h | 1 + net/sunrpc/cache.c | 47 ++++++++++++++++++++++------------------= ---- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index e783132e481ff2593fdc5d323f7b3a08f85d4cd8..3d32dd1f7b05d35562d2064fed6= 9877b3950fb51 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -113,6 +113,7 @@ struct cache_detail { =20 /* fields for communication over channel */ struct list_head queue; + spinlock_t queue_lock; =20 atomic_t writers; /* how many time is /channel open */ time64_t last_close; /* if no writers, when did last close */ diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 7c73d1c39687343db02d1f1423b58213b7a35f42..6add2fe311425dc3aec63efce2c= 4bed06a3d3ba5 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -400,6 +400,7 @@ void sunrpc_init_cache_detail(struct cache_detail *cd) { spin_lock_init(&cd->hash_lock); INIT_LIST_HEAD(&cd->queue); + spin_lock_init(&cd->queue_lock); spin_lock(&cache_list_lock); cd->nextcheck =3D 0; cd->entries =3D 0; @@ -803,8 +804,6 @@ void cache_clean_deferred(void *owner) * */ =20 -static DEFINE_SPINLOCK(queue_lock); - struct cache_queue { struct list_head list; int reader; /* if 0, then request */ @@ -847,7 +846,7 @@ static ssize_t cache_read(struct file *filp, char __use= r *buf, size_t count, inode_lock(inode); /* protect against multiple concurrent * readers on this file */ again: - spin_lock(&queue_lock); + spin_lock(&cd->queue_lock); /* need to find next request */ while (rp->q.list.next !=3D &cd->queue && list_entry(rp->q.list.next, struct cache_queue, list) @@ -856,7 +855,7 @@ static ssize_t cache_read(struct file *filp, char __use= r *buf, size_t count, list_move(&rp->q.list, next); } if (rp->q.list.next =3D=3D &cd->queue) { - spin_unlock(&queue_lock); + spin_unlock(&cd->queue_lock); inode_unlock(inode); WARN_ON_ONCE(rp->offset); return 0; @@ -865,7 +864,7 @@ static ssize_t cache_read(struct file *filp, char __use= r *buf, size_t count, WARN_ON_ONCE(rq->q.reader); if (rp->offset =3D=3D 0) rq->readers++; - spin_unlock(&queue_lock); + spin_unlock(&cd->queue_lock); =20 if (rq->len =3D=3D 0) { err =3D cache_request(cd, rq); @@ -876,9 +875,9 @@ static ssize_t cache_read(struct file *filp, char __use= r *buf, size_t count, =20 if (rp->offset =3D=3D 0 && !test_bit(CACHE_PENDING, &rq->item->flags)) { err =3D -EAGAIN; - spin_lock(&queue_lock); + spin_lock(&cd->queue_lock); list_move(&rp->q.list, &rq->q.list); - spin_unlock(&queue_lock); + spin_unlock(&cd->queue_lock); } else { if (rp->offset + count > rq->len) count =3D rq->len - rp->offset; @@ -888,26 +887,26 @@ static ssize_t cache_read(struct file *filp, char __u= ser *buf, size_t count, rp->offset +=3D count; if (rp->offset >=3D rq->len) { rp->offset =3D 0; - spin_lock(&queue_lock); + spin_lock(&cd->queue_lock); list_move(&rp->q.list, &rq->q.list); - spin_unlock(&queue_lock); + spin_unlock(&cd->queue_lock); } err =3D 0; } out: if (rp->offset =3D=3D 0) { /* need to release rq */ - spin_lock(&queue_lock); + spin_lock(&cd->queue_lock); rq->readers--; if (rq->readers =3D=3D 0 && !test_bit(CACHE_PENDING, &rq->item->flags)) { list_del(&rq->q.list); - spin_unlock(&queue_lock); + spin_unlock(&cd->queue_lock); cache_put(rq->item, cd); kfree(rq->buf); kfree(rq); } else - spin_unlock(&queue_lock); + spin_unlock(&cd->queue_lock); } if (err =3D=3D -EAGAIN) goto again; @@ -988,7 +987,7 @@ static __poll_t cache_poll(struct file *filp, poll_tabl= e *wait, if (!rp) return mask; =20 - spin_lock(&queue_lock); + spin_lock(&cd->queue_lock); =20 for (cq=3D &rp->q; &cq->list !=3D &cd->queue; cq =3D list_entry(cq->list.next, struct cache_queue, list)) @@ -996,7 +995,7 @@ static __poll_t cache_poll(struct file *filp, poll_tabl= e *wait, mask |=3D EPOLLIN | EPOLLRDNORM; break; } - spin_unlock(&queue_lock); + spin_unlock(&cd->queue_lock); return mask; } =20 @@ -1011,7 +1010,7 @@ static int cache_ioctl(struct inode *ino, struct file= *filp, if (cmd !=3D FIONREAD || !rp) return -EINVAL; =20 - spin_lock(&queue_lock); + spin_lock(&cd->queue_lock); =20 /* only find the length remaining in current request, * or the length of the next request @@ -1024,7 +1023,7 @@ static int cache_ioctl(struct inode *ino, struct file= *filp, len =3D cr->len - rp->offset; break; } - spin_unlock(&queue_lock); + spin_unlock(&cd->queue_lock); =20 return put_user(len, (int __user *)arg); } @@ -1046,9 +1045,9 @@ static int cache_open(struct inode *inode, struct fil= e *filp, rp->offset =3D 0; rp->q.reader =3D 1; =20 - spin_lock(&queue_lock); + spin_lock(&cd->queue_lock); list_add(&rp->q.list, &cd->queue); - spin_unlock(&queue_lock); + spin_unlock(&cd->queue_lock); } if (filp->f_mode & FMODE_WRITE) atomic_inc(&cd->writers); @@ -1062,7 +1061,7 @@ static int cache_release(struct inode *inode, struct = file *filp, struct cache_reader *rp =3D filp->private_data; =20 if (rp) { - spin_lock(&queue_lock); + spin_lock(&cd->queue_lock); if (rp->offset) { struct cache_queue *cq; for (cq=3D &rp->q; &cq->list !=3D &cd->queue; @@ -1075,7 +1074,7 @@ static int cache_release(struct inode *inode, struct = file *filp, rp->offset =3D 0; } list_del(&rp->q.list); - spin_unlock(&queue_lock); + spin_unlock(&cd->queue_lock); =20 filp->private_data =3D NULL; kfree(rp); @@ -1097,7 +1096,7 @@ static void cache_dequeue(struct cache_detail *detail= , struct cache_head *ch) struct cache_request *cr; LIST_HEAD(dequeued); =20 - spin_lock(&queue_lock); + spin_lock(&detail->queue_lock); list_for_each_entry_safe(cq, tmp, &detail->queue, list) if (!cq->reader) { cr =3D container_of(cq, struct cache_request, q); @@ -1110,7 +1109,7 @@ static void cache_dequeue(struct cache_detail *detail= , struct cache_head *ch) continue; list_move(&cr->q.list, &dequeued); } - spin_unlock(&queue_lock); + spin_unlock(&detail->queue_lock); while (!list_empty(&dequeued)) { cr =3D list_entry(dequeued.next, struct cache_request, q.list); list_del(&cr->q.list); @@ -1235,7 +1234,7 @@ static int cache_pipe_upcall(struct cache_detail *det= ail, struct cache_head *h) crq->buf =3D buf; crq->len =3D 0; crq->readers =3D 0; - spin_lock(&queue_lock); + spin_lock(&detail->queue_lock); if (test_bit(CACHE_PENDING, &h->flags)) { crq->item =3D cache_get(h); list_add_tail(&crq->q.list, &detail->queue); @@ -1243,7 +1242,7 @@ static int cache_pipe_upcall(struct cache_detail *det= ail, struct cache_head *h) } else /* Lost a race, no longer PENDING, so don't enqueue */ ret =3D -EAGAIN; - spin_unlock(&queue_lock); + spin_unlock(&detail->queue_lock); wake_up(&queue_wait); if (ret =3D=3D -EAGAIN) { kfree(buf); --=20 2.53.0