* [PATCH 6.12 001/670] smb: client: validate the data area in SMB2_read()
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 002/670] rxrpc: Fix update of call->tx_pending without holding lock Greg Kroah-Hartman
` (670 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Abdifatah Suruur, Namjae Jeon,
Paulo Alcantara, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdifatah Suruur <suruurism@gmail.com>
[ Upstream commit 2ec9cdf469dd32bcf33073aeb30c08e9356e0ca1 ]
SMB2_read() copies le32_to_cpu(rsp->DataLength) bytes from
(char *)rsp + rsp->DataOffset without checking that the range lies
within the response actually received. A READ response with
DataOffset == 0 makes smb2_get_data_area_len() zero the data length, so
smb2_check_message() accepts a frame as short as the fixed response,
while SMB2_read() still uses the server-supplied DataLength, capped only
by CIFS_MAX_MSGSIZE and the caller's length.
A malicious server can answer the synchronous read used by the
mfsymlinks (or SFU) symlink parser with an 81-byte READ response
carrying DataOffset 0 and DataLength 1067, making the client copy 1067
bytes from a 448-byte receive object (KASAN slab-out-of-bounds; up to
16 KiB in the general case).
Clamp a zero (or header-overlapping) DataOffset to read_rsp_size, as
handle_read_data() does for the asynchronous path, and reject the
response unless DataOffset + DataLength fits within rsp_iov.iov_len.
The SMB1 helper was fixed the same way in 5be5bdda5863.
Fixes: d8e050398d23 ("CIFS: Add readpage support for SMB2")
Cc: stable@vger.kernel.org
Signed-off-by: Abdifatah Suruur <suruurism@gmail.com>
Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
[ sashal: replaced the unavailable smb_EIO2() tracing helper call with rc = -EIO ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/smb2pdu.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index cb164f87f9082..bcfb75fab2c72 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -4792,6 +4792,7 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
struct kvec iov[1];
struct kvec rsp_iov;
unsigned int total_len;
+ u16 data_offset;
int flags = CIFS_LOG_ERROR;
struct cifs_ses *ses = io_parms->tcon->ses;
@@ -4850,8 +4851,28 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
*nbytes = 0;
}
+ data_offset = rsp->DataOffset;
+ if (data_offset < io_parms->server->vals->read_rsp_size) {
+ /*
+ * win2k8 sometimes sends an offset of 0 when the read is beyond
+ * the EOF. Treat it as if the data starts just after the header,
+ * as handle_read_data() does.
+ */
+ cifs_dbg(FYI, "data offset %u inside read response header\n",
+ data_offset);
+ data_offset = io_parms->server->vals->read_rsp_size;
+ }
+
+ /* The data area must lie within the response actually received */
+ if (*nbytes && (size_t)data_offset + *nbytes > rsp_iov.iov_len) {
+ cifs_dbg(FYI, "bad data offset %u length %u for response of %zu\n",
+ data_offset, *nbytes, rsp_iov.iov_len);
+ rc = -EIO;
+ *nbytes = 0;
+ }
+
if (*buf) {
- memcpy(*buf, (char *)rsp + rsp->DataOffset, *nbytes);
+ memcpy(*buf, (char *)rsp + data_offset, *nbytes);
free_rsp_buf(resp_buftype, rsp_iov.iov_base);
} else if (resp_buftype != CIFS_NO_BUFFER) {
*buf = rsp_iov.iov_base;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 002/670] rxrpc: Fix update of call->tx_pending without holding lock
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 001/670] smb: client: validate the data area in SMB2_read() Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 003/670] ALSA: x86: hdmi: fix chmap array missing terminator entry Greg Kroah-Hartman
` (669 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Marc Dionne,
Eric Dumazet, David S. Miller, Jakub Kicinski, Paolo Abeni,
Simon Horman, linux-afs, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit 7801c42c3bb737cfb06194a383873fcad8daacf5 ]
Currently, rxrpc_send_data() updates call->tx_pending just before it
returns - but it won't be holding the call->user_mutex when it does this if
a wait was interrupted by a signal. This would allow a parallel sendmsg()
to race.
Further, both the callers of rxrpc_send_data() call it with the lock held,
and then it returns an indication through the parameter list to say whether
it has dropped the lock or not - after which the callers both just drop the
lock if it's still held.
Fix this by:
(1) Moving the release of call->user_mutex down into rxrpc_send_data() and
get rid of the indicator parameter. This makes it easier to see where
the lock is held.
(2) After waiting, if the attempt to reacquire the mutex is interrupted,
just return directly there rather than going to out_unlock
(3) Restricting the txb variable to inside the buffering loop and leaving
->tx_pending set until we've queued the buffer.
Note that there's a slight change in behaviour in that wait_for_space
failure now doesn't check for completion because it doesn't hold the call
user_mutex. The caller, however, should re-issue the send and pick up any
error at a second attempt.
Fixes: b0f571ecd794 ("rxrpc: Fix locking in rxrpc's sendmsg")
Closes: https://sashiko.dev/#/patchset/20260702144919.172295-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20261006133011.531806-4-dhowells@redhat.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
[ sashal: adapted exit handling for code lacking RXRPC_CALL_TX_NO_MORE while preserving existing packet-length bookkeeping and the caller’s if/else structure ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/rxrpc/sendmsg.c | 59 +++++++++++++++++++++------------------------
1 file changed, 27 insertions(+), 32 deletions(-)
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index c9b85848e825b..9d68e58dace9c 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -279,10 +279,9 @@ static void rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call,
static int rxrpc_send_data(struct rxrpc_sock *rx,
struct rxrpc_call *call,
struct msghdr *msg, size_t len,
- rxrpc_notify_end_tx_t notify_end_tx,
- bool *_dropped_lock)
+ rxrpc_notify_end_tx_t notify_end_tx)
+ __releases(&call->user_mutex)
{
- struct rxrpc_txbuf *txb;
struct sock *sk = &rx->sk;
enum rxrpc_call_state state;
long timeo;
@@ -293,23 +292,18 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
ret = rxrpc_wait_to_be_connected(call, &timeo);
if (ret < 0)
- return ret;
+ goto out_unlock;
if (call->conn->state == RXRPC_CONN_CLIENT_UNSECURED) {
ret = rxrpc_init_client_conn_security(call->conn);
if (ret < 0)
- return ret;
+ goto out_unlock;
}
/* this should be in poll */
sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
reload:
- txb = call->tx_pending;
- call->tx_pending = NULL;
- if (txb)
- rxrpc_see_txbuf(txb, rxrpc_txbuf_see_send_more);
-
ret = -EPIPE;
if (sk->sk_shutdown & SEND_SHUTDOWN)
goto maybe_error;
@@ -337,6 +331,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
}
do {
+ struct rxrpc_txbuf *txb = call->tx_pending;
+
if (!txb) {
size_t remain;
@@ -355,6 +351,9 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
ret = -ENOMEM;
goto maybe_error;
}
+ call->tx_pending = txb;
+ } else {
+ rxrpc_see_txbuf(txb, rxrpc_txbuf_see_send_more);
}
_debug("append");
@@ -392,12 +391,12 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
ret = call->security->secure_packet(call, txb);
if (ret < 0)
- goto out;
+ goto out_unlock;
txb->kvec[0].iov_len += txb->len;
txb->len = txb->kvec[0].iov_len;
rxrpc_queue_packet(rx, call, txb, notify_end_tx);
- txb = NULL;
+ call->tx_pending = NULL;
}
} while (msg_data_left(msg) > 0);
@@ -406,45 +405,46 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
if (rxrpc_call_is_complete(call) &&
call->error < 0)
ret = call->error;
-out:
- call->tx_pending = txb;
+out_unlock:
+ mutex_unlock(&call->user_mutex);
_leave(" = %d", ret);
return ret;
call_terminated:
- rxrpc_put_txbuf(txb, rxrpc_txbuf_put_send_aborted);
- _leave(" = %d", call->error);
- return call->error;
+ ret = call->error;
+ goto out_unlock;
maybe_error:
if (copied)
goto success;
- goto out;
+ goto out_unlock;
efault:
ret = -EFAULT;
- goto out;
+ goto out_unlock;
wait_for_space:
ret = -EAGAIN;
if (msg->msg_flags & MSG_DONTWAIT)
goto maybe_error;
mutex_unlock(&call->user_mutex);
- *_dropped_lock = true;
+
ret = rxrpc_wait_for_tx_window(rx, call, &timeo,
msg->msg_flags & MSG_WAITALL);
if (ret < 0)
- goto maybe_error;
+ goto out_nolock;
if (call->interruptibility == RXRPC_INTERRUPTIBLE) {
if (mutex_lock_interruptible(&call->user_mutex) < 0) {
ret = sock_intr_errno(timeo);
- goto maybe_error;
+ goto out_nolock;
}
} else {
mutex_lock(&call->user_mutex);
}
- *_dropped_lock = false;
goto reload;
+out_nolock:
+ _leave(" = %d [intr]", ret);
+ return copied ?: ret;
}
/*
@@ -611,7 +611,6 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
__releases(&rx->sk.sk_lock.slock)
{
struct rxrpc_call *call;
- bool dropped_lock = false;
int ret;
struct rxrpc_send_params p = {
@@ -717,12 +716,12 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
} else if (p.command != RXRPC_CMD_SEND_DATA) {
ret = -EINVAL;
} else {
- ret = rxrpc_send_data(rx, call, msg, len, NULL, &dropped_lock);
+ ret = rxrpc_send_data(rx, call, msg, len, NULL);
+ goto error_put;
}
out_put_unlock:
- if (!dropped_lock)
- mutex_unlock(&call->user_mutex);
+ mutex_unlock(&call->user_mutex);
error_put:
rxrpc_put_call(call, rxrpc_call_put_sendmsg);
_leave(" = %d", ret);
@@ -752,7 +751,6 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
struct msghdr *msg, size_t len,
rxrpc_notify_end_tx_t notify_end_tx)
{
- bool dropped_lock = false;
int ret;
_enter("{%d},", call->debug_id);
@@ -763,12 +761,9 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
mutex_lock(&call->user_mutex);
ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len,
- notify_end_tx, &dropped_lock);
+ notify_end_tx);
if (ret == -ESHUTDOWN)
ret = call->error;
-
- if (!dropped_lock)
- mutex_unlock(&call->user_mutex);
_leave(" = %d", ret);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 003/670] ALSA: x86: hdmi: fix chmap array missing terminator entry
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 001/670] smb: client: validate the data area in SMB2_read() Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 002/670] rxrpc: Fix update of call->tx_pending without holding lock Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 004/670] backing-file: always end a queued write Greg Kroah-Hartman
` (668 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Peter Ujfalusi, Takashi Iwai,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
[ Upstream commit f5e1a9a3fddab8421416b68bb132ae9626d07156 ]
had_build_channel_allocation_map() allocates a single struct
snd_pcm_chmap_elem via kzalloc() and stores it as
intelhaddata->chmap->chmap. struct snd_pcm_chmap.chmap is expected to
be a zero-terminated array (see snd_pcm_std_chmaps[]), but
had_register_chmap_ctls() never overrides the TLV callback installed
by snd_pcm_add_chmap_ctls(), so the generic pcm_chmap_ctl_tlv() from
ALSA core is left in place.
pcm_chmap_ctl_tlv() is reachable by any local user via
SNDRV_CTL_IOCTL_TLV_READ on the "Playback Channel Map" control and
walks the array with "for (map = info->chmap; map->channels; map++)".
Since the driver's single element is never terminated, this walks
past the allocation. The same pointer is also freed on hot-unplug and
rebuilt on hot-plug under intelhaddata->mutex, while the TLV callback
runs under card->controls_rwsem without that mutex, so the walk can
also race a concurrent free of the array.
Fix this by allocating a second, zeroed element so the array is
properly terminated, and by dropping the inherited TLV callback
entirely at registration time, since the driver never implements one
of its own.
Fixes: 5dab11d89777 ("ALSA: x86: hdmi: Add audio support for BYT and CHT")
Cc: stable@vger.kernel.org
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Link: https://patch.msgid.link/20261008085411.13742-1-peter.ujfalusi@linux.intel.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
[ sashal: adjusted context for the existing kzalloc(sizeof(*chmap), GFP_KERNEL) call instead of kzalloc_obj() ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/x86/intel_hdmi_audio.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c
index 571a092b128a2..3c8f1793522ae 100644
--- a/sound/x86/intel_hdmi_audio.c
+++ b/sound/x86/intel_hdmi_audio.c
@@ -479,7 +479,8 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
kfree(intelhaddata->chmap->chmap);
intelhaddata->chmap->chmap = NULL;
- chmap = kzalloc(sizeof(*chmap), GFP_KERNEL);
+ /* info->chmap must be zero-terminated; allocate a spare terminator entry */
+ chmap = kzalloc_objs(*chmap, 2);
if (!chmap)
return;
@@ -582,6 +583,12 @@ static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata,
intelhaddata->chmap->kctl->info = had_chmap_ctl_info;
intelhaddata->chmap->kctl->get = had_chmap_ctl_get;
intelhaddata->chmap->chmap = NULL;
+
+ /* drop the inherited TLV read: it walks chmap without our mutex */
+ intelhaddata->chmap->kctl->tlv.c = NULL;
+ intelhaddata->chmap->kctl->vd[0].access &=
+ ~(SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
+
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 004/670] backing-file: always end a queued write
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (2 preceding siblings ...)
2026-11-13 15:42 ` [PATCH 6.12 003/670] ALSA: x86: hdmi: fix chmap array missing terminator entry Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 005/670] net: limit priority VLAN untag depth Greg Kroah-Hartman
` (667 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Chris Mason, Amir Goldstein,
Christian Brauner (Amutable), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Mason <mason@kernel.org>
commit 627cdcbc2a2eceb0452078a0c14370f9f1f17a91 upstream.
Writes to a loop device with direct I/O on an overlay file make the
next freeze of the upper filesystem hang for ever.
Every kiocb_start_write() needs a kiocb_end_write(). For a write that
is queued, vfs_iocb_iter_write() leaves the end to the completion, and
backing_aio_rw_complete() only calls kiocb_end_write() when IOCB_WRITE
is set in the flags copied from the submitter. In-kernel submitters
such as loop do not set that flag, so each queued write keeps the
freeze protection of the backing filesystem.
Direct writes to a loop device with direct I/O backed by an overlay
file left fsfreeze of the ext4 upper filesystem, and a later touch
there, blocked in D state. It takes write access to the node of the
loop device, which root has by default, to attach the file and to write.
The fix used here is to mark a write in struct backing_aio and to call
kiocb_end_write() on completion of every marked write.
Reproduced under qemu without KVM, on v7.3-rc6-21-g602042bf29f6 with
earlier fixes of this series applied, with and without this change,
once each. The kernel was not changed for the run. With this change
fsfreeze finished in about a second. Not run: the nvmet and LIO file
backends, which do not set IOCB_WRITE either, FUSE passthrough, and an
xfs upper filesystem.
Fixes: 2406a307ac7d ("ovl: implement async IO routines")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[amir: use aio->is_write to explicitly mark a write aio]
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Link: https://patch.msgid.link/20261029180319.2852090-1-amir73il@gmail.com
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/backing-file.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/fs/backing-file.c b/fs/backing-file.c
index cad40411c63e9..2ed8f17aa5f48 100644
--- a/fs/backing-file.c
+++ b/fs/backing-file.c
@@ -83,6 +83,7 @@ struct backing_aio {
refcount_t ref;
struct kiocb *orig_iocb;
/* used for aio completion */
+ bool is_write;
void (*end_write)(struct file *, loff_t, ssize_t);
struct work_struct work;
long res;
@@ -123,7 +124,8 @@ static void backing_aio_rw_complete(struct kiocb *iocb, long res)
struct backing_aio *aio = container_of(iocb, struct backing_aio, iocb);
struct kiocb *orig_iocb = aio->orig_iocb;
- if (iocb->ki_flags & IOCB_WRITE)
+ /* Pairs with kiocb_start_write() in vfs_iocb_iter_write() */
+ if (aio->is_write)
kiocb_end_write(iocb);
backing_aio_cleanup(aio, res);
@@ -256,6 +258,7 @@ ssize_t backing_file_write_iter(struct file *file, struct iov_iter *iter,
goto out;
aio->orig_iocb = iocb;
+ aio->is_write = true;
aio->end_write = ctx->end_write;
kiocb_clone(&aio->iocb, iocb, get_file(file));
aio->iocb.ki_flags = flags;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 005/670] net: limit priority VLAN untag depth
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (3 preceding siblings ...)
2026-11-13 15:42 ` [PATCH 6.12 004/670] backing-file: always end a queued write Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 006/670] nvmet-rdma: fix out-of-bounds write in nvmet_rdma_map_sgl_inline() Greg Kroah-Hartman
` (666 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Willem de Bruijn, Kamil Sawicki,
Kuniyuki Iwashima, Eric Dumazet, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kamil Sawicki <user148783812897@gmail.com>
[ Upstream commit d3ff07f5acc573e5f72bf1c581bae5d05191ba61 ]
The priority VLAN receive path can repeatedly remove VID 0 tags and retry
packet processing. Unlike the read-only VLAN protocol parser, this path has
no limit on the number of nested tags it consumes.
Each skb_vlan_untag() advances skb->data and resets header offsets. The
offsets are stored in 16-bit fields. With enough nested tags, the network
or transport offset can wrap. A later protocol handler can then derive a
large pull length from the wrapped offsets and access memory outside the
skb allocation.
Apply the existing VLAN_MAX_DEPTH limit to the exceptional VID 0 retry.
Count the tag already stored in skb VLAN metadata as the first level, then
stop before untagging a ninth level. Keep the accounting inside this
uncommon branch so the regular VLAN receive path is unaffected.
A single VID 0 priority tag before a real VLAN tag is valid. No normal
deployment was found that intentionally emits multiple consecutive VID 0
tags; permitting eight levels is therefore conservative.
The issue was found while researching the Linux network receive path for
Google kvmCTF, with OpenAI Codex (gpt-5.6-sol) assisting the analysis. The
affected path, reproducer and fix were manually reviewed and tested.
Fixes: 36b2f61a42c2 ("net: handle 802.1P vlan 0 packets properly")
Cc: stable@vger.kernel.org
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Kamil Sawicki <user148783812897@gmail.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Eric Dumazet <edumazet@kernel.org>
Link: https://patch.msgid.link/20261024004835.17862-1-user148783812897@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
[ Backport to 6.12.y: __netif_receive_skb_core() has no local
drop_reason variable, and this branch does not define
SKB_DROP_REASON_RECURSION_LIMIT. Omit the upstream assignment
and keep the existing SKB_DROP_REASON_UNHANDLED_PROTO drop path. ]
Signed-off-by: Kamil Sawicki <user148783812897@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/core/dev.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/net/core/dev.c b/net/core/dev.c
index 397fd0f9cc7a2..058965698004d 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5760,6 +5760,8 @@ static int __netif_receive_skb_core(struct sk_buff **pskb, bool pfmemalloc,
}
if (unlikely(skb_vlan_tag_present(skb)) && !netdev_uses_dsa(skb->dev)) {
+ unsigned int priority_tag_depth = 1;
+
check_vlan_id:
if (skb_vlan_tag_get_id(skb)) {
/* Vlan id is non 0 and vlan_do_receive() above couldn't
@@ -5771,6 +5773,10 @@ static int __netif_receive_skb_core(struct sk_buff **pskb, bool pfmemalloc,
* 802.1Q or 802.1AD and vlan_do_receive() above could
* not find vlan dev for vlan id 0.
*/
+ if (unlikely(priority_tag_depth >= VLAN_MAX_DEPTH))
+ goto drop;
+
+ priority_tag_depth++;
__vlan_hwaccel_clear_tag(skb);
skb = skb_vlan_untag(skb);
if (unlikely(!skb))
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 006/670] nvmet-rdma: fix out-of-bounds write in nvmet_rdma_map_sgl_inline()
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (4 preceding siblings ...)
2026-11-13 15:42 ` [PATCH 6.12 005/670] net: limit priority VLAN untag depth Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 007/670] Revert "net: advertise TCP MSS from the configured MTU, not the learned PMTU" Greg Kroah-Hartman
` (665 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bryam Vargas, Keith Busch,
Andrew Stellman, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrew Stellman <astellman@stellman-greene.com>
[ Upstream commit d1512773a0d539669440bd9f6d050b8e12923b5f ]
nvmet_rdma_map_sgl_inline() bounds the host-supplied in-capsule SGL
offset with "off + len > inline_data_size", evaluated in 64-bit
arithmetic. off is taken straight from the host SGL descriptor
(le64_to_cpu(sgl->addr)) and len is promoted to 64-bit, so the sum
wraps: an off within len of 2^64 makes it small and the check passes.
off is then used as page_idx = off / PAGE_SIZE to index the fixed-size
rsp->cmd->inline_sg[] array (NVMET_RDMA_MAX_INLINE_SGE entries), so a
crafted offset yields an out-of-bounds scatterlist index that is written
through in nvmet_rdma_use_inline_sg().
The mapping runs while handling a received capsule, before the command
executes, so a remote RDMA peer can reach it (the Connect capsule is a
write and takes this path on a queue that has no controller yet). The
host controls only the low bits of the resulting displacement, so the
expected impact is an out-of-bounds write that faults the target
(remote denial of service).
This wrap was reported, with a KASAN reproduction, on linux-nvme in May,
and the check below was suggested in that thread. The fix that was
applied, 48c0162f647b, reworked how the offset is mapped but kept the
original check, and its page index turns a wrapped offset into an
out-of-bounds index into inline_sg[].
Reject the offset before it can wrap.
Found independently by static analysis with AI assistance, not
reproduced at runtime.
Fixes: 0d5ee2b2ab4f ("nvmet-rdma: support max(16KB, PAGE_SIZE) inline data")
Fixes: 48c0162f647b ("nvmet-rdma: handle inline data with a nonzero offset")
Reported-by: Bryam Vargas <hexlabsecurity@proton.me>
Closes: https://lore.kernel.org/all/LM21QIR-1-qJb7PViyJKCnGBnUzizeiNJVWQ3wb7ZwGezodjgKg3f-iobqOyequ-sT1jFCKJImfqNO_BKU3KO80xFITnaI5GTV_GxLUNDDc=@proton.me/
Suggested-by: Keith Busch <kbusch@kernel.org>
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5
Signed-off-by: Andrew Stellman <astellman@stellman-greene.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/nvme/target/rdma.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index 01b7722afb5e8..290b51fef0b98 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -864,7 +864,8 @@ static u16 nvmet_rdma_map_sgl_inline(struct nvmet_rdma_rsp *rsp)
return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
}
- if (off + len > rsp->queue->dev->inline_data_size) {
+ if (off > (u64)rsp->queue->dev->inline_data_size ||
+ len > (u64)rsp->queue->dev->inline_data_size - off) {
pr_err("invalid inline data offset!\n");
return NVME_SC_SGL_INVALID_OFFSET | NVME_STATUS_DNR;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 007/670] Revert "net: advertise TCP MSS from the configured MTU, not the learned PMTU"
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (5 preceding siblings ...)
2026-11-13 15:42 ` [PATCH 6.12 006/670] nvmet-rdma: fix out-of-bounds write in nvmet_rdma_map_sgl_inline() Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 008/670] fsverity: Tell LSMs about signature only after verity is enabled Greg Kroah-Hartman
` (664 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yongjian Wang, Eric Dumazet,
Jiayuan Chen, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongjian Wang <echoowall@gmail.com>
[ Upstream commit 564313447e545eea13038f74ada9272ab129b3cb ]
This reverts commit 2640e6419594 ("net: advertise TCP MSS from the
configured MTU, not the learned PMTU").
That commit stopped the learned PMTU from lowering the MSS we advertise
in SYN and SYN-ACK. For symmetric paths it argued that "the peer runs
its own PMTU discovery and usually already knows the real path MTU".
That only holds if ICMP "fragmentation needed" can reach the peer. When
the peer sits behind a firewall that drops inbound ICMP, its PMTU
discovery is a black hole (RFC 2923, section 2.1), and the smaller MSS
we advertised was the only thing keeping its full-size segments off the
narrow hop.
Inbound ICMP filtering is very common in enterprise and carrier
networks, and it is pervasive in mainland China. We hit this in
production after the commit was backported to 6.12.111: TCP connections
that reach a server through a relay with a smaller-MTU hop complete the
handshake, then stall as soon as the client sends full-size segments.
Clients on networks that let ICMP through, and connections that bypass
the relay, are unaffected, which made it hard to trace back to the
kernel.
Reproducer, network namespaces on a single host:
cli --(1500)-- r1 --(1456)-- r2 --(1500)-- srv
r1 drops ICMP frag-needed towards cli. srv has already learned PMTU
1456 towards cli, then cli uploads 1 MB to srv:
kernel SYN-ACK MSS 1 MB upload
6.12.107 1416 OK
6.12.111 1460 stalls, times out
7.3-rc7 1460 stalls, times out
7.3-rc7 + this revert 1416 OK
The asymmetric case the commit was written for does not need a new
default: the advertised MSS can already be set per route with the
advmss metric, which takes precedence over default_advmss(). With this
revert applied, on an asymmetric path where srv learned PMTU 1456
towards cli while cli->srv is 1500 end to end:
srv route to cli SYN-ACK MSS largest cli->srv segment
default 1416 1404
advmss 1460 1460 1448
So DSR-style setups can opt in with "ip route ... advmss <mss>", while
hosts whose peers cannot complete PMTU discovery keep working by
default.
[ 6.12.y: reverse commit 7f84f07f54fa, the stable backport of
2640e6419594. Keep the local dst_dev() lookup and surrounding
context in ip6_default_advmss(). ]
Fixes: 2640e6419594 ("net: advertise TCP MSS from the configured MTU, not the learned PMTU")
Closes: https://lore.kernel.org/regressions/4F0FAEB6-A13B-47F3-BFF1-C706686C6F64@gmail.com/
Cc: stable@vger.kernel.org
Signed-off-by: Yongjian Wang <echoowall@gmail.com>
Reviewed-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Link: https://patch.msgid.link/20261026-advmss-revert-v1-2-272fa4b7ecb6@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/ip.h | 25 -------------------------
include/net/ip6_route.h | 37 -------------------------------------
net/ipv4/route.c | 4 ++--
net/ipv6/route.c | 2 +-
4 files changed, 3 insertions(+), 65 deletions(-)
diff --git a/include/net/ip.h b/include/net/ip.h
index 97c60b3002702..f00719e1863f7 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -515,31 +515,6 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
return res;
}
-/* Configured/administrative MTU of a route, for advertising the TCP MSS.
- *
- * Unlike ip_dst_mtu_maybe_forward(), this deliberately ignores the
- * ICMP-learned path MTU (rt->rt_pmtu). The advertised MSS bounds what the
- * peer may send to us and must reflect our receive capability (the device or
- * route-configured MTU), not a path MTU learned on the reverse (send)
- * direction, which may not apply to the peer->us path and outlives the fnhe
- * for the whole connection. See RFC 2923 section 2.3 and the comment above
- * tcp_advertise_mss().
- */
-static inline unsigned int ip_dst_mtu_configured(const struct dst_entry *dst)
-{
- unsigned int mtu, res;
-
- rcu_read_lock();
- mtu = dst_metric_raw(dst, RTAX_MTU);
- if (!mtu)
- mtu = READ_ONCE(dst_dev_rcu(dst)->mtu);
- mtu = min_t(unsigned int, mtu, IP_MAX_MTU);
- res = mtu - lwtunnel_headroom(dst->lwtstate, mtu);
- rcu_read_unlock();
-
- return res;
-}
-
static inline unsigned int ip_skb_dst_mtu(struct sock *sk,
const struct sk_buff *skb)
{
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 8be44dc5b5b71..ad35c7512f120 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -354,43 +354,6 @@ static inline unsigned int ip6_dst_mtu_maybe_forward(const struct dst_entry *dst
return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
}
-/* Configured/administrative MTU of a route, for advertising the TCP MSS.
- *
- * Unlike ip6_dst_mtu_maybe_forward(), this ignores any ICMPv6-learned path
- * MTU (which is kept on the RTF_CACHE exception route) and returns the MTU of
- * the underlying route (fib6_pmtu) or the egress device. The advertised MSS
- * bounds what the peer may send to us and must reflect our receive
- * capability, not a path MTU learned on the reverse (send) direction. See
- * RFC 2923 section 2.3 and the comment above tcp_advertise_mss().
- */
-static inline unsigned int ip6_dst_mtu_configured(const struct dst_entry *dst)
-{
- const struct rt6_info *rt = dst_rt6_info(dst);
- const struct fib6_info *from;
- struct inet6_dev *idev;
- unsigned int mtu = 0;
-
- rcu_read_lock();
- /* IPv6 keeps the learned PMTU and the configured MTU in the same
- * RTAX_MTU slot: the learned value sits on this (possibly RTF_CACHE)
- * dst, the configured one on the underlying route. Reach the latter
- * via ->from (fib6_pmtu), populated by ip6_route_info_create().
- */
- from = rcu_dereference(rt->from);
- if (from)
- mtu = from->fib6_pmtu;
- if (!mtu) {
- mtu = IPV6_MIN_MTU;
- idev = __in6_dev_get(dst_dev_rcu(dst));
- if (idev)
- mtu = max_t(unsigned int, mtu, READ_ONCE(idev->cnf.mtu6));
- }
- rcu_read_unlock();
-
- mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
- return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
-}
-
u32 ip6_mtu_from_fib6(const struct fib6_result *res,
const struct in6_addr *daddr,
const struct in6_addr *saddr);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 596c84fd5ab42..f1b0ab77b443b 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1358,8 +1358,8 @@ static unsigned int ipv4_default_advmss(const struct dst_entry *dst)
rcu_read_lock();
net = dst_dev_net_rcu(dst);
- advmss = max_t(unsigned int, ip_dst_mtu_configured(dst) - header_size,
- net->ipv4.ip_rt_min_advmss);
+ advmss = max_t(unsigned int, ipv4_mtu(dst) - header_size,
+ net->ipv4.ip_rt_min_advmss);
rcu_read_unlock();
return min(advmss, IPV4_MAX_PMTU - header_size);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 94fa1b34be5c3..e6c2db89860c8 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -3252,7 +3252,7 @@ EXPORT_SYMBOL_GPL(ip6_sk_redirect);
static unsigned int ip6_default_advmss(const struct dst_entry *dst)
{
struct net_device *dev = dst_dev(dst);
- unsigned int mtu = ip6_dst_mtu_configured(dst);
+ unsigned int mtu = dst6_mtu(dst);
struct net *net;
mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 008/670] fsverity: Tell LSMs about signature only after verity is enabled
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (6 preceding siblings ...)
2026-11-13 15:42 ` [PATCH 6.12 007/670] Revert "net: advertise TCP MSS from the configured MTU, not the learned PMTU" Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 009/670] Bluetooth: L2CAP: Reject signalling responses in invalid states Greg Kroah-Hartman
` (663 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Fan Wu, Eric Biggers, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <ebiggers@kernel.org>
commit 28d74059fddbd8ae83c7715056b303c402071f6f upstream.
FS_IOC_ENABLE_VERITY calls security_inode_setintegrity() before verity
has finished being enabled. That's broken because enabling verity can
still fail at that point, e.g. due to insufficient xattr space.
Afterwards, arbitrary contents can be written to the file, which doesn't
actually have verity enabled. The in-core inode stays the same, so the
LSM considers it to have verity enabled with a valid signature. (Or
rather, in the case of IPE, which is the only LSM that implements
security_inode_setintegrity(), it also checks IS_VERITY(), which can be
bypassed by enabling verity with no signature after the file writes.)
Fix this by moving the call to security_inode_setintegrity() out of
fsverity_verify_signature() and into a new function that is called from
the appropriate places.
Fixes: 7c373e4f1445 ("fsverity: expose verified fsverity built-in signatures to LSMs")
Cc: stable@vger.kernel.org
Reviewed-by: Fan Wu <wufan@kernel.org>
Tested-by: Fan Wu <wufan@kernel.org>
Link: https://patch.msgid.link/20261025204534.122506-1-ebiggers@kernel.org
(6.12: resolved conflicts with this version storing the fsverity_info
pointer in the inode instead of using a hash table)
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/verity/enable.c | 8 ++++++
fs/verity/fsverity_private.h | 8 ++++++
fs/verity/open.c | 9 ++++++
fs/verity/signature.c | 55 ++++++++++++++++++++++++++----------
4 files changed, 65 insertions(+), 15 deletions(-)
diff --git a/fs/verity/enable.c b/fs/verity/enable.c
index c284f46d1b535..197564ecd3ef6 100644
--- a/fs/verity/enable.c
+++ b/fs/verity/enable.c
@@ -292,6 +292,14 @@ static int enable_verity(struct file *filp,
* after the filesystem has successfully enabled verity.
*/
fsverity_set_info(inode, vi);
+
+ /*
+ * Now that verity is enabled, report the signature (if any) to
+ * LSMs. We tolerate that a process racing with this ioctl can
+ * briefly see verity enabled with no signature reported yet.
+ */
+ fsverity_report_valid_sig(inode, desc->signature,
+ le32_to_cpu(desc->sig_size));
}
out:
kfree(params.hashstate);
diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h
index b3506f56e180b..760f2674c816e 100644
--- a/fs/verity/fsverity_private.h
+++ b/fs/verity/fsverity_private.h
@@ -135,6 +135,8 @@ void __init fsverity_init_info_cache(void);
extern int fsverity_require_signatures;
int fsverity_verify_signature(const struct fsverity_info *vi,
const u8 *signature, size_t sig_size);
+void fsverity_report_valid_sig(const struct inode *inode, const u8 *signature,
+ size_t sig_size);
void __init fsverity_init_signature(void);
#else /* !CONFIG_FS_VERITY_BUILTIN_SIGNATURES */
@@ -145,6 +147,12 @@ fsverity_verify_signature(const struct fsverity_info *vi,
return 0;
}
+static inline void fsverity_report_valid_sig(const struct inode *inode,
+ const u8 *signature,
+ size_t sig_size)
+{
+}
+
static inline void fsverity_init_signature(void)
{
}
diff --git a/fs/verity/open.c b/fs/verity/open.c
index 9c1b37a3b96a8..dba70c0ab5b64 100644
--- a/fs/verity/open.c
+++ b/fs/verity/open.c
@@ -377,6 +377,15 @@ static int ensure_verity_info(struct inode *inode)
goto out_free_desc;
}
+ /*
+ * Now that the signature (if any) has been verified, report it to LSMs.
+ * Do this before setting the fsverity_info, so that anyone who
+ * concurrently retrieves the fsverity_info for the same inode is
+ * guaranteed to see the LSM's signature status populated.
+ */
+ fsverity_report_valid_sig(inode, desc->signature,
+ le32_to_cpu(desc->sig_size));
+
fsverity_set_info(inode, vi);
err = 0;
out_free_desc:
diff --git a/fs/verity/signature.c b/fs/verity/signature.c
index 0302a4e506ec4..212e873c84998 100644
--- a/fs/verity/signature.c
+++ b/fs/verity/signature.c
@@ -42,13 +42,16 @@ static struct key *fsverity_keyring;
* @sig_size: size of signature in bytes, or 0 if no signature
*
* If the file includes a signature of its fs-verity file digest, verify it
- * against the certificates in the fs-verity keyring. Note that signatures
- * are verified regardless of the state of the 'fsverity_require_signatures'
- * variable and the LSM subsystem relies on this behavior to help enforce
- * file integrity policies. Please discuss changes with the LSM list
- * (thank you!).
+ * against the certificates in the fs-verity keyring.
*
- * Return: 0 on success (signature valid or not required); -errno on failure
+ * Note that signatures are verified regardless of the state of the
+ * 'fsverity_require_signatures' variable, and the LSM subsystem relies on this
+ * behavior to help enforce file integrity policies. (See
+ * fsverity_report_valid_sig(), which assumes that the signature, if present,
+ * was verified here.) Please discuss changes with the LSM list (thank you!).
+ *
+ * Return: 0 if the signature is present and valid, or absent and not required;
+ * -errno on failure
*/
int fsverity_verify_signature(const struct fsverity_info *vi,
const u8 *signature, size_t sig_size)
@@ -111,18 +114,40 @@ int fsverity_verify_signature(const struct fsverity_info *vi,
return err;
}
- err = security_inode_setintegrity(inode,
- LSM_INT_FSVERITY_BUILTINSIG_VALID,
- signature,
- sig_size);
+ return 0;
+}
- if (err) {
+/*
+ * If the signature exists, this tells the LSM that it was verified.
+ *
+ * fsverity_verify_signature() must have already been called with the same
+ * signature, *and* the inode must have verity enabled with the signature
+ * matching it. If called from FS_IOC_ENABLE_VERITY, the latter means that we
+ * must be past the point of no return, i.e. verity won't fail to be enabled at
+ * a later point. This is critical, since LSMs must be told about the signature
+ * only when the verity status is permanent in the in-core inode.
+ */
+void fsverity_report_valid_sig(const struct inode *inode, const u8 *signature,
+ size_t sig_size)
+{
+ int err;
+
+ if (WARN_ON_ONCE(!IS_VERITY(inode)))
+ return;
+
+ if (sig_size == 0)
+ return;
+
+ err = security_inode_setintegrity(
+ inode, LSM_INT_FSVERITY_BUILTINSIG_VALID, signature, sig_size);
+ if (err)
fsverity_err(inode, "Error %d exposing file signature to LSMs",
err);
- return err;
- }
-
- return 0;
+ /*
+ * Besides the logging above, ignore errors here. The LSM hook just
+ * records the signature and doesn't perform access control. And in the
+ * case of FS_IOC_ENABLE_VERITY verity was already enabled.
+ */
}
void __init fsverity_init_signature(void)
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 009/670] Bluetooth: L2CAP: Reject signalling responses in invalid states
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (7 preceding siblings ...)
2026-11-13 15:42 ` [PATCH 6.12 008/670] fsverity: Tell LSMs about signature only after verity is enabled Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 010/670] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Greg Kroah-Hartman
` (662 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Siwei Zhang, Luiz Augusto von Dentz,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Siwei Zhang <oss@fourdim.xyz>
commit 6320736af7dcb90da6ee9fd651ecc11c564d45b7 upstream.
Adjusted context as stable does not have the lockdep_assert_held()
calls, and l2cap_get_chan_by_scid() still returns the channel locked,
so l2cap_config_rsp() does not lock it again.
A peer can send configuration messages while an
incoming channel is in BT_CONNECT2, before the
security or deferred accept gate has completed. A
configuration response can then promote the channel
to BT_CONNECTED. Configuration responses can also
act on channels that are closing, and a late connection
response can move a disconnecting channel back to
BT_CONFIG.
Accept connection responses only while waiting in
BT_CONNECT. Answer configuration requests in
BT_CONNECT2, but defer our own request until
BT_CONFIG so configuration cannot complete before
the gate. Ignore configuration responses outside
BT_CONFIG and BT_CONNECTED, and only complete
configuration in BT_CONFIG.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/l2cap_core.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index d8c39a4306861..fa7124c32d91a 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4278,6 +4278,10 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
l2cap_chan_lock(chan);
+ /* Ignore a late response after the channel has left BT_CONNECT. */
+ if (chan->state != BT_CONNECT)
+ goto done;
+
switch (result) {
case L2CAP_CR_SUCCESS:
if (__l2cap_get_chan_by_dcid(conn, dcid)) {
@@ -4307,6 +4311,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
break;
}
+done:
l2cap_chan_unlock(chan);
l2cap_chan_put(chan);
@@ -4439,7 +4444,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
goto unlock;
}
- if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
+ /* A channel in BT_CONNECT2 has not passed security or userspace
+ * accept yet. Answer the peer's request, but hold our own until
+ * the channel reaches BT_CONFIG: the CONNECT2 -> CONFIG sites send
+ * it. Connected channels may also need to reconfigure.
+ */
+ if ((chan->state == BT_CONFIG || chan->state == BT_CONNECTED) &&
+ !test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
u8 buf[64];
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
@@ -4487,6 +4498,10 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
if (!chan)
return 0;
+ /* Connected channels may also receive reconfiguration responses. */
+ if (chan->state != BT_CONFIG && chan->state != BT_CONNECTED)
+ goto done;
+
switch (result) {
case L2CAP_CONF_SUCCESS:
l2cap_conf_rfc_get(chan, rsp->data, len);
@@ -4554,6 +4569,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
set_default_fcs(chan);
+ if (chan->state != BT_CONFIG)
+ goto done;
+
if (chan->mode == L2CAP_MODE_ERTM ||
chan->mode == L2CAP_MODE_STREAMING)
err = l2cap_ertm_init(chan);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 010/670] Bluetooth: L2CAP: Only accept connection responses to outstanding requests
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (8 preceding siblings ...)
2026-11-13 15:42 ` [PATCH 6.12 009/670] Bluetooth: L2CAP: Reject signalling responses in invalid states Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 011/670] Bluetooth: L2CAP: Ignore connection responses with wrong ident Greg Kroah-Hartman
` (661 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Siwei Zhang, Luiz Augusto von Dentz,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Siwei Zhang <oss@fourdim.xyz>
commit a518b9a9ef6ee3b18ecdf6ba5360c608aaf969e9 upstream.
Adjusted context as stable does not have the lockdep_assert_held()
call and the __must_hold() context analysis annotations.
An outgoing channel waits in BT_CONNECT until security
and the feature mask exchange complete, and only then
sends its connection request. A peer can answer it
before that with a connection response matching our
source CID. The channel then moves to BT_CONFIG,
completes configuration and becomes connected before
security has completed. If security then fails,
l2cap_security_cfm() leaves the connected channel
alone, so it stays up on a link that did not reach
the required security level.
A connection response with a zero source CID is
matched by identifier. Another channel can hold the
same identifier for a response it still has to send,
so the lookup can pick the wrong channel.
Only accept a connection response while our request
is outstanding, and only look at such channels when
matching by identifier.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/l2cap_core.c | 31 ++++++++++++++++++++++++++++---
1 file changed, 28 insertions(+), 3 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index fa7124c32d91a..2f107c036dd4d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -161,6 +161,28 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn,
return NULL;
}
+/* Our connection request has been sent and is still outstanding */
+static bool l2cap_chan_connect_pending(struct l2cap_chan *chan)
+{
+ return chan->state == BT_CONNECT &&
+ test_bit(CONF_CONNECT_PEND, &chan->conf_state);
+}
+
+/* Other channels may hold the same ident for a response they still have
+ * to send, so only look at channels waiting for a connection response.
+ */
+static struct l2cap_chan *__l2cap_get_connect_chan_by_ident(struct l2cap_conn *conn,
+ u8 ident)
+{
+ struct l2cap_chan *c;
+
+ list_for_each_entry(c, &conn->chan_l, list) {
+ if (c->ident == ident && l2cap_chan_connect_pending(c))
+ return c;
+ }
+ return NULL;
+}
+
static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src,
u8 src_type)
{
@@ -4265,7 +4287,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
if (!chan)
return -EBADSLT;
} else {
- chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
+ chan = __l2cap_get_connect_chan_by_ident(conn, cmd->ident);
if (!chan)
return -EBADSLT;
}
@@ -4278,8 +4300,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
l2cap_chan_lock(chan);
- /* Ignore a late response after the channel has left BT_CONNECT. */
- if (chan->state != BT_CONNECT)
+ /* Only accept a response to a connection request we sent and that
+ * is still outstanding. A channel waiting in BT_CONNECT for security
+ * or the feature mask has not sent one yet.
+ */
+ if (!l2cap_chan_connect_pending(chan))
goto done;
switch (result) {
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 011/670] Bluetooth: L2CAP: Ignore connection responses with wrong ident
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (9 preceding siblings ...)
2026-11-13 15:42 ` [PATCH 6.12 010/670] Bluetooth: L2CAP: Only accept connection responses to outstanding requests Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 012/670] smb: client: hold server info until cifsd exits Greg Kroah-Hartman
` (660 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jinwang Li, Luiz Augusto von Dentz,
Siwei Zhang, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jinwang Li <jinwang.li@oss.qualcomm.com>
commit a9f9eeb5344fc7dc625e5700ccf09891bc2603b5 upstream.
Adjusted context as stable does not have the lockdep_assert_held()
call in l2cap_connect_create_rsp().
L2CAP/COS/CED/BI-28-C requires the IUT to ignore a Connection Response
that carries an invalid Identifier.
l2cap_connect_create_rsp() only checks that a connection request is
outstanding, not that the response answers it. Add an ident check
against the pending request so that a mismatched response is dropped.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Jinwang Li <jinwang.li@oss.qualcomm.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/l2cap_core.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 2f107c036dd4d..514abca6ed88c 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4300,11 +4300,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
l2cap_chan_lock(chan);
- /* Only accept a response to a connection request we sent and that
- * is still outstanding. A channel waiting in BT_CONNECT for security
- * or the feature mask has not sent one yet.
+ /* Only accept a response matching a connection request we sent and
+ * that is still outstanding. A channel waiting in BT_CONNECT for
+ * security or the feature mask has not sent one yet.
*/
- if (!l2cap_chan_connect_pending(chan))
+ if (!l2cap_chan_connect_pending(chan) || chan->ident != cmd->ident)
goto done;
switch (result) {
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 012/670] smb: client: hold server info until cifsd exits
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (10 preceding siblings ...)
2026-11-13 15:42 ` [PATCH 6.12 011/670] Bluetooth: L2CAP: Ignore connection responses with wrong ident Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 013/670] smb: client: fix OOB read of the resume name sent in TRANS2_FIND_NEXT2 Greg Kroah-Hartman
` (659 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+5c3ed2a0de3270efc921,
syzbot+c2ec61adfbcb24e5ec20, Eduard Zateev,
Michail Andreas Michalopoulos, Paulo Alcantara, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zateev <hackerowskiy@gmail.com>
[ Upstream commit 482c117c6dbeee382790168af10959810450ab09 ]
The last session reference can be dropped while the cifsd demultiplex
thread is still running clean_demultiplex_info(). That thread frees
TCP_Server_Info there, racing with cifs_put_tcp_session() as it releases
the server crypto state. syzbot reported a KASAN use-after-free in
cifs_crypto_secmech_release().
Keep an object reference for the cifsd thread. Defer final crypto,
session-key, network namespace, string, and structure cleanup until both
the last session reference and the thread reference are dropped. Drop the
thread reference after clean_demultiplex_info() has finished using the
server.
Build-tested with ARCH=arm64 and W=1 for
fs/smb/client/connect.o. The KASAN reproducer was not run on the patched
kernel.
Fixes: a5c3e1c725af ("Revert "cifs: No need to send SIGKILL to demux_thread during umount"")
Reported-by: syzbot+5c3ed2a0de3270efc921@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=5c3ed2a0de3270efc921
Reported-by: syzbot+c2ec61adfbcb24e5ec20@syzkaller.appspotmail.com
Closes: https://syzbot.org/bug?extid=c2ec61adfbcb24e5ec20
Assisted-by: LLM OpenAI Codex
Signed-off-by: Eduard Zateev <hackerowskiy@gmail.com>
Cc: stable@vger.kernel.org
Tested-by: Michail Andreas Michalopoulos <mike.michalo@gmail.com>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
[ sashal: Adjusted patch context for missing NetBIOS fields and existing kfree() cleanup instead of kfree_sensitive(). ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/cifsglob.h | 2 ++
fs/smb/client/connect.c | 33 +++++++++++++++++++++------------
2 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index f5ca2cd653e95..8ffc8b2ab6db4 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -16,6 +16,7 @@
#include <linux/scatterlist.h>
#include <linux/mm.h>
#include <linux/mempool.h>
+#include <linux/refcount.h>
#include <linux/workqueue.h>
#include <linux/utsname.h>
#include <linux/sched/mm.h>
@@ -647,6 +648,7 @@ struct TCP_Server_Info {
spinlock_t srv_lock; /* protect anything here that is not protected */
__u64 conn_id; /* connection identifier (useful for debugging) */
int srv_count; /* reference counter */
+ refcount_t obj_refs; /* struct lifetime: srv_count users + cifsd */
/* 15 character server name + 0x20 16th byte indicating type = srv */
char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
struct smb_version_operations *ops;
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index eace4d1a3dce7..82a70370a60f8 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -977,6 +977,19 @@ cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
return 0;
}
+static void cifs_tcp_server_put(struct TCP_Server_Info *server)
+{
+ if (!refcount_dec_and_test(&server->obj_refs))
+ return;
+
+ cifs_crypto_secmech_release(server);
+ kfree_sensitive(server->session_key.response);
+ put_net(cifs_net_ns(server));
+ kfree(server->leaf_fullpath);
+ kfree(server->hostname);
+ kfree_sensitive(server);
+}
+
static noinline_for_stack void
clean_demultiplex_info(struct TCP_Server_Info *server)
{
@@ -1062,14 +1075,11 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
*/
}
- put_net(cifs_net_ns(server));
- kfree(server->leaf_fullpath);
- kfree(server->hostname);
- kfree(server);
-
length = atomic_dec_return(&tcpSesAllocCount);
if (length > 0)
mempool_resize(cifs_req_poolp, length + cifs_min_rcv);
+
+ cifs_tcp_server_put(server);
}
static int
@@ -1680,7 +1690,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
else
cancel_delayed_work_sync(&server->reconnect);
- /* For secondary channels, we pick up ref-count on the primary server */
+ /* For secondary channels, drop the reference on the primary server */
if (SERVER_IS_CHAN(server))
cifs_put_tcp_session(server->primary_server, from_reconnect);
@@ -1688,15 +1698,11 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
server->tcpStatus = CifsExiting;
spin_unlock(&server->srv_lock);
- cifs_crypto_secmech_release(server);
-
- kfree_sensitive(server->session_key.response);
- server->session_key.response = NULL;
- server->session_key.len = 0;
-
task = xchg(&server->tsk, NULL);
if (task)
send_sig(SIGKILL, task, 1);
+
+ cifs_tcp_server_put(server);
}
struct TCP_Server_Info *
@@ -1718,6 +1724,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
rc = -ENOMEM;
goto out_err;
}
+ refcount_set(&tcp_ses->obj_refs, 1);
tcp_ses->hostname = kstrdup(ctx->server_hostname, GFP_KERNEL);
if (!tcp_ses->hostname) {
@@ -1858,6 +1865,8 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
module_put(THIS_MODULE);
goto out_err_crypto_release;
}
+ /* Keep the server alive until the demultiplex thread has exited */
+ refcount_inc(&tcp_ses->obj_refs);
/* thread created, put it on the list */
spin_lock(&cifs_tcp_ses_lock);
list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 013/670] smb: client: fix OOB read of the resume name sent in TRANS2_FIND_NEXT2
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (11 preceding siblings ...)
2026-11-13 15:42 ` [PATCH 6.12 012/670] smb: client: hold server info until cifsd exits Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 014/670] smb: client: reject short SESSION_SETUP responses Greg Kroah-Hartman
` (658 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Diego Oliva, David Howells,
Paulo Alcantara, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Diego Oliva <diego@bynar.io>
[ Upstream commit f8171804a39ee89a11cd462f67862899de9c6b10 ]
cifs_fill_dirent() reads the fixed part of a directory entry and the
name length it holds, or for SMB_FIND_FILE_UNIX scans the name for its
terminating NUL, without knowing where the response ends.
cifs_save_resume_key() calls it for the entry at the LastNameOffset the
server chose, after every FindNext and after the FindFirst of a search
rewind, and records the name it returns as the resume name of the
search without bounding it; the next CIFSFindNext() copies up to
PATH_MAX - 1 bytes from that name into its request and sends them to
the server. cifs_filldir() bounds
the name against the end of the response since
commit f8cf09a53a0d ("smb: client: bound dirent name against end of
SMB response in cifs_filldir"), but only after cifs_fill_dirent() has
read the entry, and nxt_dir_entry() checks the entries it walks only
against sizeof(FILE_DIRECTORY_INFO), for every level but
SMB_FIND_FILE_INFO_STANDARD, and never sees the first entry of a
response.
Bounding where last_entry starts, as the preceding patch does, does
not bound the read. A last entry that starts within the final bytes of
the response still has its fixed part read past the end of the
received data, and the name length it declares, a __le32 for every
level but SMB_FIND_FILE_INFO_STANDARD and SMB_FIND_FILE_UNIX, is
recorded without being checked against anything. CIFSFindNext()
rejects only a length of PATH_MAX or more, then copies the name, up to
4095 bytes, into its request and sends it, and as the report below
shows that copy can run past the end of the cifs_request allocation
that holds the response. For SMB_FIND_FILE_UNIX the name is in
addition scanned for its terminating NUL over up to PATH_MAX + 1
UTF-16 units, or PATH_MAX bytes, before any check. The FindNext that
carries the name is only sent by the SMB1 dialect, which is not
negotiated by default; reaching it requires an explicit vers=1.0
mount.
With KASAN enabled, a response whose last entry declares a name
longer than the bytes that follow it gives:
==================================================================
BUG: KASAN: slab-out-of-bounds in CIFSFindNext+0x8ca/0x14c0
Read of size 4080 at addr ffff88807c823f98 by task ls/83
CPU: 0 UID: 0 PID: 83 Comm: ls Not tainted 7.3.0-rc4-00457-gf14572c203d5 #69 PREEMPT(lazy)
Call Trace:
<TASK>
kasan_report+0xdf/0x1a0
kasan_check_range+0x10f/0x1e0
__asan_memcpy+0x23/0x60
CIFSFindNext+0x8ca/0x14c0
cifs_readdir+0xf51/0x29c0
iterate_dir+0x1c0/0x570
__x64_sys_getdents64+0x133/0x270
do_syscall_64+0x109/0x5d0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
</TASK>
Allocated by task 83 on cpu 1 at 13.497119s:
cifs_buf_get+0x36/0x90
smb_init+0x4f/0x110
CIFSFindNext+0xf7/0x14c0
cifs_readdir+0xf51/0x29c0
The buggy address belongs to the object at ffff88807c820000
which belongs to the cache cifs_request of size 16588
The buggy address is located 16280 bytes inside of
allocated 16588-byte region [ffff88807c820000, ffff88807c8240cc)
==================================================================
The read is the memcpy() that copies the recorded name into the next
request, so those bytes go to the server.
Pass the end of the response to cifs_fill_dirent() and have it reject
an entry whose fixed part does not fit or whose name extends past the
end, before either is used, so that both callers are covered;
cifs_save_resume_key() computes the end the same way cifs_readdir()
does. The name bound compares the bytes left between the name and the
end with the name length rather than adding the length to the name
pointer, since the length is a 32-bit value taken from the entry and
the sum could wrap on 32-bit systems. cifs_fill_dirent() is also used
on the SMB2 readdir path; there smb2_parse_query_directory() has
already checked every entry against the end of the response, so a
valid SMB2 response is not rejected by the new checks. The check
cifs_filldir() applies after the parse is left in place. The NUL scan
for SMB_FIND_FILE_UNIX names is capped by a separate patch.
An entry and its name lie inside the data area of the response, so a
server that points LastNameOffset at the entry is not affected. One
that points it at the file name, as MS-CIFS 2.2.6.2.2 describes, has
its last entry rejected here; the listing is unaffected, because
cifs_readdir() records the resume name from an entry it emitted, and
before this series such a response could instead end the listing early,
since a name length read from the wrong place is usually PATH_MAX or
more, which CIFSFindNext() rejects with -EINVAL.
On trees before v6.19 the type for the level 0x105 fixed part is
spelled SEARCH_ID_FULL_DIR_INFO; adjust when backporting.
Fixes: 0752f1522a91 ("[CIFS] make sure we have the right resume info before calling CIFSFindNext")
Cc: stable@vger.kernel.org # 6.1.x: f8cf09a53a0d: smb: client: bound dirent name against end of SMB response in cifs_filldir
Assisted-by: Bynario AI
Signed-off-by: Diego Oliva <diego@bynar.io>
Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
[ sashal: Replaced FILE_ID_FULL_DIR_INFO with SEARCH_ID_FULL_DIR_INFO in the offsetof(..., FileName) check. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/readdir.c | 39 ++++++++++++++++++++++++++++++++++++---
1 file changed, 36 insertions(+), 3 deletions(-)
diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c
index 9412c69e5aea6..449e8dbc98309 100644
--- a/fs/smb/client/readdir.c
+++ b/fs/smb/client/readdir.c
@@ -584,30 +584,46 @@ static void cifs_fill_dirent_std(struct cifs_dirent *de,
}
static int cifs_fill_dirent(struct cifs_dirent *de, const void *info,
- u16 level, bool is_unicode)
+ const char *end, u16 level, bool is_unicode)
{
+ size_t len = end > (const char *)info ? end - (const char *)info : 0;
+
memset(de, 0, sizeof(*de));
switch (level) {
case SMB_FIND_FILE_POSIX_INFO:
+ if (len < sizeof(struct smb2_posix_info))
+ goto too_short;
cifs_fill_dirent_posix(de, info);
break;
case SMB_FIND_FILE_UNIX:
+ if (len < offsetof(FILE_UNIX_INFO, FileName))
+ goto too_short;
cifs_fill_dirent_unix(de, info, is_unicode);
break;
case SMB_FIND_FILE_DIRECTORY_INFO:
+ if (len < offsetof(FILE_DIRECTORY_INFO, FileName))
+ goto too_short;
cifs_fill_dirent_dir(de, info);
break;
case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ if (len < offsetof(FILE_FULL_DIRECTORY_INFO, FileName))
+ goto too_short;
cifs_fill_dirent_full(de, info);
break;
case SMB_FIND_FILE_ID_FULL_DIR_INFO:
+ if (len < offsetof(SEARCH_ID_FULL_DIR_INFO, FileName))
+ goto too_short;
cifs_fill_dirent_search(de, info);
break;
case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ if (len < offsetof(FILE_BOTH_DIRECTORY_INFO, FileName))
+ goto too_short;
cifs_fill_dirent_both(de, info);
break;
case SMB_FIND_FILE_INFO_STANDARD:
+ if (len < offsetof(FIND_FILE_STANDARD_INFO, FileName))
+ goto too_short;
cifs_fill_dirent_std(de, info);
break;
default:
@@ -615,7 +631,19 @@ static int cifs_fill_dirent(struct cifs_dirent *de, const void *info,
return -EINVAL;
}
+ if (de->name &&
+ (end < de->name || (size_t)(end - de->name) < de->namelen)) {
+ cifs_dbg(VFS, "%s: search entry name extends past end of SMB\n",
+ __func__);
+ return -EINVAL;
+ }
+
return 0;
+
+too_short:
+ cifs_dbg(VFS, "%s: search entry extends past end of SMB\n",
+ __func__);
+ return -EINVAL;
}
#define UNICODE_DOT cpu_to_le16(0x2e)
@@ -670,10 +698,14 @@ static int is_dir_changed(struct file *file)
static int cifs_save_resume_key(const char *current_entry,
struct cifsFileInfo *file_info)
{
+ struct TCP_Server_Info *server = tlink_tcon(file_info->tlink)->ses->server;
+ char *buf = file_info->srch_inf.ntwrk_buf_start;
+ const char *end = buf + server->ops->calc_smb_size(buf);
struct cifs_dirent de;
int rc;
- rc = cifs_fill_dirent(&de, current_entry, file_info->srch_inf.info_level,
+ rc = cifs_fill_dirent(&de, current_entry, end,
+ file_info->srch_inf.info_level,
file_info->srch_inf.unicode);
if (!rc) {
file_info->srch_inf.presume_name = de.name;
@@ -958,7 +990,8 @@ static int cifs_filldir(char *find_entry, struct file *file,
struct qstr name;
int rc = 0;
- rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level,
+ rc = cifs_fill_dirent(&de, find_entry, end_of_smb,
+ file_info->srch_inf.info_level,
file_info->srch_inf.unicode);
if (rc)
return rc;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 014/670] smb: client: reject short SESSION_SETUP responses
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (12 preceding siblings ...)
2026-11-13 15:42 ` [PATCH 6.12 013/670] smb: client: fix OOB read of the resume name sent in TRANS2_FIND_NEXT2 Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:42 ` [PATCH 6.12 015/670] smb: client: require stable pages for SMB compression Greg Kroah-Hartman
` (657 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Abdifatah Suruur, Namjae Jeon,
Paulo Alcantara, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdifatah Suruur <suruurism@gmail.com>
[ Upstream commit 4d8930afa3446041358a7db33e7b23a0bb9459b5 ]
smb2_check_message() accepts frames shorter than struct smb2_pdu when
the SMB2 status is non-zero, before the minimum-PDU check added by
b4694f269e66d. A 64-byte STATUS_MORE_PROCESSING_REQUIRED SESSION_SETUP
response is therefore accepted even though it cannot contain the
SecurityBufferOffset and SecurityBufferLength fields.
The parser then reads those fields from stale bytes left in the reused
receive buffer by an earlier frame. With a long stale
SecurityBufferLength, decode_ntlmssp_challenge() copies up to about
64 KB from beyond the receive object and sends the data back to the
server in the NTLMv2 AUTHENTICATE target info.
Reject short MPR SESSION_SETUP responses before the short-error path,
and validate SecurityBufferOffset + SecurityBufferLength against the
received response length before decoding the challenge.
The ordering bypass is not new: the short-error early return predates
b4694f269e66d, and the unvalidated SecurityBufferLength read predates
the 2016 raw NTLMSSP split in 166cea4dc3a4, so all supported stable
trees are affected. Reproduced on 6.6.87.2; the path is unchanged on
mainline.
Fixes: 5478f9ba9a34 ("CIFS: Add session setup/logoff capability for SMB2")
Cc: stable@vger.kernel.org
Signed-off-by: Abdifatah Suruur <suruurism@gmail.com>
Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/smb2misc.c | 15 +++++++++++++++
fs/smb/client/smb2pdu.c | 18 ++++++++++++------
2 files changed, 27 insertions(+), 6 deletions(-)
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
index 23320b794b177..7be338ad755b1 100644
--- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -193,6 +193,21 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
return 1;
}
+ /*
+ * A SESSION_SETUP response that asks for more processing carries a
+ * security blob and is parsed as a normal reply. Do not let the
+ * short-error path below accept a frame that cannot hold the fixed
+ * response fields.
+ */
+ if (command == SMB2_SESSION_SETUP_HE &&
+ shdr->Status == STATUS_MORE_PROCESSING_REQUIRED &&
+ len < sizeof(struct smb2_sess_setup_rsp)) {
+ cifs_server_dbg(VFS,
+ "%s: session setup response too short: %u < %zu\n",
+ __func__, len, sizeof(struct smb2_sess_setup_rsp));
+ return 1;
+ }
+
if (len < pdu_size) {
if ((len >= hdr_size)
&& (shdr->Status != 0)) {
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index bcfb75fab2c72..8e72506a24099 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -1773,15 +1773,21 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
if (rc)
goto out;
- if (offsetof(struct smb2_sess_setup_rsp, Buffer) !=
- le16_to_cpu(rsp->SecurityBufferOffset)) {
- cifs_dbg(VFS, "Invalid security buffer offset %d\n",
- le16_to_cpu(rsp->SecurityBufferOffset));
+ u16 boff = le16_to_cpu(rsp->SecurityBufferOffset);
+ u16 blen = le16_to_cpu(rsp->SecurityBufferLength);
+
+ if (offsetof(struct smb2_sess_setup_rsp, Buffer) != boff) {
+ cifs_dbg(VFS, "Invalid security buffer offset %d\n", boff);
rc = -EIO;
goto out;
}
- rc = decode_ntlmssp_challenge(rsp->Buffer,
- le16_to_cpu(rsp->SecurityBufferLength), ses);
+ if ((u32)boff + blen > sess_data->iov[0].iov_len) {
+ cifs_dbg(VFS, "%s: invalid security buffer length: %u\n",
+ __func__, blen);
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = decode_ntlmssp_challenge(rsp->Buffer, blen, ses);
if (rc)
goto out;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 015/670] smb: client: require stable pages for SMB compression
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (13 preceding siblings ...)
2026-11-13 15:42 ` [PATCH 6.12 014/670] smb: client: reject short SESSION_SETUP responses Greg Kroah-Hartman
@ 2026-11-13 15:42 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 016/670] mm: remove !root_reclaim checking in should_abort_scan() Greg Kroah-Hartman
` (656 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:42 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Paulo Alcantara,
Namjae Jeon, Ronnie Sahlberg, Shyam Prasad N, Tom Talpey,
Bharath SM, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <pc@manguebit.org>
[ Upstream commit 8667061cf99394526dd9c0ea2662e6bbc7ae7848 ]
Like signing, SMB compression builds the write payload from the pagecache
folios: should_compress() lets a write request through and smb_compress()
compresses those folios on the way to the socket. If a buffered write
mutates a folio while a write subrequest is still in flight, the compressed
bytes no longer correspond to a consistent view of the data, and the server
silently stores corrupted contents - worse than the signed case, which at
least fails loudly with STATUS_ACCESS_DENIED.
Mark the mapping for stable writes when a write may be compressed, i.e. the
same condition should_compress() tests (compression negotiated and the share
allows compressed data), so netfs_perform_write() waits for writeback to
complete before modifying an in-flight folio.
Fixes: f046d71e84e1 ("smb: client: insert compression check/call on write requests")
Suggested-by: David Howells <dhowells@redhat.com>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
Reviewed-by: David Howells <dhowells@redhat.com>
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com>
Cc: Shyam Prasad N <sprasad@microsoft.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Bharath SM <bharathsm@microsoft.com>
Cc: stable@vger.kernel.org
[ sashal: replaced tcon references with cifs_sb_master_tcon(cifs_sb) calls ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/inode.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 9307a2ad9e444..5db59b429fc3b 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -87,7 +87,9 @@ static void cifs_set_ops(struct inode *inode)
else
inode->i_data.a_ops = &cifs_addr_ops;
mapping_set_large_folios(inode->i_mapping);
- if (cifs_sb_master_tcon(cifs_sb)->ses->server->sign)
+ if (cifs_sb_master_tcon(cifs_sb)->ses->server->sign ||
+ (cifs_sb_master_tcon(cifs_sb)->ses->server->compression.enabled &&
+ (cifs_sb_master_tcon(cifs_sb)->share_flags & SMB2_SHAREFLAG_COMPRESS_DATA)))
mapping_set_stable_writes(inode->i_mapping);
break;
case S_IFDIR:
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 016/670] mm: remove !root_reclaim checking in should_abort_scan()
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (14 preceding siblings ...)
2026-11-13 15:42 ` [PATCH 6.12 015/670] smb: client: require stable pages for SMB compression Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 017/670] smb: client: validate SMB1 EA list bounds before parsing Greg Kroah-Hartman
` (655 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Zhaoyang Huang, T.J.Mercier,
Shakeel Butt, Qi Zheng, Barry Song, Kairui Song, Johannes Weiner,
Michal Hocko, Rik van Riel, Roman Gushchin, Yu Zhao,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhaoyang Huang <zhaoyang.huang@unisoc.com>
[ Upstream commit 19999e479c2a38672789e66b4830f43c645ca1f2 ]
Android systems usually use memory.reclaim interface to implement user
space memory management which expects that the requested reclaim target
and actually reclaimed amount memory are not diverging by too much. With
the current MGRLU implementation there is, however, no bail out when the
reclaim target is reached and this could lead to an excessive reclaim
that scales with the reclaim hierarchy size.For example, we can get a
nr_reclaimed=394/nr_to_reclaim=32 proactive reclaim under a common 1-N
cgroup hierarchy.
This defect arose from the goal of keeping fairness among memcgs that is,
for try_to_free_mem_cgroup_pages -> shrink_node_memcgs -> shrink_lruvec ->
lru_gen_shrink_lruvec -> try_to_shrink_lruvec, the !root_reclaim(sc) check
was there for reclaim fairness, which was necessary before commit
b82b530740b9 ("mm: vmscan: restore incremental cgroup iteration") because
the fairness depended on attempted proportional reclaim from every memcg
under the target memcg. However after commit b82b530740b9 there is no
longer a need to visit every memcg to ensure fairness. Let's have
try_to_shrink_lruvec bail out when the nr_reclaimed achieved.
Link: https://lore.kernel.org/20260318011558.1696310-1-zhaoyang.huang@unisoc.com
Link: https://lore.kernel.org/20260212032111.408865-1-zhaoyang.huang@unisoc.com
Signed-off-by: Zhaoyang Huang <zhaoyang.huang@unisoc.com>
Suggested-by: T.J.Mercier <tjmercier@google.com>
Reviewed-by: T.J. Mercier <tjmercier@google.com>
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: Qi Zheng <qi.zheng@linux.dev>
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: Kairui Song <kasong@tencent.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Rik van Riel <riel@surriel.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Yu Zhao <yuzhao@google.com>
Cc: Axel Rasmussen <axelrasmussen@google.com>
Cc: Yuanchu Xie <yuanchu@google.com>
Cc: Wei Xu <weixugc@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: T.J. Mercier <tjmercier@google.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/vmscan.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 512a31d7ae9e6..de7a50570db36 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -4752,10 +4752,6 @@ static bool should_abort_scan(struct lruvec *lruvec, struct scan_control *sc)
int i;
enum zone_watermarks mark;
- /* don't abort memcg reclaim to ensure fairness */
- if (!root_reclaim(sc))
- return false;
-
if (sc->nr_reclaimed >= max(sc->nr_to_reclaim, compact_gap(sc->order)))
return true;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 017/670] smb: client: validate SMB1 EA list bounds before parsing
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (15 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 016/670] mm: remove !root_reclaim checking in should_abort_scan() Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 018/670] xfs: break out xattr entry checks into separate functions Greg Kroah-Hartman
` (654 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ratnaker Gautam, Paulo Alcantara,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ratnaker Gautam <ratnaker.gautam@kuleuven.be>
[ Upstream commit ddc7a7e1eeb116ccaf010a6f1fb6ab927f3f888d ]
CIFSSMBQAllEAs() checks the server-provided EA list length by adding it
to the response pointer. On 32-bit systems, a positive length can wrap
the pointer and pass the comparison. The parser then walks outside the
received response while reading the next FEA header.
A response with a list length of 0x40000000 reproduces this as a native
i386 page fault and kernel panic from listxattr() against an SMB1
server.
Check that the EA list starts within the SMB byte area before reading
its header. Keep its length unsigned and compare it with the bytes left
in the response without pointer addition.
SMB1 is not negotiated by default and requires an explicit vers=1.0
mount.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Ratnaker Gautam <ratnaker.gautam@kuleuven.be>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
[ sashal: Replaced unavailable smb_EIO2() tracing calls with direct -EIO assignments. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/cifssmb.c | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index 45c6eb11356ba..1c2b73bdef6cb 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -5763,9 +5763,11 @@ CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
int bytes_returned;
int list_len;
+ u32 ea_list_len;
struct fealist *ea_response_data;
struct fea *temp_fea;
char *temp_ptr;
+ char *byte_area;
char *end_of_smb;
__u16 params, byte_count, data_offset;
unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
@@ -5842,9 +5844,18 @@ CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
ea_response_data = (struct fealist *)
(((char *) &pSMBr->hdr.Protocol) + data_offset);
- list_len = le32_to_cpu(ea_response_data->list_len);
- cifs_dbg(FYI, "ea length %d\n", list_len);
- if (list_len <= 8) {
+ byte_area = pByteArea(&pSMBr->hdr);
+ end_of_smb = byte_area + get_bcc(&pSMBr->hdr);
+ if ((char *)ea_response_data < byte_area ||
+ (char *)ea_response_data >
+ end_of_smb - sizeof(ea_response_data->list_len)) {
+ rc = -EIO;
+ goto QAllEAsOut;
+ }
+
+ ea_list_len = le32_to_cpu(ea_response_data->list_len);
+ cifs_dbg(FYI, "%s: ea length: %u\n", __func__, ea_list_len);
+ if (ea_list_len <= 8) {
cifs_dbg(FYI, "empty EA list returned from server\n");
/* didn't find the named attribute */
if (ea_name)
@@ -5853,12 +5864,12 @@ CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
}
/* make sure list_len doesn't go past end of SMB */
- end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
- if ((char *)ea_response_data + list_len > end_of_smb) {
+ if (ea_list_len > end_of_smb - (char *)ea_response_data) {
cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
rc = -EIO;
goto QAllEAsOut;
}
+ list_len = ea_list_len;
/* account for ea list len */
list_len -= 4;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 018/670] xfs: break out xattr entry checks into separate functions
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (16 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 017/670] smb: client: validate SMB1 EA list bounds before parsing Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 019/670] xfs: check for buffer overruns when examining local/remote xattr entries Greg Kroah-Hartman
` (653 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit 9eb04a6d41c7e474d4665118895c3c2d8e5a2741 ]
We're going to add more xattr entry checking code in xchk_xattr_entry so
break these out into separate functions so that we don't go crazy
indenting. There's a slight behavior change here where we skip updating
the usedmap if we've decided the xattr structure is corrupt.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Stable-dep-of: 91c41f952490 ("xfs: check for buffer overruns when examining local/remote xattr entries")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/attr.c | 90 ++++++++++++++++++++++++++++++++++-----------
1 file changed, 68 insertions(+), 22 deletions(-)
diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c
index 7315d0cb1e2e7..84507c80cf945 100644
--- a/fs/xfs/scrub/attr.c
+++ b/fs/xfs/scrub/attr.c
@@ -293,6 +293,66 @@ xchk_xattr_set_map(
return ret;
}
+static unsigned int
+xchk_xattr_local_entry(
+ struct xchk_da_btree *ds,
+ int level,
+ char *buf_end,
+ struct xfs_attr_leafblock *leaf,
+ int idx)
+{
+ struct xfs_attr_leaf_name_local *lentry =
+ xfs_attr3_leaf_name_local(leaf, idx);
+ char *name_end;
+ unsigned int namesize;
+
+ namesize = xfs_attr_leaf_entsize_local(lentry->namelen,
+ be16_to_cpu(lentry->valuelen));
+ name_end = (char *)lentry + namesize;
+ if (lentry->namelen == 0) {
+ xchk_da_set_corrupt(ds, level);
+ return 0;
+ }
+ if (name_end > buf_end) {
+ xchk_da_set_corrupt(ds, level);
+ return 0;
+ }
+
+ return namesize;
+}
+
+static unsigned int
+xchk_xattr_remote_entry(
+ struct xchk_da_btree *ds,
+ int level,
+ char *buf_end,
+ struct xfs_attr_leafblock *leaf,
+ int idx,
+ struct xfs_attr_leaf_entry *ent)
+{
+ struct xfs_attr_leaf_name_remote *rentry =
+ xfs_attr3_leaf_name_remote(leaf, idx);
+ char *name_end;
+ unsigned int namesize;
+
+ namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
+ name_end = (char *)rentry + namesize;
+ if (rentry->namelen == 0) {
+ xchk_da_set_corrupt(ds, level);
+ return 0;
+ }
+ if (rentry->valueblk == 0 && !(ent->flags & XFS_ATTR_INCOMPLETE)) {
+ xchk_da_set_corrupt(ds, level);
+ return 0;
+ }
+ if (name_end > buf_end) {
+ xchk_da_set_corrupt(ds, level);
+ return 0;
+ }
+
+ return namesize;
+}
+
/*
* Check this leaf entry's relations to everything else.
* Returns the number of bytes used for the name/value data.
@@ -311,9 +371,6 @@ xchk_xattr_entry(
{
struct xfs_mount *mp = ds->state->mp;
struct xchk_xattr_buf *ab = ds->sc->buf;
- char *name_end;
- struct xfs_attr_leaf_name_local *lentry;
- struct xfs_attr_leaf_name_remote *rentry;
unsigned int nameidx;
unsigned int namesize;
@@ -333,25 +390,14 @@ xchk_xattr_entry(
}
/* Check the name information. */
- if (ent->flags & XFS_ATTR_LOCAL) {
- lentry = xfs_attr3_leaf_name_local(leaf, idx);
- namesize = xfs_attr_leaf_entsize_local(lentry->namelen,
- be16_to_cpu(lentry->valuelen));
- name_end = (char *)lentry + namesize;
- if (lentry->namelen == 0)
- xchk_da_set_corrupt(ds, level);
- } else {
- rentry = xfs_attr3_leaf_name_remote(leaf, idx);
- namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
- name_end = (char *)rentry + namesize;
- if (rentry->namelen == 0)
- xchk_da_set_corrupt(ds, level);
- if (rentry->valueblk == 0 &&
- !(ent->flags & XFS_ATTR_INCOMPLETE))
- xchk_da_set_corrupt(ds, level);
- }
- if (name_end > buf_end)
- xchk_da_set_corrupt(ds, level);
+ if (ent->flags & XFS_ATTR_LOCAL)
+ namesize = xchk_xattr_local_entry(ds, level, buf_end, leaf,
+ idx);
+ else
+ namesize = xchk_xattr_remote_entry(ds, level, buf_end, leaf,
+ idx, ent);
+ if (!namesize)
+ return;
if (!xchk_xattr_set_map(ds->sc, ab->usedmap, nameidx, namesize))
xchk_da_set_corrupt(ds, level);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 019/670] xfs: check for buffer overruns when examining local/remote xattr entries
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (17 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 018/670] xfs: break out xattr entry checks into separate functions Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 020/670] xfs: refactor directory data block walking loops in scrub Greg Kroah-Hartman
` (652 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit 91c41f9524906a8ebd2ae68c98a07b4bd5255ddb ]
LOLLM noticed that the xattr scrub and repair code can walk off the end
of the buffer if the xattr entry record starts so close to the end of
the buffer that there's not even space for the entry structure itself.
Strengthen the bounds checking here.
Cc: stable@vger.kernel.org # v4.15
Fixes: 13791d3b833428 ("xfs: scrub extended attribute leaf space")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/attr.c | 12 ++++++++++++
fs/xfs/scrub/attr_repair.c | 16 +++++++++++++---
2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c
index 84507c80cf945..68d9666ab201a 100644
--- a/fs/xfs/scrub/attr.c
+++ b/fs/xfs/scrub/attr.c
@@ -306,6 +306,12 @@ xchk_xattr_local_entry(
char *name_end;
unsigned int namesize;
+ name_end = (char *)lentry + offsetof(typeof(*lentry), nameval[0]);
+ if (name_end > buf_end) {
+ xchk_da_set_corrupt(ds, level);
+ return 0;
+ }
+
namesize = xfs_attr_leaf_entsize_local(lentry->namelen,
be16_to_cpu(lentry->valuelen));
name_end = (char *)lentry + namesize;
@@ -335,6 +341,12 @@ xchk_xattr_remote_entry(
char *name_end;
unsigned int namesize;
+ name_end = (char *)rentry + offsetof(typeof(*rentry), name[0]);
+ if (name_end > buf_end) {
+ xchk_da_set_corrupt(ds, level);
+ return 0;
+ }
+
namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
name_end = (char *)rentry + namesize;
if (rentry->namelen == 0) {
diff --git a/fs/xfs/scrub/attr_repair.c b/fs/xfs/scrub/attr_repair.c
index ab5bd7a4d4abb..2c573897c0c6a 100644
--- a/fs/xfs/scrub/attr_repair.c
+++ b/fs/xfs/scrub/attr_repair.c
@@ -285,6 +285,7 @@ xrep_xattr_salvage_local_attr(
struct xfs_attr_leaf_name_local *lentry)
{
struct xchk_xattr_buf *ab = rx->sc->buf;
+ char *name_end;
unsigned char *value;
unsigned int valuelen;
unsigned int namesize;
@@ -293,10 +294,14 @@ xrep_xattr_salvage_local_attr(
* Decode the leaf local entry format. If something seems wrong, we
* junk the attribute.
*/
+ name_end = (char *)lentry + offsetof(typeof(*lentry), nameval[0]);
+ if (name_end > buf_end)
+ return 0;
value = &lentry->nameval[lentry->namelen];
valuelen = be16_to_cpu(lentry->valuelen);
namesize = xfs_attr_leaf_entsize_local(lentry->namelen, valuelen);
- if ((char *)lentry + namesize > buf_end)
+ name_end = (char *)lentry + namesize;
+ if (name_end > buf_end)
return 0;
if (!xrep_xattr_want_salvage(rx, ent->flags, lentry->nameval,
lentry->namelen, value, valuelen))
@@ -333,8 +338,8 @@ xrep_xattr_salvage_remote_attr(
.attr_filter = ent->flags & XFS_ATTR_NSP_ONDISK_MASK,
.namelen = rentry->namelen,
.name = rentry->name,
- .valuelen = be32_to_cpu(rentry->valuelen),
};
+ char *name_end;
unsigned int namesize;
int error;
@@ -343,9 +348,14 @@ xrep_xattr_salvage_remote_attr(
* junk the attribute. Note that we should never find a zero-length
* remote attribute value.
*/
+ name_end = (char *)rentry + offsetof(typeof(*rentry), name[0]);
+ if (name_end > buf_end)
+ return 0;
namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
- if ((char *)rentry + namesize > buf_end)
+ name_end = (char *)rentry + namesize;
+ if (name_end > buf_end)
return 0;
+ args.valuelen = be32_to_cpu(rentry->valuelen);
if (args.valuelen == 0 ||
!xrep_xattr_want_salvage(rx, ent->flags, rentry->name,
rentry->namelen, NULL, args.valuelen))
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 020/670] xfs: refactor directory data block walking loops in scrub
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (18 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 019/670] xfs: check for buffer overruns when examining local/remote xattr entries Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 021/670] xfs: improve dirent bounds checking in scrub and repair Greg Kroah-Hartman
` (651 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit 19b5653cc870788df71e7fcf2dd7b6131d8868dc ]
Hoist the inner loop code of the directory data block walking code in
the directory scrub and repair code to separate functions in preparation
for strengthening the validation in a subsequent patch.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Stable-dep-of: 5d470234d04d ("xfs: improve dirent bounds checking in scrub and repair")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/dir.c | 56 ++++++++++++++++++++++++++----
fs/xfs/scrub/dir_repair.c | 73 ++++++++++++++++++++++++++++-----------
2 files changed, 102 insertions(+), 27 deletions(-)
diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c
index 284f72ef2b584..7928dbe221d58 100644
--- a/fs/xfs/scrub/dir.c
+++ b/fs/xfs/scrub/dir.c
@@ -305,6 +305,45 @@ xchk_dir_actor(
return error;
}
+/*
+ * Deal with an unused directory entry. Returns a positive number of bytes to
+ * advance in the directory block, zero to stop processing, or -1 if corruption
+ * was found.
+ */
+static int
+xchk_dir_check_unused(
+ struct xchk_da_btree *ds,
+ struct xfs_buf *bp,
+ unsigned int iter_off,
+ unsigned int end)
+{
+ struct xfs_dir2_data_unused *dup = bp->b_addr + iter_off;
+
+ return be16_to_cpu(dup->length);
+}
+
+/*
+ * Check a directory entry. Returns a positive number of bytes to advance
+ * in the directory block, zero to stop processing, or -1 if corruption was
+ * found.
+ */
+static int
+xchk_dir_check_entry(
+ struct xchk_da_btree *ds,
+ struct xfs_buf *bp,
+ unsigned int iter_off,
+ unsigned int end,
+ struct xfs_dir2_data_entry *dent)
+{
+ struct xfs_dir2_data_entry *dep = bp->b_addr + iter_off;
+ struct xfs_mount *mp = ds->state->mp;
+
+ if (dep == dent)
+ return 0;
+
+ return xfs_dir2_data_entsize(mp, dep->namelen);
+}
+
/* Scrub a directory btree record. */
STATIC int
xchk_dir_rec(
@@ -381,21 +420,24 @@ xchk_dir_rec(
goto out_relse;
}
for (;;) {
- struct xfs_dir2_data_entry *dep = bp->b_addr + iter_off;
struct xfs_dir2_data_unused *dup = bp->b_addr + iter_off;
+ int advance;
if (iter_off >= end) {
xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
goto out_relse;
}
- if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
- iter_off += be16_to_cpu(dup->length);
- continue;
- }
- if (dep == dent)
+ if (dup->freetag == cpu_to_be16(XFS_DIR2_DATA_FREE_TAG))
+ advance = xchk_dir_check_unused(ds, bp, iter_off, end);
+ else
+ advance = xchk_dir_check_entry(ds, bp, iter_off, end,
+ dent);
+ if (advance < 0)
+ goto out_relse;
+ if (!advance)
break;
- iter_off += xfs_dir2_data_entsize(mp, dep->namelen);
+ iter_off += advance;
}
/* Retrieve the entry, sanity check it, and compare hashes. */
diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c
index 2bc2354cd85d4..4c565f7bcd290 100644
--- a/fs/xfs/scrub/dir_repair.c
+++ b/fs/xfs/scrub/dir_repair.c
@@ -456,6 +456,52 @@ xrep_dir_salvage_data_entry(
return xrep_dir_salvage_entry(rd, dep->name, dep->namelen, ino);
}
+/*
+ * Deal with an unused directory entry. Returns a positive number of bytes to
+ * advance in the directory block, or zero to stop processing.
+ */
+static int
+xrep_dir_recover_unused(
+ struct xfs_buf *bp,
+ unsigned int offset,
+ unsigned int end)
+{
+ struct xfs_dir2_data_unused *dup = bp->b_addr + offset;
+
+ return be16_to_cpu(dup->length);
+}
+
+/*
+ * Salvage a directory entry. Returns a positive number of bytes to advance
+ * in the directory block, zero to stop processing, or a negative errno.
+ */
+static int
+xrep_dir_recover_entry(
+ struct xrep_dir *rd,
+ struct xfs_buf *bp,
+ unsigned int offset,
+ unsigned int end)
+{
+ struct xfs_dir2_data_entry *dep = bp->b_addr + offset;
+ unsigned int advance;
+ int error;
+
+ /* Don't walk off the end of the block. */
+ advance = xfs_dir2_data_entsize(rd->sc->mp, dep->namelen);
+ if (!advance)
+ return 0;
+ if (offset + advance > end)
+ return 0;
+
+ /* Ok, let's save this entry. */
+ error = xrep_dir_salvage_data_entry(rd, dep);
+ if (error < 0)
+ return error;
+
+ return advance;
+}
+
+
/* Try to recover block/data format directory entries. */
STATIC int
xrep_dir_recover_data(
@@ -477,33 +523,20 @@ xrep_dir_recover_data(
while (offset < end) {
struct xfs_dir2_data_unused *dup = bp->b_addr + offset;
- struct xfs_dir2_data_entry *dep = bp->b_addr + offset;
- unsigned int advance;
+ int advance;
if (xchk_should_terminate(rd->sc, &error))
return error;
- /* Skip unused entries. */
- if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
- if (!dup->length)
- break;
- offset += be16_to_cpu(dup->length);
- continue;
- }
-
- /* Don't walk off the end of the block. */
- advance = xfs_dir2_data_entsize(rd->sc->mp, dep->namelen);
+ if (dup->freetag == cpu_to_be16(XFS_DIR2_DATA_FREE_TAG))
+ advance = xrep_dir_recover_unused(bp, offset, end);
+ else
+ advance = xrep_dir_recover_entry(rd, bp, offset, end);
+ if (advance < 0)
+ return advance;
if (!advance)
break;
offset += advance;
- if (offset > end)
- break;
-
- /* Ok, let's save this entry. */
- error = xrep_dir_salvage_data_entry(rd, dep);
- if (error)
- return error;
-
}
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 021/670] xfs: improve dirent bounds checking in scrub and repair
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (19 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 020/670] xfs: refactor directory data block walking loops in scrub Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 022/670] NFSv4/pnfs: bound the CB_NOTIFY_DEVICEID array count before allocating Greg Kroah-Hartman
` (650 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit 5d470234d04dae6fe2ca2cf4b9ef277b78c7e05a ]
LOLLM complains that we don't do enough bounds checking of the directory
entries in directory blocks when we're looking for errors or trying to
salvage entries. Let's improve that with more detailed checks.
Cc: stable@vger.kernel.org # v4.16
Fixes: ce92d29ddf9908 ("xfs: directory scrubber must walk through data block to offset")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/dir.c | 68 +++++++++++++++++++++++++++++++++------
fs/xfs/scrub/dir_repair.c | 37 ++++++++++++++++++---
2 files changed, 91 insertions(+), 14 deletions(-)
diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c
index 7928dbe221d58..2bb5ead7cffd0 100644
--- a/fs/xfs/scrub/dir.c
+++ b/fs/xfs/scrub/dir.c
@@ -315,11 +315,24 @@ xchk_dir_check_unused(
struct xchk_da_btree *ds,
struct xfs_buf *bp,
unsigned int iter_off,
- unsigned int end)
+ unsigned int end,
+ xfs_dablk_t rec_bno)
{
struct xfs_dir2_data_unused *dup = bp->b_addr + iter_off;
+ unsigned int advance;
+
+ if (iter_off + sizeof(*dup) > end) {
+ xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
+ return -1;
+ }
+
+ advance = xfs_dir2_data_unusedsize(be16_to_cpu(dup->length));
+ if (!advance || iter_off + advance > end) {
+ xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
+ return -1;
+ }
- return be16_to_cpu(dup->length);
+ return advance;
}
/*
@@ -333,15 +346,31 @@ xchk_dir_check_entry(
struct xfs_buf *bp,
unsigned int iter_off,
unsigned int end,
- struct xfs_dir2_data_entry *dent)
+ struct xfs_dir2_data_entry *dent,
+ xfs_dablk_t rec_bno)
{
struct xfs_dir2_data_entry *dep = bp->b_addr + iter_off;
struct xfs_mount *mp = ds->state->mp;
+ unsigned int advance;
+
+ /* must have namelen */
+ advance = offsetof(typeof(*dep), name);
+ if (iter_off + advance >= end) {
+ xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
+ return -1;
+ }
+
+ /* Don't walk off the end of the block. */
+ advance = xfs_dir2_data_entsize(mp, dep->namelen);
+ if (!advance || iter_off + advance > end) {
+ xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
+ return -1;
+ }
if (dep == dent)
return 0;
- return xfs_dir2_data_entsize(mp, dep->namelen);
+ return advance;
}
/* Scrub a directory btree record. */
@@ -369,6 +398,7 @@ xchk_dir_rec(
xfs_dahash_t hash;
struct xfs_dir3_icleaf_hdr hdr;
unsigned int tag;
+ bool foundit = false;
int error;
ASSERT(blk->magic == XFS_DIR2_LEAF1_MAGIC ||
@@ -413,33 +443,44 @@ xchk_dir_rec(
dent = bp->b_addr + off;
/* Make sure we got a real directory entry. */
- iter_off = geo->data_entry_offset;
end = xfs_dir3_data_end_offset(geo, bp->b_addr);
if (!end) {
xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
goto out_relse;
}
- for (;;) {
+ iter_off = geo->data_entry_offset;
+ while (iter_off < end) {
struct xfs_dir2_data_unused *dup = bp->b_addr + iter_off;
int advance;
- if (iter_off >= end) {
+ /* must have freetag */
+ advance = offsetof(typeof(*dup), length);
+ if (iter_off + advance >= end) {
xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
goto out_relse;
}
if (dup->freetag == cpu_to_be16(XFS_DIR2_DATA_FREE_TAG))
- advance = xchk_dir_check_unused(ds, bp, iter_off, end);
+ advance = xchk_dir_check_unused(ds, bp, iter_off, end,
+ rec_bno);
else
advance = xchk_dir_check_entry(ds, bp, iter_off, end,
- dent);
+ dent, rec_bno);
if (advance < 0)
goto out_relse;
- if (!advance)
+ if (!advance) {
+ foundit = true;
break;
+ }
iter_off += advance;
}
+ /* Hash tree must point to the exact dirent */
+ if (!foundit) {
+ xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
+ goto out_relse;
+ }
+
/* Retrieve the entry, sanity check it, and compare hashes. */
ino = be64_to_cpu(dent->inumber);
hash = be32_to_cpu(ent->hashval);
@@ -451,6 +492,13 @@ xchk_dir_rec(
goto out_relse;
}
+ /* Name must not overflow end of block */
+ if ((char *)dent->name + dent->namelen >
+ (char *)bp->b_addr + BBTOB(bp->b_length)) {
+ xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno);
+ goto out_relse;
+ }
+
/* Does the directory hash match? */
dname.name = dent->name;
dname.len = dent->namelen;
diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c
index 4c565f7bcd290..72fe0ae3e18de 100644
--- a/fs/xfs/scrub/dir_repair.c
+++ b/fs/xfs/scrub/dir_repair.c
@@ -467,8 +467,16 @@ xrep_dir_recover_unused(
unsigned int end)
{
struct xfs_dir2_data_unused *dup = bp->b_addr + offset;
+ unsigned int advance;
+
+ if (offset + sizeof(*dup) > end)
+ return 0;
+
+ advance = xfs_dir2_data_unusedsize(be16_to_cpu(dup->length));
+ if (!advance || offset + advance > end)
+ return 0;
- return be16_to_cpu(dup->length);
+ return advance;
}
/*
@@ -486,11 +494,14 @@ xrep_dir_recover_entry(
unsigned int advance;
int error;
+ /* must have namelen */
+ advance = offsetof(typeof(*dep), name);
+ if (offset + advance >= end)
+ return 0;
+
/* Don't walk off the end of the block. */
advance = xfs_dir2_data_entsize(rd->sc->mp, dep->namelen);
- if (!advance)
- return 0;
- if (offset + advance > end)
+ if (!advance || offset + advance > end)
return 0;
/* Ok, let's save this entry. */
@@ -528,6 +539,11 @@ xrep_dir_recover_data(
if (xchk_should_terminate(rd->sc, &error))
return error;
+ /* must have freetag */
+ advance = offsetof(typeof(*dup), length);
+ if (offset + advance >= end)
+ break;
+
if (dup->freetag == cpu_to_be16(XFS_DIR2_DATA_FREE_TAG))
advance = xrep_dir_recover_unused(bp, offset, end);
else
@@ -559,6 +575,19 @@ xrep_dir_recover_sf(
hdr = ifp->if_data;
end = (unsigned char *)ifp->if_data + ifp->if_bytes;
+ /* sf header must be big enough for count/i8count */
+ if (!hdr || ifp->if_bytes < 2)
+ return 0;
+
+ /* and large enough for the parent inumber */
+ if (hdr->i8count) {
+ if (ifp->if_bytes < offsetof(struct xfs_dir2_sf_hdr, parent[8]))
+ return 0;
+ } else {
+ if (ifp->if_bytes < offsetof(struct xfs_dir2_sf_hdr, parent[4]))
+ return 0;
+ }
+
ino = xfs_dir2_sf_get_parent_ino(hdr);
trace_xrep_dir_salvaged_parent(rd->sc->ip, ino);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 022/670] NFSv4/pnfs: bound the CB_NOTIFY_DEVICEID array count before allocating
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (20 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 021/670] xfs: improve dirent bounds checking in scrub and repair Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 023/670] smb: client: bound POSIX lock data area by response length Greg Kroah-Hartman
` (649 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Benjamin Coddington, Anna Schumaker,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Coddington <ben.coddington@hammerspace.com>
[ Upstream commit 32f0967ea296d447925465c98e7eec71d4e2f755 ]
decode_devicenotify_args() hands the server's notification count
straight to kmalloc_objs() as the array length, without checking it
against the message that carried it. Bound it the way nfs4xdr.c bounds
an attribute length, against xdr_stream_remaining().
Fixes: 1be5683b03a7 ("pnfs: CB_NOTIFY_DEVICEID")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-fable-5
Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com>
Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
[ sashal: adapted allocation context from kmalloc_objs() to kmalloc_array() with an explicit element size and GFP_KERNEL ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfs/callback_xdr.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 1aa6a6e14b057..34fa00f1a1c20 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -275,6 +275,13 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
if (n == 0)
goto out;
+ /* sanity check the count against the remaining stream */
+ if (n > xdr_stream_remaining(xdr) /
+ ((4 * sizeof(uint32_t)) + NFS4_DEVICEID4_SIZE)) {
+ status = htonl(NFS4ERR_BADXDR);
+ goto out;
+ }
+
args->devs = kmalloc_array(n, sizeof(*args->devs), GFP_KERNEL);
if (!args->devs) {
status = htonl(NFS4ERR_DELAY);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 023/670] smb: client: bound POSIX lock data area by response length
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (21 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 022/670] NFSv4/pnfs: bound the CB_NOTIFY_DEVICEID array count before allocating Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 024/670] NFSD: map fh_verify() status codes for NFS_ACLv2 replies Greg Kroah-Hartman
` (648 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ratnaker Gautam, Namjae Jeon,
Paulo Alcantara, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ratnaker Gautam <ratnaker.gautam@kuleuven.be>
[ Upstream commit 8fc9af68c57156ff64769f30e831553cd03b3000 ]
CIFSSMBPosixLock() receives a TRANS2 response whose server-provided
DataOffset and DataCount are not required by validate_t2() to describe an
interval inside the response. A server can therefore make the client read a
cifs_posix_lock beyond the response buffer and return those kernel bytes
through F_GETLK.
Use smbCalcSize() to obtain the full response length after any multipart
TRANS2 reassembly, then reject data areas that extend past it before
dereferencing them.
Fixes: fc94cdb94462 ("[CIFS] Fix new POSIX Locking for setting lock_type correctly on unlock")
Reported-by: Ratnaker Gautam <ratnaker.gautam@kuleuven.be>
Cc: stable@vger.kernel.org
Signed-off-by: Ratnaker Gautam <ratnaker.gautam@kuleuven.be>
Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
[ sashal: Subtracted the four-byte RFC1001 prefix from smbCalcSize() and replaced unavailable smb_EIO2() tracing with -EIO. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/cifssmb.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index 1c2b73bdef6cb..8062b0328e07d 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -2092,6 +2092,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
} else if (pLockData) {
/* lock structure can be returned on get */
+ unsigned int rsp_len;
__u16 data_offset;
__u16 data_count;
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
@@ -2102,10 +2103,16 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
}
data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
data_count = le16_to_cpu(pSMBr->t2.DataCount);
+ rsp_len = smbCalcSize(&pSMBr->hdr) - 4;
if (data_count < sizeof(struct cifs_posix_lock)) {
rc = -EIO;
goto plk_err_exit;
}
+ if (data_offset > rsp_len ||
+ data_count > rsp_len - data_offset) {
+ rc = -EIO;
+ goto plk_err_exit;
+ }
parm_data = (struct cifs_posix_lock *)
((char *)&pSMBr->hdr.Protocol + data_offset);
if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 024/670] NFSD: map fh_verify() status codes for NFS_ACLv2 replies
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (22 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 023/670] smb: client: bound POSIX lock data area by response length Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 025/670] nfsd: dont offer flexfiles layouts when NFSv3 isnt being served Greg Kroah-Hartman
` (647 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeff Layton, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <cel@kernel.org>
[ Upstream commit ccfc4db5ab740175b9958ea0cf5986957bf4e659 ]
The NFS_ACL v2 protocol shares its status code space with NFSv2,
which has no NFSERR_BADHANDLE and no NFSERR_NOFILEHANDLE. An
NFS_ACLv2 GETACL, SETACL, GETATTR, or ACCESS request that carries a
malformed or empty file handle gets a reply with status 10001 or
10020, values the client cannot interpret.
Commit 1459ad57673b ("nfsd: Move error code mapping to per-version
proc code.") removed the version check from fh_verify() that turned
those codes into NFSERR_STALE for any version 2 program. The NFSv2
procedures gained nfsd_map_status() in exchange, but the NFS_ACL v2
procedures did not, so the unmapped status reaches the encoder.
Add the same mapping to the NFS_ACL v2 procedures.
Fixes: 1459ad57673b ("nfsd: Move error code mapping to per-version proc code.")
Cc: stable@vger.kernel.org
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260916004240.141975-1-cel@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
[ sashal: Placed nfsacld_map_status() before the NULL handler because the upstream access-map declarations are absent. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfs2acl.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index 2998640f259de..cf92e1f8df7d2 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -15,6 +15,20 @@
#define NFSDDBG_FACILITY NFSDDBG_PROC
+static __be32 nfsacld_map_status(__be32 status)
+{
+ switch (status) {
+ case nfserr_nofilehandle:
+ case nfserr_badhandle:
+ status = nfserr_stale;
+ break;
+ case nfserr_wrongsec:
+ status = nfserr_acces;
+ break;
+ }
+ return status;
+}
+
/*
* NULL call.
*/
@@ -79,6 +93,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
/* resp->acl_{access,default} are released in nfssvc_release_getacl. */
out:
+ resp->status = nfsacld_map_status(resp->status);
return rpc_success;
fail:
@@ -137,6 +152,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
out:
/* argp->acl_{access,default} are released in nfsaclsvc_release_setacl. */
+ resp->status = nfsacld_map_status(resp->status);
return rpc_success;
out_drop_lock:
@@ -163,6 +179,7 @@ static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp)
goto out;
resp->status = fh_getattr(&resp->fh, &resp->stat);
out:
+ resp->status = nfsacld_map_status(resp->status);
return rpc_success;
}
@@ -185,6 +202,7 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp)
goto out;
resp->status = fh_getattr(&resp->fh, &resp->stat);
out:
+ resp->status = nfsacld_map_status(resp->status);
return rpc_success;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 025/670] nfsd: dont offer flexfiles layouts when NFSv3 isnt being served
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (23 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 024/670] NFSD: map fh_verify() status codes for NFS_ACLv2 replies Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 026/670] NFSD: report listener creation failures through extack Greg Kroah-Hartman
` (646 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Benji Wiebe, Jeff Layton,
Chuck Lever, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <jlayton@kernel.org>
[ Upstream commit 5d28b2c920d9d9d3c45b41769342ad785eb372a7 ]
The flexfiles layout driver hands out a deviceinfo that names this server
as an NFSv3 DS (flexfilelayout.c hardcodes da->version = 3). With v3
disabled, the client can't talk to the DS: it loops on v3 NULL calls that
the server answers with PROG_MISMATCH, and I/O hangs in D state.
Skip LAYOUT_FLEX_FILES in nfsd4_setup_layout_type() unless v3 is enabled.
Reported-by: Benji Wiebe <itsme@benjiwiebe.com>
Closes: https://lore.kernel.org/linux-nfs/c734eeb8-8486-4491-bb4d-b9656cbaffbe@app.fastmail.com/
Fixes: 9b9960a0ca47 ("nfsd: Add a super simple flex file server")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260904-pnfs-ff-v1-1-5f502cf25401@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
[ sashal: adapted the flexfiles condition to the older layout-selection code that uses direct block/SCSI checks ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfs4layouts.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c
index 0ff8994752637..a78e0bfdc9363 100644
--- a/fs/nfsd/nfs4layouts.c
+++ b/fs/nfsd/nfs4layouts.c
@@ -125,6 +125,7 @@ nfsd4_set_deviceid(struct nfsd4_deviceid *id, const struct svc_fh *fhp,
void nfsd4_setup_layout_type(struct svc_export *exp)
{
+ struct nfsd_net *nn = net_generic(exp->cd->net, nfsd_net_id);
#if defined(CONFIG_NFSD_BLOCKLAYOUT) || defined(CONFIG_NFSD_SCSILAYOUT)
struct super_block *sb = exp->ex_path.mnt->mnt_sb;
#endif
@@ -132,9 +133,9 @@ void nfsd4_setup_layout_type(struct svc_export *exp)
if (!(exp->ex_flags & NFSEXP_PNFS))
return;
-#ifdef CONFIG_NFSD_FLEXFILELAYOUT
- exp->ex_layout_types |= 1 << LAYOUT_FLEX_FILES;
-#endif
+ if (IS_ENABLED(CONFIG_NFSD_FLEXFILELAYOUT) &&
+ nfsd_vers(nn, 3, NFSD_TEST))
+ exp->ex_layout_types |= 1 << LAYOUT_FLEX_FILES;
#ifdef CONFIG_NFSD_BLOCKLAYOUT
if (sb->s_export_op->get_uuid &&
sb->s_export_op->map_blocks &&
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 026/670] NFSD: report listener creation failures through extack
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (24 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 025/670] nfsd: dont offer flexfiles layouts when NFSv3 isnt being served Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 027/670] SUNRPC: report local rpcbind calls that get no answer Greg Kroah-Hartman
` (645 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeff Layton, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <jlayton@kernel.org>
[ Upstream commit 8e590a16853fedd2697a3b0c32b3cbf1a444f7b2 ]
nfsd_nl_listener_set_doit() returns the raw errno from
svc_xprt_create_from_sa() and sets no extack. A failed LISTENER_SET
therefore tells userland only "Address already in use", or whatever else
the transport returned. It never tells userland which entry failed.
Record the attribute and the transport name of the entry whose errno the
call returns, and report both after the loop. NL_SET_BAD_ATTR() names the
entry, which the message alone cannot do: a request can carry several
entries with the same transport name.
The rejections in nfsd_nl_validate_listeners() other than -E2BIG and the
unsupported transport name still carry no extack. This patch does not
change them.
Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260901-nfsd-nl-hang-v5-5-a540d86668b0@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Stable-dep-of: bf0f3a37e6cc ("NFSD: stop registering with rpcbind after a failure in listener_set")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfsctl.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 2a225756ef0d8..ecfdd8e5fd3d3 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -2107,7 +2107,9 @@ static int nfsd_nl_validate_listeners(struct genl_info *info)
int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
{
struct net *net = genl_info_net(info);
+ const struct nlattr *bad_attr = NULL;
struct svc_xprt *xprt, *tmp;
+ const char *bad_xprt = NULL;
const struct nlattr *attr;
struct svc_serv *serv;
LIST_HEAD(permsocks);
@@ -2226,8 +2228,22 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
ret = svc_xprt_create_from_sa(serv, xcl_name, net, sa, 0,
current_cred());
/* always save the latest error */
- if (ret < 0)
+ if (ret < 0) {
+ bad_attr = attr;
+ bad_xprt = xcl_name;
err = ret;
+ }
+ }
+
+ /*
+ * The ack carries the errno of the last entry that failed. Point at
+ * that entry as well, since several entries can share a transport
+ * name and the errno alone cannot tell them apart.
+ */
+ if (err) {
+ NL_SET_BAD_ATTR(info->extack, bad_attr);
+ NL_SET_ERR_MSG_FMT(info->extack, "cannot create %s listener",
+ bad_xprt);
}
if (!serv->sv_nrthreads && list_empty(&nn->nfsd_serv->sv_permsocks))
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 027/670] SUNRPC: report local rpcbind calls that get no answer
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (25 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 026/670] NFSD: report listener creation failures through extack Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 028/670] NFSD: stop registering with rpcbind after a failure in listener_set Greg Kroah-Hartman
` (644 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeff Layton, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <jlayton@kernel.org>
[ Upstream commit 202a557d0c8e65c7fd7fcff2ad2756468d1ab711 ]
A caller that creates many listeners in one operation calls svc_register()
once for each of them. Every call waits for the local rpcbind on its own,
so a rpcbind that never answers costs the caller one timeout per listener.
The caller has no way to learn that the first call already failed.
Split rpcb_register_call() failures by whether rpcbind answered:
- answered: a FALSE reply, or an RPC-level rejection that
rpc_decode_header() derives from the reply. -EACCES (FALSE reply or
AUTH_ERROR), -EPROTONOSUPPORT, -EPFNOSUPPORT, -EOPNOTSUPP.
- never sent: -ENOMEM, -EMSGSIZE, -ERESTARTSYS.
- no answer: everything else, i.e. transport errors.
Any no-answer error gets represented by -EIO, which is already what the
RPC layer reports for most of it: rpc_check_timeout() returns -EIO for a
soft timeout without RPC_TASK_TIMEOUT, and call_status() documents -EIO
as "shutdown or soft timeout".
Keep a count of the number of rpcbind failures in the serv. Later
patches will use that to watch for hard rpcbind failures, and alter
their behavior accordingly.
Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260901-nfsd-nl-hang-v5-6-a540d86668b0@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Stable-dep-of: bf0f3a37e6cc ("NFSD: stop registering with rpcbind after a failure in listener_set")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/sunrpc/clnt.h | 3 ++-
include/linux/sunrpc/svc.h | 7 +++++--
net/sunrpc/rpcb_clnt.c | 22 ++++++++++++++++---
net/sunrpc/svc.c | 42 ++++++++++++++++++++++++++++++++++++-
4 files changed, 67 insertions(+), 7 deletions(-)
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index bd6ac060450cb..acdb31039c35f 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -195,7 +195,8 @@ struct rpc_xprt *rpc_task_get_xprt(struct rpc_clnt *clnt,
int rpcb_create_local(struct net *);
void rpcb_put_local(struct net *);
-int rpcb_register(struct net *, u32, u32, int, unsigned short);
+int rpcb_register(struct net *net, u32 prog, u32 vers, int prot,
+ unsigned short port);
int rpcb_v4_register(struct net *net, const u32 program,
const u32 version,
const struct sockaddr *address,
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 79f3c5c1d0e9f..b7a61aafc2dd1 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -79,6 +79,7 @@ struct svc_serv {
unsigned int sv_max_payload; /* datagram payload size */
unsigned int sv_max_mesg; /* max_payload + 1 page for overheads */
unsigned int sv_xdrsize; /* XDR buffer size */
+ atomic_t sv_rpcb_failures; /* unanswered rpcbind calls */
struct list_head sv_permsocks; /* all permanent sockets */
struct list_head sv_tempsocks; /* all temporary sockets */
int sv_tmpcnt; /* count of temporary "valid" sockets */
@@ -451,6 +452,7 @@ int sunrpc_set_pool_mode(const char *val);
int sunrpc_get_pool_mode(char *val, size_t size);
void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
int svc_bind(struct svc_serv *serv, struct net *net);
+unsigned int svc_rpcb_failure_count(struct svc_serv *serv);
struct svc_serv *svc_create(struct svc_program *, unsigned int,
int (*threadfn)(void *data));
bool svc_rqst_replace_page(struct svc_rqst *rqstp,
@@ -466,8 +468,9 @@ int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
int svc_pool_stats_open(struct svc_info *si, struct file *file);
void svc_process(struct svc_rqst *rqstp);
void svc_process_bc(struct rpc_rqst *req, struct svc_rqst *rqstp);
-int svc_register(const struct svc_serv *, struct net *, const int,
- const unsigned short, const unsigned short);
+int svc_register(struct svc_serv *serv, struct net *net,
+ const int family, const unsigned short proto,
+ const unsigned short port);
void svc_wake_up(struct svc_serv *);
void svc_reserve(struct svc_rqst *rqstp, int space);
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 2d74c660de666..9b90350820be4 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -400,7 +400,8 @@ static struct rpc_clnt *rpcb_create(struct net *net, const char *nodename,
return rpc_create(&args);
}
-static int rpcb_register_call(struct sunrpc_net *sn, struct rpc_clnt *clnt, struct rpc_message *msg, bool is_set)
+static int rpcb_register_call(struct sunrpc_net *sn, struct rpc_clnt *clnt,
+ struct rpc_message *msg, bool is_set)
{
int flags = RPC_TASK_NOCONNECT;
int error, result = 0;
@@ -410,8 +411,23 @@ static int rpcb_register_call(struct sunrpc_net *sn, struct rpc_clnt *clnt, stru
msg->rpc_resp = &result;
error = rpc_call_sync(clnt, msg, flags);
- if (error < 0)
- return error;
+ if (error < 0) {
+ switch (error) {
+ /* rpcbind answered; the reply itself carries the error */
+ case -EPROTONOSUPPORT:
+ case -EPFNOSUPPORT:
+ case -EOPNOTSUPP:
+ case -EACCES:
+ /* the call never made it onto the wire */
+ case -ENOMEM:
+ case -EMSGSIZE:
+ /* the caller is going away; this says nothing about rpcbind */
+ case -ERESTARTSYS:
+ return error;
+ }
+ /* anything else, we assume that rpcbind isn't functional */
+ return -EIO;
+ }
if (!result)
return -EACCES;
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 4b4a2890a874a..6d43f479342da 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -1204,10 +1204,40 @@ int svc_generic_rpcbind_set(struct net *net,
error = svc_rpcbind_set_version(net, progp, version,
family, proto, port);
+ /* -EIO means no answer, not a refusal, so vs_rpcb_optnl must keep it. */
+ if (error == -EIO)
+ return error;
+
return (vers->vs_rpcb_optnl) ? 0 : error;
}
EXPORT_SYMBOL_GPL(svc_generic_rpcbind_set);
+/**
+ * svc_rpcb_failure_count - local rpcbind calls for @serv that got no answer
+ * @serv: RPC service to query
+ *
+ * svc_register() adds one for each of its calls that got no answer. A reply
+ * that refuses one entry does not count, because rpcbind answered and the
+ * next entry may still succeed.
+ *
+ * The count is kept per serv rather than per net. The local rpcbind client
+ * is per-net and lockd shares it, but a count that another service can move
+ * says nothing about this serv's own calls.
+ *
+ * This is for callers that cannot see the svc_register() return, because a
+ * transport class sits in between. Such a caller reads the count before it
+ * starts and compares as it goes, so there is no state to reset between
+ * operations. The count never resets, and callers must not attach meaning
+ * to the value itself.
+ *
+ * Return: the number of unanswered calls since this serv was created.
+ */
+unsigned int svc_rpcb_failure_count(struct svc_serv *serv)
+{
+ return atomic_read(&serv->sv_rpcb_failures);
+}
+EXPORT_SYMBOL_GPL(svc_rpcb_failure_count);
+
/**
* svc_register - register an RPC service with the local portmapper
* @serv: svc_serv struct for the service to register
@@ -1218,10 +1248,11 @@ EXPORT_SYMBOL_GPL(svc_generic_rpcbind_set);
*
* Service is registered for any address in the passed-in protocol family
*/
-int svc_register(const struct svc_serv *serv, struct net *net,
+int svc_register(struct svc_serv *serv, struct net *net,
const int family, const unsigned short proto,
const unsigned short port)
{
+ bool noanswer = false;
unsigned int p, i;
int error = 0;
@@ -1233,10 +1264,16 @@ int svc_register(const struct svc_serv *serv, struct net *net,
struct svc_program *progp = &serv->sv_programs[p];
for (i = 0; i < progp->pg_nvers; i++) {
+ const struct svc_version *vers = progp->pg_vers[i];
int ret;
ret = progp->pg_rpcbind_set(net, progp, i,
family, proto, port);
+ if (ret == -EIO) {
+ noanswer = true;
+ if (vers && vers->vs_rpcb_optnl)
+ ret = 0;
+ }
if (ret < 0) {
printk(KERN_WARNING "svc: failed to register "
"%sv%u RPC service (errno %d).\n",
@@ -1248,6 +1285,9 @@ int svc_register(const struct svc_serv *serv, struct net *net,
}
}
+ if (noanswer)
+ atomic_inc(&serv->sv_rpcb_failures);
+
return error;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 028/670] NFSD: stop registering with rpcbind after a failure in listener_set
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (26 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 027/670] SUNRPC: report local rpcbind calls that get no answer Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 029/670] nfsd: prevent callback tasks running concurrently Greg Kroah-Hartman
` (643 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Olga Kornievskaia, Jeff Layton,
Chuck Lever, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <jlayton@kernel.org>
[ Upstream commit bf0f3a37e6ccb78ae80cc6eb2edde4f033c7574c ]
nfsd_nl_listener_set_doit() calls svc_xprt_create_from_sa() once for each
requested listener and passes flags of 0, so every listener registers with
rpcbind on its own. A rpcbind that accepts the connection and never replies
therefore costs one timeout for each entry. With the cap of 1024 entries
the request can hold nfsd_mutex for about 34 minutes, which is roughly 17
times the hung-task threshold.
One failure is enough to know that the next call will not fare better.
Read svc_rpcb_failure_count() before the create loop, and pass
SVC_SOCK_ANONYMOUS for the rest of the request once the count moves.
Fixes: 16a471177496 ("NFSD: add listener-{set,get} netlink command")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Link: https://syzkaller.appspot.com/bug?extid=c7eae0eb80858a2dba0f
Suggested-by: Olga Kornievskaia <okorniev@redhat.com>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260901-nfsd-nl-hang-v5-10-a540d86668b0@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfsctl.c | 42 ++++++++++++++++++++++++++++++++++++++----
1 file changed, 38 insertions(+), 4 deletions(-)
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index ecfdd8e5fd3d3..6ca903922fe9b 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -2110,7 +2110,10 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
const struct nlattr *bad_attr = NULL;
struct svc_xprt *xprt, *tmp;
const char *bad_xprt = NULL;
+ unsigned int rpcb_failures;
const struct nlattr *attr;
+ bool skipped_rpcb = false;
+ bool bad_rpcb = false;
struct svc_serv *serv;
LIST_HEAD(permsocks);
struct nfsd_net *nn;
@@ -2200,13 +2203,16 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
if (delete)
svc_xprt_destroy_all(serv, net);
+ rpcb_failures = svc_rpcb_failure_count(serv);
+
/* walk list of addrs again, open any that still don't exist */
nlmsg_for_each_attr_type(attr, NFSD_A_SERVER_SOCK_ADDR, info->nlhdr,
GENL_HDRLEN, rem) {
struct nlattr *tb[NFSD_A_SOCK_MAX + 1];
const char *xcl_name;
struct sockaddr *sa;
- int ret;
+ bool hit_rpcb;
+ int flags, ret;
/* validated up front in nfsd_nl_validate_listeners() */
if (nla_parse_nested(tb, NFSD_A_SOCK_MAX, attr,
@@ -2225,12 +2231,27 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
continue;
}
- ret = svc_xprt_create_from_sa(serv, xcl_name, net, sa, 0,
+ flags = skipped_rpcb ? SVC_SOCK_ANONYMOUS : 0;
+ ret = svc_xprt_create_from_sa(serv, xcl_name, net, sa, flags,
current_cred());
+
+ hit_rpcb = false;
+ if (!skipped_rpcb &&
+ svc_rpcb_failure_count(serv) != rpcb_failures) {
+ skipped_rpcb = true;
+ hit_rpcb = true;
+ if (ret < 0)
+ ret = svc_xprt_create_from_sa(serv, xcl_name,
+ net, sa,
+ SVC_SOCK_ANONYMOUS,
+ current_cred());
+ }
+
/* always save the latest error */
if (ret < 0) {
bad_attr = attr;
bad_xprt = xcl_name;
+ bad_rpcb = hit_rpcb;
err = ret;
}
}
@@ -2242,8 +2263,21 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
*/
if (err) {
NL_SET_BAD_ATTR(info->extack, bad_attr);
- NL_SET_ERR_MSG_FMT(info->extack, "cannot create %s listener",
- bad_xprt);
+ if (bad_rpcb)
+ NL_SET_ERR_MSG_FMT(info->extack,
+ "cannot create %s listener; rpcbind did not answer",
+ bad_xprt);
+ else if (skipped_rpcb)
+ NL_SET_ERR_MSG_FMT(info->extack,
+ "cannot create %s listener; rpcbind did not answer earlier, so some listeners are not registered",
+ bad_xprt);
+ else
+ NL_SET_ERR_MSG_FMT(info->extack,
+ "cannot create %s listener",
+ bad_xprt);
+ } else if (skipped_rpcb) {
+ NL_SET_ERR_MSG(info->extack,
+ "rpcbind did not answer, some listeners are not registered");
}
if (!serv->sv_nrthreads && list_empty(&nn->nfsd_serv->sv_permsocks))
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 029/670] nfsd: prevent callback tasks running concurrently
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (27 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 028/670] NFSD: stop registering with rpcbind after a failure in listener_set Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 030/670] nfsd: eliminate cl_ra_cblist and NFSD4_CLIENT_CB_RECALL_ANY Greg Kroah-Hartman
` (642 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeff Layton, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <jlayton@kernel.org>
[ Upstream commit 1054e8ffc5c492f341bdf1888b882f1d163dd3d8 ]
The nfsd4_callback workqueue jobs exist to queue backchannel RPCs to
rpciod. Because they run in different workqueue contexts, the rpc_task
can run concurrently with the workqueue job itself, should it become
requeued. This is problematic as there is no locking when accessing the
fields in the nfsd4_callback.
Add a new unsigned long to nfsd4_callback and declare a new
NFSD4_CALLBACK_RUNNING flag to be set in it. When attempting to run a
workqueue job, do a test_and_set_bit() on that flag first, and don't
queue the workqueue job if it returns true. Clear NFSD4_CALLBACK_RUNNING
in nfsd41_destroy_cb().
This also gives us a more reliable mechanism for handling queueing
failures in codepaths where we have to take references under spinlocks.
We can now do the test_and_set_bit on NFSD4_CALLBACK_RUNNING first, and
only take references to the objects if that returns false.
Most of the nfsd4_run_cb() callers are converted to use this new flag or
the nfsd4_try_run_cb() wrapper. The main exception is the callback
channel probe, which has its own synchronization.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Stable-dep-of: 9af39c0773ef ("NFSD: Send a meaningful CB_RECALL_ANY keep count")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfs4callback.c | 2 ++
fs/nfsd/nfs4layouts.c | 7 ++++---
fs/nfsd/nfs4proc.c | 2 +-
fs/nfsd/nfs4state.c | 14 ++++++++++----
fs/nfsd/state.h | 9 +++++++++
5 files changed, 26 insertions(+), 8 deletions(-)
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 798fcc9c40926..47cfd4bd4ecc4 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -1227,6 +1227,7 @@ static void nfsd41_destroy_cb(struct nfsd4_callback *cb)
trace_nfsd_cb_destroy(clp, cb);
nfsd41_cb_release_slot(cb);
+ clear_bit(NFSD4_CALLBACK_RUNNING, &cb->cb_flags);
if (cb->cb_ops && cb->cb_ops->release)
cb->cb_ops->release(cb);
nfsd41_cb_inflight_end(clp);
@@ -1575,6 +1576,7 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
cb->cb_msg.rpc_proc = &nfs4_cb_procedures[op];
cb->cb_msg.rpc_argp = cb;
cb->cb_msg.rpc_resp = cb;
+ cb->cb_flags = 0;
cb->cb_ops = ops;
INIT_WORK(&cb->cb_work, nfsd4_run_cb_work);
cb->cb_status = 0;
diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c
index a78e0bfdc9363..1f37044db59f3 100644
--- a/fs/nfsd/nfs4layouts.c
+++ b/fs/nfsd/nfs4layouts.c
@@ -348,9 +348,10 @@ nfsd4_recall_file_layout(struct nfs4_layout_stateid *ls)
atomic_inc(&ls->ls_stid.sc_file->fi_lo_recalls);
trace_nfsd_layout_recall(&ls->ls_stid.sc_stateid);
- refcount_inc(&ls->ls_stid.sc_count);
- nfsd4_run_cb(&ls->ls_recall);
-
+ if (!test_and_set_bit(NFSD4_CALLBACK_RUNNING, &ls->ls_recall.cb_flags)) {
+ refcount_inc(&ls->ls_stid.sc_count);
+ nfsd4_run_cb(&ls->ls_recall);
+ }
out_unlock:
spin_unlock(&ls->ls_lock);
}
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 53ded5de593a8..4825be4dc6467 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1769,7 +1769,7 @@ static void nfsd4_send_cb_offload(struct nfsd4_copy *copy)
NFSPROC4_CLNT_CB_OFFLOAD);
trace_nfsd_cb_offload(copy->cp_clp, &cbo->co_res.cb_stateid,
&cbo->co_fh, copy->cp_count, copy->nfserr);
- nfsd4_run_cb(&cbo->co_cb);
+ nfsd4_try_run_cb(&cbo->co_cb);
}
/**
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 723a1ae688366..2188c15d3ec6c 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3303,8 +3303,10 @@ static void nfs4_cb_getattr(struct nfs4_cb_fattr *ncf)
/* set to proper status when nfsd4_cb_getattr_done runs */
ncf->ncf_cb_status = NFS4ERR_IO;
- refcount_inc(&dp->dl_stid.sc_count);
- nfsd4_run_cb(&ncf->ncf_getattr);
+ if (!test_and_set_bit(NFSD4_CALLBACK_RUNNING, &ncf->ncf_getattr.cb_flags)) {
+ refcount_inc(&dp->dl_stid.sc_count);
+ nfsd4_run_cb(&ncf->ncf_getattr);
+ }
}
static struct nfs4_client *create_client(struct xdr_netobj name,
@@ -5477,6 +5479,10 @@ static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = {
static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
{
bool queued;
+
+ if (test_and_set_bit(NFSD4_CALLBACK_RUNNING, &dp->dl_recall.cb_flags))
+ return;
+
/*
* We're assuming the state code never drops its reference
* without first removing the lease. Since we're in this lease
@@ -7036,7 +7042,7 @@ deleg_reaper(struct nfsd_net *nn)
clp->cl_ra->ra_bmval[0] = BIT(RCA4_TYPE_MASK_RDATA_DLG) |
BIT(RCA4_TYPE_MASK_WDATA_DLG);
trace_nfsd_cb_recall_any(clp->cl_ra);
- nfsd4_run_cb(&clp->cl_ra->ra_cb);
+ nfsd4_try_run_cb(&clp->cl_ra->ra_cb);
}
}
@@ -7977,7 +7983,7 @@ nfsd4_lm_notify(struct file_lock *fl)
if (queue) {
trace_nfsd_cb_notify_lock(lo, nbl);
- nfsd4_run_cb(&nbl->nbl_cb);
+ nfsd4_try_run_cb(&nbl->nbl_cb);
}
}
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index f39a425639b07..e4c3e5907db15 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -67,6 +67,8 @@ typedef struct {
struct nfsd4_callback {
struct nfs4_client *cb_clp;
struct rpc_message cb_msg;
+#define NFSD4_CALLBACK_RUNNING (0)
+ unsigned long cb_flags;
const struct nfsd4_callback_ops *cb_ops;
struct work_struct cb_work;
int cb_seq_status;
@@ -748,6 +750,13 @@ extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *
extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
const struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op);
extern bool nfsd4_run_cb(struct nfsd4_callback *cb);
+
+static inline void nfsd4_try_run_cb(struct nfsd4_callback *cb)
+{
+ if (!test_and_set_bit(NFSD4_CALLBACK_RUNNING, &cb->cb_flags))
+ WARN_ON_ONCE(!nfsd4_run_cb(cb));
+}
+
extern void nfsd4_shutdown_callback(struct nfs4_client *);
extern void nfsd4_shutdown_copy(struct nfs4_client *clp);
extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name,
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 030/670] nfsd: eliminate cl_ra_cblist and NFSD4_CLIENT_CB_RECALL_ANY
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (28 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 029/670] nfsd: prevent callback tasks running concurrently Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 031/670] nfsd: defer setting NFSD4_CALLBACK_RUNNING in deleg_reaper Greg Kroah-Hartman
` (641 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeff Layton, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <jlayton@kernel.org>
[ Upstream commit 424dd3df1f991b14a70f044a68c8a595abbdf1ad ]
deleg_reaper() will walk the client_lru list and put any suitable
entries onto "cblist" using the cl_ra_cblist pointer. It then walks the
objects outside the spinlock and queues callbacks for them.
None of the operations that deleg_reaper() does outside the
nn->client_lock are blocking operations. Just queue their workqueue jobs
under the nn->client_lock instead.
Also, the NFSD4_CLIENT_CB_RECALL_ANY and NFSD4_CALLBACK_RUNNING flags
serve an identical purpose now. Drop the NFSD4_CLIENT_CB_RECALL_ANY flag
and just use the one in the callback.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Stable-dep-of: 9af39c0773ef ("NFSD: Send a meaningful CB_RECALL_ANY keep count")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfs4state.c | 16 +++-------------
fs/nfsd/state.h | 2 --
2 files changed, 3 insertions(+), 15 deletions(-)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 2188c15d3ec6c..b9d3e134dc1b4 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3246,7 +3246,6 @@ nfsd4_cb_recall_any_release(struct nfsd4_callback *cb)
{
struct nfs4_client *clp = cb->cb_clp;
- clear_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags);
drop_client(clp);
}
@@ -7005,7 +7004,6 @@ deleg_reaper(struct nfsd_net *nn)
{
struct list_head *pos, *next;
struct nfs4_client *clp;
- LIST_HEAD(cblist);
spin_lock(&nn->client_lock);
list_for_each_safe(pos, next, &nn->client_lru) {
@@ -7019,31 +7017,23 @@ deleg_reaper(struct nfsd_net *nn)
continue;
if (atomic_read(&clp->cl_delegs_in_recall))
continue;
- if (test_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags))
+ if (test_and_set_bit(NFSD4_CALLBACK_RUNNING, &clp->cl_ra->ra_cb.cb_flags))
continue;
if (ktime_get_boottime_seconds() - clp->cl_ra_time < 5)
continue;
if (clp->cl_cb_state != NFSD4_CB_UP)
continue;
- list_add(&clp->cl_ra_cblist, &cblist);
/* release in nfsd4_cb_recall_any_release */
kref_get(&clp->cl_nfsdfs.cl_ref);
- set_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags);
clp->cl_ra_time = ktime_get_boottime_seconds();
- }
- spin_unlock(&nn->client_lock);
-
- while (!list_empty(&cblist)) {
- clp = list_first_entry(&cblist, struct nfs4_client,
- cl_ra_cblist);
- list_del_init(&clp->cl_ra_cblist);
clp->cl_ra->ra_keep = 0;
clp->cl_ra->ra_bmval[0] = BIT(RCA4_TYPE_MASK_RDATA_DLG) |
BIT(RCA4_TYPE_MASK_WDATA_DLG);
trace_nfsd_cb_recall_any(clp->cl_ra);
- nfsd4_try_run_cb(&clp->cl_ra->ra_cb);
+ nfsd4_run_cb(&clp->cl_ra->ra_cb);
}
+ spin_unlock(&nn->client_lock);
}
static void
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index e4c3e5907db15..4e0e36b81b203 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -412,7 +412,6 @@ struct nfs4_client {
#define NFSD4_CLIENT_UPCALL_LOCK (5) /* upcall serialization */
#define NFSD4_CLIENT_CB_FLAG_MASK (1 << NFSD4_CLIENT_CB_UPDATE | \
1 << NFSD4_CLIENT_CB_KILL)
-#define NFSD4_CLIENT_CB_RECALL_ANY (6)
unsigned long cl_flags;
struct workqueue_struct *cl_callback_wq;
@@ -461,7 +460,6 @@ struct nfs4_client {
struct nfsd4_cb_recall_any *cl_ra;
time64_t cl_ra_time;
- struct list_head cl_ra_cblist;
};
/* struct nfs4_client_reset
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 031/670] nfsd: defer setting NFSD4_CALLBACK_RUNNING in deleg_reaper
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (29 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 030/670] nfsd: eliminate cl_ra_cblist and NFSD4_CLIENT_CB_RECALL_ANY Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 032/670] NFSD: Count the delegations held by each client Greg Kroah-Hartman
` (640 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeff Layton, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <jlayton@kernel.org>
[ Upstream commit 108969960dc54de673869814c5f37c22f6cf404a ]
deleg_reaper() sets NFSD4_CALLBACK_RUNNING before checking the
5-second rate limit and cl_cb_state gates. When either gate fires
the loop continues without queuing callback work, so the bit's only
clear site in nfsd41_destroy_cb() is never reached and RECALL_ANY
dispatch is permanently disabled for the affected client.
Move the test_and_set_bit() below both non-queueing gates so the
bit is taken only when nfsd4_run_cb() will be called.
Fixes: 424dd3df1f99 ("nfsd: eliminate cl_ra_cblist and NFSD4_CLIENT_CB_RECALL_ANY")
Cc: stable@vger.kernel.org
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260526-cb_recall_any_callback_running_stuck-v1-1-310011a028f3@kernel.org
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Stable-dep-of: 9af39c0773ef ("NFSD: Send a meaningful CB_RECALL_ANY keep count")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfs4state.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b9d3e134dc1b4..d2878bf1e7181 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -7017,12 +7017,12 @@ deleg_reaper(struct nfsd_net *nn)
continue;
if (atomic_read(&clp->cl_delegs_in_recall))
continue;
- if (test_and_set_bit(NFSD4_CALLBACK_RUNNING, &clp->cl_ra->ra_cb.cb_flags))
- continue;
if (ktime_get_boottime_seconds() - clp->cl_ra_time < 5)
continue;
if (clp->cl_cb_state != NFSD4_CB_UP)
continue;
+ if (test_and_set_bit(NFSD4_CALLBACK_RUNNING, &clp->cl_ra->ra_cb.cb_flags))
+ continue;
/* release in nfsd4_cb_recall_any_release */
kref_get(&clp->cl_nfsdfs.cl_ref);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 032/670] NFSD: Count the delegations held by each client
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (30 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 031/670] nfsd: defer setting NFSD4_CALLBACK_RUNNING in deleg_reaper Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 033/670] NFSD: Send a meaningful CB_RECALL_ANY keep count Greg Kroah-Hartman
` (639 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeff Layton, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <cel@kernel.org>
[ Upstream commit 5d5a6e996e7c36bc2f7b035743c16f2bf03a227d ]
struct nfs4_client records the delegations it holds on cl_delegations
but keeps no count of them. deleg_reaper() walks nn->client_lru under
nn->client_lock, but cl_delegations is serialized by nn->deleg_lock,
which nests outside nn->client_lock. A caller there cannot take
nn->deleg_lock to count the list. The cost tells against the walk as
well: an O(n) count per client, on a pass that already visits every
client.
Add cl_deleg_count, maintained at the two sites that mutate
cl_delegations. Both hold nn->deleg_lock, so the counter is already
serialized against itself and needs no atomic of its own. The decrement
sits below the delegation_hashed() test, next to the list_del_init it
pairs with, so it runs only when the delegation really leaves the list.
A reader that holds only nn->client_lock is not synchronized against
either update site, so it can see a count that does not match the
list. Such a reader marks the access with data_race() and may not
depend on the value for correctness.
No functional change.
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260817-recall-any-keep-count-v5-2-3b2cffce701e@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Stable-dep-of: 9af39c0773ef ("NFSD: Send a meaningful CB_RECALL_ANY keep count")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfs4state.c | 2 ++
fs/nfsd/state.h | 2 ++
2 files changed, 4 insertions(+)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index d2878bf1e7181..43755bce08f95 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1420,6 +1420,7 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
dp->dl_stid.sc_type = SC_TYPE_DELEG;
list_add(&dp->dl_perfile, &fp->fi_delegations);
list_add(&dp->dl_perclnt, &clp->cl_delegations);
+ clp->cl_deleg_count++;
return 0;
}
@@ -1451,6 +1452,7 @@ unhash_delegation_locked(struct nfs4_delegation *dp, unsigned short statusmask)
++dp->dl_time;
spin_lock(&fp->fi_lock);
list_del_init(&dp->dl_perclnt);
+ dp->dl_stid.sc_client->cl_deleg_count--;
list_del_init(&dp->dl_recall_lru);
list_del_init(&dp->dl_perfile);
spin_unlock(&fp->fi_lock);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 4e0e36b81b203..1909d744d4ac5 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -457,6 +457,8 @@ struct nfs4_client {
unsigned int cl_state;
atomic_t cl_delegs_in_recall;
+ /* Length of cl_delegations, updated under nn->deleg_lock */
+ unsigned int cl_deleg_count;
struct nfsd4_cb_recall_any *cl_ra;
time64_t cl_ra_time;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 033/670] NFSD: Send a meaningful CB_RECALL_ANY keep count
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (31 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 032/670] NFSD: Count the delegations held by each client Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 034/670] nfsd: clear CALLBACK_RUNNING on failed delegation recall queue Greg Kroah-Hartman
` (638 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeff Layton, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <cel@kernel.org>
[ Upstream commit 9af39c0773ef956039e1ebe9c235532fe6ee1e50 ]
deleg_reaper() sets craa_objects_to_keep to zero on every
CB_RECALL_ANY. RFC 8881 Section 20.6.3 defines that field as the
number of objects the client may keep, leaving the client to choose
which of the excess to return, because the server cannot read lack
of recent use as lack of usefulness. Zero asks for every delegation
the client holds, including the ones backing files an application
still has open.
There is also no reason NFSD has to reclaim the entire delegation
working set on the first sign of memory pressure.
Derive the keep count from cl_deleg_count so that each callback
asks for one delegation. Both the shrinker and the laundromat re-arm
while their condition lasts, so a client with more to give is asked
again on the next pass.
The Linux client ignores craa_objects_to_keep and returns unused
delegations selected from the type mask alone, so the count changes
nothing for it.
Fixes: 44df6f439a17 ("NFSD: add delegation reaper to react to low memory condition")
Cc: stable@vger.kernel.org
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260817-recall-any-keep-count-v5-4-3b2cffce701e@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfs4state.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 43755bce08f95..c79b7ad28f3c4 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -7006,6 +7006,7 @@ deleg_reaper(struct nfsd_net *nn)
{
struct list_head *pos, *next;
struct nfs4_client *clp;
+ unsigned int count;
spin_lock(&nn->client_lock);
list_for_each_safe(pos, next, &nn->client_lru) {
@@ -7015,21 +7016,33 @@ deleg_reaper(struct nfsd_net *nn)
continue;
if (clp->cl_state != NFSD4_ACTIVE)
continue;
- if (list_empty(&clp->cl_delegations))
- continue;
if (atomic_read(&clp->cl_delegs_in_recall))
continue;
if (ktime_get_boottime_seconds() - clp->cl_ra_time < 5)
continue;
if (clp->cl_cb_state != NFSD4_CB_UP)
continue;
+ /*
+ * This read races with hash_delegation_locked() and
+ * unhash_delegation_locked() on other CPUs. A stale
+ * count only skews the keep value; the next
+ * laundromat pass sees a more current one.
+ */
+ count = data_race(READ_ONCE(clp->cl_deleg_count));
+ if (!count)
+ continue;
if (test_and_set_bit(NFSD4_CALLBACK_RUNNING, &clp->cl_ra->ra_cb.cb_flags))
continue;
/* release in nfsd4_cb_recall_any_release */
kref_get(&clp->cl_nfsdfs.cl_ref);
clp->cl_ra_time = ktime_get_boottime_seconds();
- clp->cl_ra->ra_keep = 0;
+ /*
+ * Ask for a single delegation. Recalling one before it
+ * is needed costs the client an OPEN when it next
+ * touches the file.
+ */
+ clp->cl_ra->ra_keep = count - 1;
clp->cl_ra->ra_bmval[0] = BIT(RCA4_TYPE_MASK_RDATA_DLG) |
BIT(RCA4_TYPE_MASK_WDATA_DLG);
trace_nfsd_cb_recall_any(clp->cl_ra);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 034/670] nfsd: clear CALLBACK_RUNNING on failed delegation recall queue
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (32 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 033/670] NFSD: Send a meaningful CB_RECALL_ANY keep count Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 035/670] NFSD: Move the cld upcall message out of the callers stack frame Greg Kroah-Hartman
` (637 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeff Layton, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <jlayton@kernel.org>
[ Upstream commit b036727d334b1b7cd4c1f1fba3b59ba93a6bbe96 ]
nfsd_break_one_deleg() sets NFSD4_CALLBACK_RUNNING via test_and_set_bit
at entry to serialize recall work, then calls nfsd4_run_cb() to queue
the recall. When the queue attempt fails the refcount bump is undone,
but the RUNNING bit is left set. The only site that clears the bit is
nfsd41_destroy_cb() (fs/nfsd/nfs4callback.c), which runs from the
workqueue and is therefore unreachable when nothing was queued.
The bit becomes a permanent latch on dp->dl_recall.cb_flags: every
subsequent break_lease() on the same delegation hits the early-return
guard in nfsd_break_one_deleg() and silently skips the recall, so the
delegation is never broken and the conflicting open or lock stalls.
Fix by clearing NFSD4_CALLBACK_RUNNING on the !queued branch alongside
the refcount_dec.
Fixes: 1054e8ffc5c4 ("nfsd: prevent callback tasks running concurrently")
Cc: stable@vger.kernel.org
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260526-cb_recall_any_callback_running_stuck-v1-2-310011a028f3@kernel.org
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfs4state.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index c79b7ad28f3c4..061ce98eb414f 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5494,8 +5494,10 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
refcount_inc(&dp->dl_stid.sc_count);
queued = nfsd4_run_cb(&dp->dl_recall);
WARN_ON_ONCE(!queued);
- if (!queued)
+ if (!queued) {
refcount_dec(&dp->dl_stid.sc_count);
+ clear_bit(NFSD4_CALLBACK_RUNNING, &dp->dl_recall.cb_flags);
+ }
}
/* Called from break_lease() with flc_lock held. */
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 035/670] NFSD: Move the cld upcall message out of the callers stack frame
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (33 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 034/670] nfsd: clear CALLBACK_RUNNING on failed delegation recall queue Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 036/670] NFSD: Complete a cld upcall when the daemon closes the pipe Greg Kroah-Hartman
` (636 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+d5c77cabf7a3492aa650,
Chuck Lever, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <cel@kernel.org>
[ Upstream commit c559b05610557fa3c6c30259261f6dae523b3f23 ]
__cld_pipe_upcall() builds its struct rpc_pipe_msg on the stack and
hands it to rpc_queue_upcall(), which links it into a list the pipe
owns until the message is released. Only the completion rules keep that
frame alive for as long as the pipe refers to it, and the peer that
drives those rules is an untrusted userspace daemon. The gss and idmap
upcalls do not take that on: each keeps the message in the object it
already allocates.
Do the same here and put the message in struct cld_upcall, beside the
reply buffer it carries. cld_pipe_destroy_msg() then reaches the upcall
from the message directly rather than through msg->data.
Reported-by: syzbot+d5c77cabf7a3492aa650@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=d5c77cabf7a3492aa650
Link: https://patch.msgid.link/20260901-alemi-v2-2-e163f94a3a6e@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Stable-dep-of: 2a83fcb50f3c ("NFSD: Complete a cld upcall when the daemon closes the pipe")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfs4recover.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 104dafbe881bc..b493bb059a8b0 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -730,6 +730,7 @@ struct cld_upcall {
struct completion cu_done;
/* daemon has read the whole upcall; protected by cn_lock */
bool cu_inflight;
+ struct rpc_pipe_msg cu_pipe_msg;
union {
struct cld_msg_hdr cu_hdr;
struct cld_msg cu_msg;
@@ -741,22 +742,22 @@ static int
__cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg, struct nfsd_net *nn)
{
int ret;
- struct rpc_pipe_msg msg;
struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, cu_u);
+ struct rpc_pipe_msg *msg = &cup->cu_pipe_msg;
- memset(&msg, 0, sizeof(msg));
- msg.data = cmsg;
- msg.len = nn->client_tracking_ops->msglen;
+ memset(msg, 0, sizeof(*msg));
+ msg->data = cmsg;
+ msg->len = nn->client_tracking_ops->msglen;
- ret = rpc_queue_upcall(pipe, &msg);
+ ret = rpc_queue_upcall(pipe, msg);
if (ret < 0) {
goto out;
}
wait_for_completion(&cup->cu_done);
- if (msg.errno < 0)
- ret = msg.errno;
+ if (msg->errno < 0)
+ ret = msg->errno;
out:
return ret;
}
@@ -929,9 +930,8 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
static void
cld_pipe_destroy_msg(struct rpc_pipe_msg *msg)
{
- struct cld_msg *cmsg = msg->data;
- struct cld_upcall *cup = container_of(cmsg, struct cld_upcall,
- cu_u.cu_msg);
+ struct cld_upcall *cup = container_of(msg, struct cld_upcall,
+ cu_pipe_msg);
struct cld_net *cn = cup->cu_net;
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 036/670] NFSD: Complete a cld upcall when the daemon closes the pipe
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (34 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 035/670] NFSD: Move the cld upcall message out of the callers stack frame Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 037/670] NFSD: Complete a cld upcall when copying its reply fails Greg Kroah-Hartman
` (635 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+edbebd898142ee5e24ce,
Chuck Lever, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <cel@kernel.org>
[ Upstream commit 2a83fcb50f3c25c493cc4389619340fefe9d6ac4 ]
Once nfsdcld has read a whole upcall, rpc_pipe_read() unlinks the
message from every pipe list, so the purges in rpc_pipe_release()
and rpc_close_pipes() no longer reach it. cld_upcall_ops supplies no
.release_pipe callback, and cld_pipe_destroy_msg() returns without
completing the upcall because a downcall is expected to follow. A
daemon that exits between the read and the write therefore strands
its waiter: the nfsd thread sleeps in TASK_UNINTERRUPTIBLE in
__cld_pipe_upcall() and never returns, hung task warnings follow,
and the server cannot be shut down.
Add a .release_pipe that completes every upcall the daemon has
consumed. cu_inflight distinguishes those from upcalls still queued
on the pipe, which the framework purges before it calls this
callback; cld_pipe_downcall() removes an upcall it accepts from
cn_list under the same lock. Neither can be completed twice.
Fail the stranded upcall with -EPIPE rather than the -EAGAIN that
makes cld_pipe_upcall() retry. The daemon consumed the request, so
whether it acted on it before exiting is unknown.
Fixes: f3f8014862d8 ("nfsd: add the infrastructure to handle the cld upcall")
Reported-by: syzbot+edbebd898142ee5e24ce@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/linux-nfs/6a99f6f0.2e567484.299ffc.000c.GAE@google.com/
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260901-alemi-v2-7-e163f94a3a6e@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfs4recover.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index b493bb059a8b0..9c7f6d90a1b99 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -948,10 +948,34 @@ cld_pipe_destroy_msg(struct rpc_pipe_msg *msg)
complete(&cup->cu_done);
}
+/*
+ * An upcall the daemon has consumed is off every pipe list, so the
+ * purge in rpc_pipe_release() and rpc_close_pipes() cannot reach it.
+ * Release its waiter here instead; no downcall can arrive now.
+ */
+static void
+cld_release_pipe(struct inode *inode)
+{
+ struct nfsd_net *nn = net_generic(inode->i_sb->s_fs_info, nfsd_net_id);
+ struct cld_net *cn = nn->cld_net;
+ struct cld_upcall *cup;
+
+ spin_lock(&cn->cn_lock);
+ list_for_each_entry(cup, &cn->cn_list, cu_list) {
+ if (!cup->cu_inflight)
+ continue;
+ cup->cu_inflight = false;
+ cup->cu_pipe_msg.errno = -EPIPE;
+ complete(&cup->cu_done);
+ }
+ spin_unlock(&cn->cn_lock);
+}
+
static const struct rpc_pipe_ops cld_upcall_ops = {
.upcall = rpc_pipe_generic_upcall,
.downcall = cld_pipe_downcall,
.destroy_msg = cld_pipe_destroy_msg,
+ .release_pipe = cld_release_pipe,
};
static int
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 037/670] NFSD: Complete a cld upcall when copying its reply fails
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (35 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 036/670] NFSD: Complete a cld upcall when the daemon closes the pipe Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 038/670] NFSD: Map flex file layout IDs through the requests user namespace Greg Kroah-Hartman
` (634 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Chuck Lever, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <cel@kernel.org>
[ Upstream commit 8cef2b0a01d28647facc57501a3df7ccd8d13ccd ]
cld_pipe_downcall() removes the matching upcall from cn_list before
copying the daemon's reply. When that copy_from_user() faults, the
downcall returns -EFAULT without completing the upcall, and a
retried write cannot reach it because its xid is no longer on the
list. __cld_pipe_upcall() waits on cu_done uninterruptibly, so the
nfsd thread that sent the upcall is stuck, and nfsd shutdown hangs
behind it. The pipe is mode 0600, so only a broken or hostile
nfsdcld can trigger the fault.
Record the fault in the upcall's pipe message and complete it, so
the waiter returns the error to its client tracking operation.
Fixes: f3f8014862d8 ("nfsd: add the infrastructure to handle the cld upcall")
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260901-alemi-v2-3-e163f94a3a6e@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfs4recover.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 9c7f6d90a1b99..ef0388d92aca5 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -920,8 +920,11 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
if (status == -EINPROGRESS)
return __cld_pipe_inprogress_downcall(cmsg, nn);
- if (copy_from_user(&cup->cu_u.cu_msg_v2, src, mlen) != 0)
+ if (copy_from_user(&cup->cu_u.cu_msg_v2, src, mlen) != 0) {
+ cup->cu_pipe_msg.errno = -EFAULT;
+ complete(&cup->cu_done);
return -EFAULT;
+ }
complete(&cup->cu_done);
return mlen;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 038/670] NFSD: Map flex file layout IDs through the requests user namespace
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (36 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 037/670] NFSD: Complete a cld upcall when copying its reply fails Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 039/670] afs: Fix afs to abort the rxrpc call on send error Greg Kroah-Hartman
` (633 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, sashiko-bot, Jeff Layton,
Chuck Lever, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <cel@kernel.org>
[ Upstream commit f913d5d2130a584d1a027ffe3dfd88b6be2e0540 ]
nfsd4_ff_proc_layoutget() and nfsd4_ff_encode_layoutget() translate
the file's owner and group with init_user_ns, but every other identity
nfsd places on the wire goes through nfsd_user_namespace(). When the
transport carries a credential from a non-initial user namespace, the
flex file layout reports host-global IDs. The client copies those IDs
into the AUTH_SYS credential it presents to the data server, and
svcauth_unix_accept() resolves that credential in the transport's
namespace, so data server I/O runs under an identity unrelated to the
file's owner.
Switching to the request's namespace introduces a second hazard.
from_kuid() returns (uid_t)-1 when the target namespace has no
mapping for the owner, and the IOMODE_READ arm adds one to that
result to derive an identity for which the data server denies
writes. The addition would wrap to zero, handing the client uid 0
instead of an identity distinct from the owner.
Translate both IDs in nfsd4_ff_proc_layoutget(), which has the
svc_rqst, and carry the wire values in struct pnfs_ff_layout.
from_kuid_munged() substitutes overflowuid for an unmapped owner and
thus never returns (uid_t)-1, so the increment cannot wrap to zero.
Fixes: 9b9960a0ca47 ("nfsd: Add a super simple flex file server")
Cc: stable@vger.kernel.org
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260720141442.783935-1-cel@kernel.org?part=3
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260720163724.810227-1-cel@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
[ sashal: extended the proc_layoutget callback interface to pass rqstp from its caller to all implementations ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/blocklayout.c | 4 ++--
fs/nfsd/flexfilelayout.c | 24 ++++++++++++++----------
fs/nfsd/flexfilelayoutxdr.c | 4 ++--
fs/nfsd/flexfilelayoutxdr.h | 5 +++--
fs/nfsd/nfs4proc.c | 2 +-
fs/nfsd/pnfs.h | 4 ++--
6 files changed, 24 insertions(+), 19 deletions(-)
diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c
index bbd87cd162822..de789cefd30dc 100644
--- a/fs/nfsd/blocklayout.c
+++ b/fs/nfsd/blocklayout.c
@@ -18,8 +18,8 @@
static __be32
-nfsd4_block_proc_layoutget(struct inode *inode, const struct svc_fh *fhp,
- struct nfsd4_layoutget *args)
+nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
+ const struct svc_fh *fhp, struct nfsd4_layoutget *args)
{
struct nfsd4_layout_seg *seg = &args->lg_seg;
struct super_block *sb = inode->i_sb;
diff --git a/fs/nfsd/flexfilelayout.c b/fs/nfsd/flexfilelayout.c
index 3c4419da5e24c..64b85b9fd9f41 100644
--- a/fs/nfsd/flexfilelayout.c
+++ b/fs/nfsd/flexfilelayout.c
@@ -14,19 +14,20 @@
#include <linux/sunrpc/addr.h>
#include "flexfilelayoutxdr.h"
+#include "auth.h"
#include "pnfs.h"
#include "vfs.h"
#define NFSDDBG_FACILITY NFSDDBG_PNFS
static __be32
-nfsd4_ff_proc_layoutget(struct inode *inode, const struct svc_fh *fhp,
- struct nfsd4_layoutget *args)
+nfsd4_ff_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
+ const struct svc_fh *fhp, struct nfsd4_layoutget *args)
{
+ struct user_namespace *userns = nfsd_user_namespace(rqstp);
struct nfsd4_layout_seg *seg = &args->lg_seg;
u32 device_generation = 0;
int error;
- uid_t u;
struct pnfs_ff_layout *fl;
@@ -49,13 +50,16 @@ nfsd4_ff_proc_layoutget(struct inode *inode, const struct svc_fh *fhp,
fl->flags = FF_FLAGS_NO_LAYOUTCOMMIT | FF_FLAGS_NO_IO_THRU_MDS |
FF_FLAGS_NO_READ_IO;
- /* Do not allow a IOMODE_READ segment to have write pemissions */
- if (seg->iomode == IOMODE_READ) {
- u = from_kuid(&init_user_ns, inode->i_uid) + 1;
- fl->uid = make_kuid(&init_user_ns, u);
- } else
- fl->uid = inode->i_uid;
- fl->gid = inode->i_gid;
+ fl->uid = from_kuid_munged(userns, inode->i_uid);
+ fl->gid = from_kgid_munged(userns, inode->i_gid);
+
+ /*
+ * Do not allow an IOMODE_READ segment to have write permissions.
+ * The group is left intact so group-readable files stay readable;
+ * nfsd_setuser() squashes an unmapped uid to the export's anon ID.
+ */
+ if (seg->iomode == IOMODE_READ)
+ fl->uid++;
error = nfsd4_set_deviceid(&fl->deviceid, fhp, device_generation);
if (error)
diff --git a/fs/nfsd/flexfilelayoutxdr.c b/fs/nfsd/flexfilelayoutxdr.c
index 374e52d3064a6..b80352f41c0d0 100644
--- a/fs/nfsd/flexfilelayoutxdr.c
+++ b/fs/nfsd/flexfilelayoutxdr.c
@@ -32,8 +32,8 @@ nfsd4_ff_encode_layoutget(struct xdr_stream *xdr,
fh_len = 4 + xdr_align_size(fl->fh.size);
- uid.len = sprintf(uid.buf, "%u", from_kuid(&init_user_ns, fl->uid));
- gid.len = sprintf(gid.buf, "%u", from_kgid(&init_user_ns, fl->gid));
+ uid.len = sprintf(uid.buf, "%u", fl->uid);
+ gid.len = sprintf(gid.buf, "%u", fl->gid);
/* data server entry: deviceid + efficiency + stateid + fh list +
* user + group + flags + stats_collect_hint
diff --git a/fs/nfsd/flexfilelayoutxdr.h b/fs/nfsd/flexfilelayoutxdr.h
index 6d5a1066a903c..3e1876d49db23 100644
--- a/fs/nfsd/flexfilelayoutxdr.h
+++ b/fs/nfsd/flexfilelayoutxdr.h
@@ -35,8 +35,9 @@ struct pnfs_ff_device_addr {
struct pnfs_ff_layout {
u32 flags;
u32 stats_collect_hint;
- kuid_t uid;
- kgid_t gid;
+ /* Values to encode; nfsd4_ff_proc_layoutget() has mapped these */
+ u32 uid;
+ u32 gid;
struct nfsd4_deviceid deviceid;
stateid_t stateid;
struct nfs_fh fh;
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 4825be4dc6467..3d03ff6313d76 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -2359,7 +2359,7 @@ nfsd4_layoutget(struct svc_rqst *rqstp,
if (atomic_read(&ls->ls_stid.sc_file->fi_lo_recalls))
goto out_put_stid;
- nfserr = ops->proc_layoutget(d_inode(current_fh->fh_dentry),
+ nfserr = ops->proc_layoutget(rqstp, d_inode(current_fh->fh_dentry),
current_fh, lgp);
if (nfserr)
goto out_put_stid;
diff --git a/fs/nfsd/pnfs.h b/fs/nfsd/pnfs.h
index dfd411d1f363f..db9af780438b5 100644
--- a/fs/nfsd/pnfs.h
+++ b/fs/nfsd/pnfs.h
@@ -29,8 +29,8 @@ struct nfsd4_layout_ops {
__be32 (*encode_getdeviceinfo)(struct xdr_stream *xdr,
const struct nfsd4_getdeviceinfo *gdevp);
- __be32 (*proc_layoutget)(struct inode *, const struct svc_fh *fhp,
- struct nfsd4_layoutget *lgp);
+ __be32 (*proc_layoutget)(struct svc_rqst *rqstp, struct inode *inode,
+ const struct svc_fh *fhp, struct nfsd4_layoutget *lgp);
__be32 (*encode_layoutget)(struct xdr_stream *xdr,
const struct nfsd4_layoutget *lgp);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 039/670] afs: Fix afs to abort the rxrpc call on send error
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (37 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 038/670] NFSD: Map flex file layout IDs through the requests user namespace Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 040/670] KVM: nSVM: Reject KVM_SET_NESTED_STATE if L1 has EFER.LMA=1 && EFER.LME=0 Greg Kroah-Hartman
` (632 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Marc Dionne,
Eric Dumazet, David S. Miller, Jakub Kicinski, Paolo Abeni,
Simon Horman, linux-afs, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit 3e6af08a571fe2943a006acf3e890f36322602bc ]
Fix afs_send_empty_reply() and afs_send_simple_reply() to always try to
abort the rxrpc call rather than just aborting on -ENOMEM and otherwise
abandoning it. If the call is already complete due to network failure or a
received abort, this will do nothing.
Also make afs_make_call() always abort on send error; again, it does
nothing if the rxrpc call is already dead.
Fixes: 08e0e7c82eea ("[AF_RXRPC]: Make the in-kernel AFS filesystem use AF_RXRPC.")
Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260824091645.415423-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20261006133011.531806-6-dhowells@redhat.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
[ sashal: Retained explicit length arguments in rxrpc_kernel_send_data() calls to match the older API. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/afs/rxrpc.c | 49 +++++++++++++-----------------------
include/trace/events/rxrpc.h | 2 +-
2 files changed, 18 insertions(+), 33 deletions(-)
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 55449c8791426..934667e547dc2 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -442,10 +442,8 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
return;
error_do_abort:
- if (ret != -ECONNABORTED)
- rxrpc_kernel_abort_call(call->net->socket, rxcall,
- RX_USER_ABORT, ret,
- afs_abort_send_data_error);
+ rxrpc_kernel_abort_call(call->net->socket, rxcall,
+ RX_USER_ABORT, ret, afs_abort_send_data_error);
if (call->async) {
afs_see_call(call, afs_call_trace_async_abort);
return;
@@ -853,6 +851,7 @@ void afs_send_empty_reply(struct afs_call *call)
{
struct afs_net *net = call->net;
struct msghdr msg;
+ int ret;
_enter("");
@@ -865,21 +864,13 @@ void afs_send_empty_reply(struct afs_call *call)
msg.msg_controllen = 0;
msg.msg_flags = 0;
- switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0,
- afs_notify_end_reply_tx)) {
- case 0:
- _leave(" [replied]");
- return;
-
- case -ENOMEM:
- _debug("oom");
+ ret = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0,
+ afs_notify_end_reply_tx);
+ if (ret < 0) {
rxrpc_kernel_abort_call(net->socket, call->rxcall,
- RXGEN_SS_MARSHAL, -ENOMEM,
- afs_abort_oom);
- fallthrough;
- default:
- _leave(" [error]");
- return;
+ RXGEN_SS_MARSHAL, ret,
+ afs_abort_send_error);
+ afs_set_call_complete(call, ret, RXGEN_SS_MARSHAL);
}
}
@@ -891,7 +882,7 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
struct afs_net *net = call->net;
struct msghdr msg;
struct kvec iov[1];
- int n;
+ int ret;
_enter("");
@@ -906,21 +897,15 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
msg.msg_controllen = 0;
msg.msg_flags = 0;
- n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len,
- afs_notify_end_reply_tx);
- if (n >= 0) {
- /* Success */
- _leave(" [replied]");
- return;
- }
-
- if (n == -ENOMEM) {
- _debug("oom");
+ ret = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len,
+ afs_notify_end_reply_tx);
+ if (ret < 0) {
rxrpc_kernel_abort_call(net->socket, call->rxcall,
- RXGEN_SS_MARSHAL, -ENOMEM,
- afs_abort_oom);
+ RXGEN_SS_MARSHAL, ret,
+ afs_abort_send_error);
+ afs_set_call_complete(call, ret, RXGEN_SS_MARSHAL);
+ _leave(" [error]");
}
- _leave(" [error]");
}
/*
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 8c4d791507f18..5e29744e45037 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -20,10 +20,10 @@
/* AFS errors */ \
EM(afs_abort_general_error, "afs-error") \
EM(afs_abort_interrupted, "afs-intr") \
- EM(afs_abort_oom, "afs-oom") \
EM(afs_abort_op_not_supported, "afs-op-notsupp") \
EM(afs_abort_probeuuid_negative, "afs-probeuuid-neg") \
EM(afs_abort_send_data_error, "afs-send-data") \
+ EM(afs_abort_send_error, "afs-send-error") \
EM(afs_abort_unmarshal_error, "afs-unmarshal") \
/* rxperf errors */ \
EM(rxperf_abort_general_error, "rxperf-error") \
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 040/670] KVM: nSVM: Reject KVM_SET_NESTED_STATE if L1 has EFER.LMA=1 && EFER.LME=0
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (38 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 039/670] afs: Fix afs to abort the rxrpc call on send error Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 041/670] KVM: Harden and prepare for modifying existing guest_memfd memslots Greg Kroah-Hartman
` (631 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yosry Ahmed, Stefan Teodorescu,
Sean Christopherson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <seanjc@google.com>
[ Upstream commit 5dc500a354cc8e109df678076ae3488094649468 ]
Reject KVM_SET_NESTED_STATE if the incoming L1 host state has what is
effectively an impossible EFER combination of LMA=1 but LME=0, i.e. if the
state says long mode is active but not enabled. Unlike VMX, SVM doesn't
have an explicit consistent check for the illegal combination; presumably
hardware simply ignores EFER.LMA if EFER.LME=0.
Unfortunately, KVM doesn't ignore EFER.LMA in this case and consumes the
illegal state when constructing the shadow MMU for L2. E.g. if userspace
also clears CR4.PAE, then kvm_calc_cpu_role() will compute a role with 4 or
5 levels of paging, but shadow_mmu_init_context() will wire up the MMU to
use the paging32 template, which maxes out its levels at 2.
Note, the "real badness" is effectively the same as what happened with the
nVMX bug fixed by commit 112e66017bff ("KVM: nVMX: add missing consistency
checks for CR0 and CR4"). Unfortunately, the sanity check added by commit
72e2fb24a0b0 ("KVM: x86/mmu: Bug the VM if a vCPU ends up in long mode
without PAE enabled") doesn't work for this case, since L2 state is active
at the time of the page fault, but it's L1 that has the bad state.
Fixes: cc440cdad5b7 ("KVM: nSVM: implement KVM_GET_NESTED_STATE and KVM_SET_NESTED_STATE")
Cc: stable@vger.kernel.org
Cc: Yosry Ahmed <yosry@kernel.org>
Reported-by: Stefan Teodorescu <fane@google.com>
Link: https://patch.msgid.link/20260902232028.2767071-2-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
[ sashal: adjusted context for __nested_vmcb_check_save() without the third argument ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/svm/nested.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index e2e9ab0858858..3c9c20d7855fe 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -1763,6 +1763,7 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
if (!(save->cr0 & X86_CR0_PG) ||
!(save->cr0 & X86_CR0_PE) ||
(save->rflags & X86_EFLAGS_VM) ||
+ ((save->efer & EFER_LMA) && !(save->efer & EFER_LME)) ||
!__nested_vmcb_check_save(vcpu, &save_cached))
goto out_free;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 041/670] KVM: Harden and prepare for modifying existing guest_memfd memslots
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (39 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 040/670] KVM: nSVM: Reject KVM_SET_NESTED_STATE if L1 has EFER.LMA=1 && EFER.LME=0 Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 042/670] KVM: Only bind memslot to guest_memfd instance for CREATE operations Greg Kroah-Hartman
` (630 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Sean Christopherson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <seanjc@google.com>
[ Upstream commit af62fe2494da84eb01752282c8228c9bb3fe9f67 ]
Unbind guest_memfd memslots if KVM commits a MOVE or FLAGS_ONLY memslot
change to harden against use-after-free, and to prepare for eventually
supporting dirty logging on guest_memfd memslots, at which point
FLAGS_ONLY changes will be expected/supported.
Add two separate WARNs, once to yell if a guest_memfd memslot is moved
(which KVM is never expected to allow/support), and again if the unbind()
is triggered, to help detect uAPI goofs prior to deliberately allowing
FLAGS_ONLY changes.
Link: https://patch.msgid.link/20251202020334.1171351-3-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
Stable-dep-of: 513333a55460 ("KVM: Only bind memslot to guest_memfd instance for CREATE operations")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
virt/kvm/kvm_main.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 7debedc1ddaae..0d017f75c5a11 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1725,6 +1725,12 @@ static void kvm_commit_memory_region(struct kvm *kvm,
kvm_free_memslot(kvm, old);
break;
case KVM_MR_MOVE:
+ /*
+ * Moving a guest_memfd memslot isn't supported, and will never
+ * be supported.
+ */
+ WARN_ON_ONCE(old->flags & KVM_MEM_GUEST_MEMFD);
+ fallthrough;
case KVM_MR_FLAGS_ONLY:
/*
* Free the dirty bitmap as needed; the below check encompasses
@@ -1733,6 +1739,15 @@ static void kvm_commit_memory_region(struct kvm *kvm,
if (old->dirty_bitmap && !new->dirty_bitmap)
kvm_destroy_dirty_bitmap(old);
+ /*
+ * Unbind the guest_memfd instance as needed; the @new slot has
+ * already created its own binding. TODO: Drop the WARN when
+ * dirty logging guest_memfd memslots is supported. Until then,
+ * flags-only changes on guest_memfd slots should be impossible.
+ */
+ if (WARN_ON_ONCE(old->flags & KVM_MEM_GUEST_MEMFD))
+ kvm_gmem_unbind(old);
+
/*
* The final quirk. Free the detached, old slot, but only its
* memory, not any metadata. Metadata, including arch specific
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 042/670] KVM: Only bind memslot to guest_memfd instance for CREATE operations
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (40 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 041/670] KVM: Harden and prepare for modifying existing guest_memfd memslots Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 043/670] KVM: x86: Clear hardware HLT state when userspace makes a vCPU not-halted Greg Kroah-Hartman
` (629 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Hildenbrand (Arm),
Sean Christopherson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <seanjc@google.com>
[ Upstream commit 513333a5546017da2a4a6173bfb70372f83733b3 ]
For additional defense-in-depth, and to avoid having to handle impossible
unwind scenarios when binding to a memslot fails, bind a memslot to a gmem
instance only for CREATE operations, i.e. don't attempt to establish a
binding for MOVE and FLAGS_ONLY operations. And when FLAGS_ONLY operations
are eventually supported (this is currently all dead code), creating a new
binding would be incorrect; KVM instead needs to do a 1:1 replacement of
the existing binding, i.e. FLAGS_ONLY will need its own dedicated handling.
Update the relevant TODO to make a better guess as to what needs to be done
to support toggling dirty logging for guest_memfd memslots.
Because it's dead code, no functional change intended.
Cc: stable@vger.kernel.org
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Link: https://patch.msgid.link/20260922001332.1121266-4-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
virt/kvm/kvm_main.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 0d017f75c5a11..c574cd2f4f722 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1740,10 +1740,10 @@ static void kvm_commit_memory_region(struct kvm *kvm,
kvm_destroy_dirty_bitmap(old);
/*
- * Unbind the guest_memfd instance as needed; the @new slot has
- * already created its own binding. TODO: Drop the WARN when
- * dirty logging guest_memfd memslots is supported. Until then,
- * flags-only changes on guest_memfd slots should be impossible.
+ * TODO: Drop the WARN and do the unbind() call only for MOVE
+ * when dirty logging guest_memfd memslots is supported. Until
+ * then, flags-only changes on guest_memfd slots should also be
+ * impossible; unbind the old memslot for defense-in-depth.
*/
if (WARN_ON_ONCE(old->flags & KVM_MEM_GUEST_MEMFD))
kvm_gmem_unbind(old);
@@ -2102,7 +2102,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
new->npages = npages;
new->flags = mem->flags;
new->userspace_addr = mem->userspace_addr;
- if (mem->flags & KVM_MEM_GUEST_MEMFD) {
+ if (change == KVM_MR_CREATE && (mem->flags & KVM_MEM_GUEST_MEMFD)) {
r = kvm_gmem_bind(kvm, new, mem->guest_memfd, mem->guest_memfd_offset);
if (r)
goto out;
@@ -2115,7 +2115,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
return 0;
out_unbind:
- if (mem->flags & KVM_MEM_GUEST_MEMFD)
+ if (change == KVM_MR_CREATE && (mem->flags & KVM_MEM_GUEST_MEMFD))
kvm_gmem_unbind(new);
out:
kfree(new);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 043/670] KVM: x86: Clear hardware HLT state when userspace makes a vCPU not-halted
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (41 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 042/670] KVM: Only bind memslot to guest_memfd instance for CREATE operations Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 044/670] KVM: guest_memfd: take the invalidate lock when unbinding a dying file Greg Kroah-Hartman
` (628 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Qinguang Chen, Zhiping Du,
Keqiang Duan, Chao Gao, Sean Christopherson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Keqiang Duan <duankeqiangcym@gmail.com>
[ Upstream commit 883719f57f5d3898637b130d6db4742471cad618 ]
Force a vCPU out of its hardware-tracked halted state when userspace puts
the vCPU into any state other than HALTED via KVM_SET_MP_STATE, i.e. clear
VMCS.GUEST_ACTIVITY_STATE if it says the vCPU is halted. Add an optional
kvm_x86_ops hook to do the clearing, as SVM has no equivalent VMCB field.
When HLT-exiting is disabled for a VM (KVM_CAP_X86_DISABLE_EXITS with
KVM_X86_DISABLE_EXITS_HLT, e.g. QEMU's "-overcommit cpu-pm=on"), a guest
HLT halts the physical CPU instead of exiting to KVM, and hardware saves
GUEST_ACTIVITY_STATE=HLT into the VMCS on the next VM-Exit. That field is
sticky: it survives VM-Exit/VM-Enter and is only cleared by vmx_clear_hlt()
on event injection, or by vmx_vcpu_reset() on INIT / vCPU creation.
Nothing clears it on a userspace-driven state change. KVM_SET_REGS only
writes the software register cache and KVM_SET_MP_STATE only writes
vcpu->arch.mp_state; kvm_vcpu_running() likewise consults software state
only. A VMM that emulates a machine reset therefore ends up with a vCPU
that KVM happily VM-Enters while hardware refuses to fetch instructions.
Reproduce with a Linux guest by triggering a panic/kdump on a non-boot
vCPU: nmi_shootdown_cpus() parks the other vCPUs -- including vCPU0 -- in
crash_nmi_callback(), which does local_irq_disable() followed by a bare
HLT. The capture kernel then resets the machine via port 0xCF9. QEMU
rewrites RIP to 0xfff0 and sets mp_state to RUNNABLE, but vCPU0's
GUEST_ACTIVITY_STATE is still HLT, so the BSP never executes the reset
vector, never sends SIPIs, and the entire VM hangs at "reboot: machine
restart" forever. Only destroying and recreating the VM recovers it.
Key off "not HALTED" rather than "is RUNNABLE" as HALTED is the only target
state for which retaining the hardware halted state is meaningful; every
other transition either can't be reached on VMX, e.g. AP_RESET_HOLD, or
goes through vmx_vcpu_reset(), which stuffs GUEST_ACTIVITY_ACTIVE anyways.
This also captures the intent more directly: KVM only ever drops the
hardware halted state, it never installs it.
Hook KVM_SET_MP_STATE rather than the VM-Enter path so that the clearing
is driven by an explicit userspace declaration, and so that no work is
added to vmx_vcpu_run(). Gate the call on kvm_hlt_in_guest() even though
vmx_clear_hlt() checks it as well, as the check is cheap and makes it
obvious in common code when the hardware state can exist at all.
Do nothing for TDX vCPUs as TDX doesn't support disabling HLT-exiting and
KVM cannot access a TD's VMCS, i.e. the VMCS used to run the vCPU can't
in HALTED state, and even if it were, KVM can't change it.
Fixes: caa057a2cad6 ("KVM: X86: Provide a capability to disable HLT intercepts")
Cc: stable@vger.kernel.org
Tested-by: Qinguang Chen <chenqinguang@kuaishou.com>
Signed-off-by: Zhiping Du <duzhiping@kuaishou.com>
Signed-off-by: Keqiang Duan <duankeqiangcym@gmail.com>
Reviewed-by: Chao Gao <chao.gao@intel.com>
Link: https://patch.msgid.link/20260820123512.87236-1-duankeqiangcym@gmail.com
[sean: drop claim that spurious wakeups are ok, massage changelog]
Signed-off-by: Sean Christopherson <seanjc@google.com>
[ sashal: Adapted to direct VMX callback registration and existing MP-state assignments because the TDX wrapper and kvm_set_mp_state() helper are absent. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/include/asm/kvm-x86-ops.h | 1 +
arch/x86/include/asm/kvm_host.h | 7 +++++++
arch/x86/kvm/vmx/main.c | 1 +
arch/x86/kvm/vmx/vmx.c | 2 +-
arch/x86/kvm/vmx/x86_ops.h | 1 +
arch/x86/kvm/x86.c | 13 +++++++++++++
6 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h
index 861d080ed4c6a..63bdbd15efcde 100644
--- a/arch/x86/include/asm/kvm-x86-ops.h
+++ b/arch/x86/include/asm/kvm-x86-ops.h
@@ -78,6 +78,7 @@ KVM_X86_OP(interrupt_allowed)
KVM_X86_OP(nmi_allowed)
KVM_X86_OP(get_nmi_mask)
KVM_X86_OP(set_nmi_mask)
+KVM_X86_OP_OPTIONAL(clear_hlt)
KVM_X86_OP(enable_nmi_window)
KVM_X86_OP(enable_irq_window)
KVM_X86_OP_OPTIONAL(update_cr8_intercept)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index cec497aed149a..93d3f8010a1f8 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1735,6 +1735,13 @@ struct kvm_x86_ops {
int (*nmi_allowed)(struct kvm_vcpu *vcpu, bool for_injection);
bool (*get_nmi_mask)(struct kvm_vcpu *vcpu);
void (*set_nmi_mask)(struct kvm_vcpu *vcpu, bool masked);
+ /*
+ * Force the vCPU out of any hardware-tracked halted/inactive state so
+ * that it will fetch and execute instructions on the next VM-Enter.
+ * Only needed by VMX, where VMCS.GUEST_ACTIVITY_STATE persists across
+ * VM-Exit/VM-Enter; SVM has no equivalent VMCB field.
+ */
+ void (*clear_hlt)(struct kvm_vcpu *vcpu);
/* Whether or not a virtual NMI is pending in hardware. */
bool (*is_vnmi_pending)(struct kvm_vcpu *vcpu);
/*
diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c
index 3f83e36a657b9..8a922ce0d19c4 100644
--- a/arch/x86/kvm/vmx/main.c
+++ b/arch/x86/kvm/vmx/main.c
@@ -90,6 +90,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = {
.nmi_allowed = vmx_nmi_allowed,
.get_nmi_mask = vmx_get_nmi_mask,
.set_nmi_mask = vmx_set_nmi_mask,
+ .clear_hlt = vmx_clear_hlt,
.enable_nmi_window = vmx_enable_nmi_window,
.enable_irq_window = vmx_enable_irq_window,
.update_cr8_intercept = vmx_update_cr8_intercept,
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index a36d9f504ba53..8e23e901a7593 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -1814,7 +1814,7 @@ int vmx_skip_emulated_instruction(struct kvm_vcpu *vcpu)
return skip_emulated_instruction(vcpu);
}
-static void vmx_clear_hlt(struct kvm_vcpu *vcpu)
+void vmx_clear_hlt(struct kvm_vcpu *vcpu)
{
/*
* Ensure that we clear the HLT state in the VMCS. We don't need to
diff --git a/arch/x86/kvm/vmx/x86_ops.h b/arch/x86/kvm/vmx/x86_ops.h
index 5e4ce13ab3051..4348674de9f35 100644
--- a/arch/x86/kvm/vmx/x86_ops.h
+++ b/arch/x86/kvm/vmx/x86_ops.h
@@ -96,6 +96,7 @@ int vmx_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection);
int vmx_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection);
bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu);
void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked);
+void vmx_clear_hlt(struct kvm_vcpu *vcpu);
void vmx_enable_nmi_window(struct kvm_vcpu *vcpu);
void vmx_enable_irq_window(struct kvm_vcpu *vcpu);
void vmx_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 68599667907c8..ea8b6ec561dc4 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -11281,6 +11281,19 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
set_bit(KVM_APIC_SIPI, &vcpu->arch.apic->pending_events);
} else
vcpu->arch.mp_state = mp_state->mp_state;
+
+ /*
+ * Force the vCPU out of any hardware-tracked halted state, e.g. VMX's
+ * GUEST_ACTIVITY_STATE=HLT, when userspace puts the vCPU into a state
+ * other than HALTED. The hardware state is sticky across VM-Exit and
+ * VM-Enter and is not touched by any other ioctl, so a vCPU that halted
+ * with HLT-exiting disabled stays wedged even after userspace rewrites
+ * its registers, e.g. when a VMM emulates a machine reset.
+ */
+ if (kvm_hlt_in_guest(vcpu->kvm) &&
+ mp_state->mp_state != KVM_MP_STATE_HALTED)
+ kvm_x86_call(clear_hlt)(vcpu);
+
kvm_make_request(KVM_REQ_EVENT, vcpu);
ret = 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 044/670] KVM: guest_memfd: take the invalidate lock when unbinding a dying file
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (42 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 043/670] KVM: x86: Clear hardware HLT state when userspace makes a vCPU not-halted Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 045/670] ksmbd: look up stream size by exact xattr name Greg Kroah-Hartman
` (627 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sashiko, Sean Christopherson,
Shivank Garg, David Hildenbrand (Arm), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shivank Garg <shivankg@amd.com>
[ Upstream commit 0ee2c883b62deb74d8c43007e8049dc006d3a2fb ]
kvm_gmem_unbind() takes mapping->invalidate_lock only if the
get_file_active() succeeds. When the guest_memfd file is dying, its
reference count is already zero so get_file_active fails and the binding
is removed without holding the invalidate lock.
kvm_gmem_invalidate_{start,end}() checks f->bindings independently to
decide whether to begin or end KVM MMU invalidation. So, the bindings
must therefore remain stable between the two calls. Otherwise, unbind
can remove a binding after start increments mmu_invalidate_in_progress,
but before end finds the binding and decrements it.
Example, unbind race with memory failure:
CPU 0: memory failure CPU 1: memslot delete
---------------------------------- ---------------------------
(guest_memfd file is dying)
kvm_gmem_error_folio()
kvm_gmem_invalidate_start()
finds binding
mmu_invalidate_in_progress++
kvm_gmem_unbind()
get_file_active() fails
removes binding
kvm_gmem_invalidate_end()
no binding found
counter stays elevated
mmu_invalidate_retry() then returns 1 forever, so guest page faults
retry without ever installing a mapping and the guest hangs.
Remove the distinction between live and dying files in the unbind path.
Always use slot->gmem.file and take the invalidate lock when it's non-NULL.
Normal unbind callers hold slots_lock, which prevents release from clearing
the pointer or freeing the file state until unbind completes. Final VM
teardown can only see a NULL pointer because guest_memfd pins the KVM until
release has cleared all bindings.
Fixes: ae431059e75d ("KVM: guest_memfd: Remove bindings on memslot deletion when gmem is dying")
Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260728092027.225CF1F000E9@smtp.kernel.org
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Shivank Garg <shivankg@amd.com>
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Link: https://patch.msgid.link/20260901-gmem-unbind-fix-v2-1-12febe1d2216@amd.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
[ sashal: adapted unbinding to the existing kvm_gmem structure and explicit kvm_gmem_get_file()/fput() reference handling ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
virt/kvm/guest_memfd.c | 48 ++++++++++++++++--------------------------
1 file changed, 18 insertions(+), 30 deletions(-)
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 2e9b5129b5a22..88b7279f4634d 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -538,53 +538,41 @@ int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
return r;
}
-static void __kvm_gmem_unbind(struct kvm_memory_slot *slot, struct kvm_gmem *gmem)
+void kvm_gmem_unbind(struct kvm_memory_slot *slot)
{
+ struct file *file = slot->gmem.file;
unsigned long start = slot->gmem.pgoff;
unsigned long end = start + slot->npages;
-
- xa_store_range(&gmem->bindings, start, end - 1, NULL, GFP_KERNEL);
-
- /*
- * synchronize_srcu(&kvm->srcu) ensured that kvm_gmem_get_pfn()
- * cannot see this memslot.
- */
- WRITE_ONCE(slot->gmem.file, NULL);
-}
-
-void kvm_gmem_unbind(struct kvm_memory_slot *slot)
-{
- struct file *file;
+ struct kvm_gmem *gmem;
/*
* Nothing to do if the underlying file was _already_ closed, as
* kvm_gmem_release() invalidates and nullifies all bindings.
*/
- if (!slot->gmem.file)
+ if (!file)
return;
- file = kvm_gmem_get_file(slot);
-
/*
* However, if the file is _being_ closed, then the bindings need to be
* removed as kvm_gmem_release() might not run until after the memslot
- * is freed. Note, modifying the bindings is safe even though the file
- * is dying as kvm_gmem_release() nullifies slot->gmem.file under
- * slots_lock, and only puts its reference to KVM after destroying all
- * bindings. I.e. reaching this point means kvm_gmem_release() hasn't
- * yet destroyed the bindings or freed the gmem_file, and can't do so
- * until the caller drops slots_lock.
+ * is freed. Modifying the bindings is safe even if the file is dying
+ * as kvm_gmem_release() nullifies slot->gmem.file under slots_lock,
+ * and only puts its reference to KVM after destroying all bindings.
+ * I.e. reaching this point means kvm_gmem_release() hasn't destroyed
+ * the bindings or freed the gmem_file and can't do so until the caller
+ * drops slots_lock, so there's no need to verify the file is live.
*/
- if (!file) {
- __kvm_gmem_unbind(slot, slot->gmem.file->private_data);
- return;
- }
+ gmem = file->private_data;
filemap_invalidate_lock(file->f_mapping);
- __kvm_gmem_unbind(slot, file->private_data);
- filemap_invalidate_unlock(file->f_mapping);
+ xa_store_range(&gmem->bindings, start, end - 1, NULL, GFP_KERNEL);
- fput(file);
+ /*
+ * synchronize_srcu(&kvm->srcu) ensured that kvm_gmem_get_pfn()
+ * cannot see this memslot.
+ */
+ WRITE_ONCE(slot->gmem.file, NULL);
+ filemap_invalidate_unlock(file->f_mapping);
}
/* Returns a locked folio on success. */
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 045/670] ksmbd: look up stream size by exact xattr name
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (43 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 044/670] KVM: guest_memfd: take the invalidate lock when unbinding a dying file Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 046/670] serial: amba-pl011: keep transmitter enabled when disabling RS485 Greg Kroah-Hartman
` (626 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Gael Blivet, Namjae Jeon,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gael Blivet <gael.blivet@gmail.com>
[ Upstream commit 10ea20d6584ecdaf2f7505855412a856a88d8934 ]
get_file_stream_info() walks the xattr list from a single
ksmbd_vfs_listxattr() and sizes each stream it finds with
ksmbd_vfs_casexattr_len(), which matches with strncasecmp(). Linux
xattr names are case-sensitive, so two streams differing only in case
report each other's size.
The loop already holds the exact name, so query it directly with
ksmbd_vfs_xattr_len(), which is what casexattr_len() calls once its
search succeeds. Make it non-static and declare it in vfs.h, and drop
the comment above it, which describes a different bug and no longer
matches the code.
This also drops a full listing per stream: casexattr_len() runs its own
listxattr on every call, so enumerating a file with N xattrs cost N
listings instead of one.
Fixes: 689f1eb3719d ("ksmbd: report actual xattr value length in stream enumeration")
Signed-off-by: Gael Blivet <gael.blivet@gmail.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
[ sashal: adapted ksmbd_vfs_xattr_len() to accept a non-const struct mnt_idmap pointer ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/server/smb2pdu.c | 13 ++-----------
fs/smb/server/vfs.c | 4 ++--
fs/smb/server/vfs.h | 2 ++
3 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 4e0f43051d9e0..1ed32310c73a5 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -5275,17 +5275,8 @@ static int get_file_stream_info(struct ksmbd_work *work,
streamlen *= 2;
kfree(stream_buf);
file_info->StreamNameLength = cpu_to_le32(streamlen);
- /*
- * stream_name_len is the byte length of the xattr's *name*,
- * not its value -- same class of bug ksmbd_stream_eof()
- * (smb2pdu.c) already fixes for EndOfFile/AllocationSize on
- * a stream handle; this enumeration path needs the same
- * real xattr value length, not the name length reused as a
- * size.
- */
- slen = ksmbd_vfs_casexattr_len(file_mnt_idmap(fp->filp),
- path->dentry, stream_name,
- strlen(stream_name) + 1, NULL);
+ slen = ksmbd_vfs_xattr_len(file_mnt_idmap(fp->filp),
+ path->dentry, stream_name);
ssize = slen < 0 ? 0 : (loff_t)slen;
file_info->StreamSize = cpu_to_le64(ssize);
file_info->StreamAllocationSize = cpu_to_le64(ssize);
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index dafb92aa39a6c..9aee0214e8fdc 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -943,8 +943,8 @@ ssize_t ksmbd_vfs_listxattr(struct dentry *dentry, char **list)
return size;
}
-static ssize_t ksmbd_vfs_xattr_len(struct mnt_idmap *idmap,
- struct dentry *dentry, char *xattr_name)
+ssize_t ksmbd_vfs_xattr_len(struct mnt_idmap *idmap,
+ struct dentry *dentry, char *xattr_name)
{
return vfs_getxattr(idmap, dentry, xattr_name, NULL, 0);
}
diff --git a/fs/smb/server/vfs.h b/fs/smb/server/vfs.h
index 397dd2dd09886..1ca170dfb349d 100644
--- a/fs/smb/server/vfs.h
+++ b/fs/smb/server/vfs.h
@@ -106,6 +106,8 @@ ssize_t ksmbd_vfs_getxattr(struct mnt_idmap *idmap,
struct dentry *dentry,
char *xattr_name,
char **xattr_buf);
+ssize_t ksmbd_vfs_xattr_len(struct mnt_idmap *idmap,
+ struct dentry *dentry, char *xattr_name);
ssize_t ksmbd_vfs_casexattr_len(struct mnt_idmap *idmap,
struct dentry *dentry, char *attr_name,
int attr_name_len, char *actual_name);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 046/670] serial: amba-pl011: keep transmitter enabled when disabling RS485
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (44 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 045/670] ksmbd: look up stream size by exact xattr name Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 047/670] nvme-tcp: fix io_work priority inversion when send_mutex is held Greg Kroah-Hartman
` (625 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, stable, Nicolai Buchwitz,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolai Buchwitz <nb@tipi-net.de>
commit 97f85204275ae4d7fb530e451f3acc65c1ec1155 upstream.
Disabling RS485 on an open port calls pl011_rs485_tx_stop(), which
turns off the transmitter. Only the RS485 TX path turns it back on, so
any later output stays queued and tcdrain() hangs until the port is
closed.
pl011_rs485_tx_stop() also checks only the hardware FIFO. If a DMA
transfer has started but has not filled the FIFO yet, the transmitter
is turned off under the transfer and the DMA channel never recovers.
When leaving RS485 mode, cancel pending deferred starts and stops, leave
the transmitter enabled and start any TX that was still waiting for
delay_rts_before_send.
Fixes: 8d479237727c ("serial: amba-pl011: add RS485 support")
Cc: stable@kernel.org
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
Link: https://patch.msgid.link/20261012-fix-pl011-rs485-txe-v2-1-e9bf7d218389@tipi-net.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[nb: Use rs485_tx_started and omit timer handling on older kernels.]
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/tty/serial/amba-pl011.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 3e1932a3bfbbd..a0e20bffefba8 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2224,8 +2224,21 @@ static int pl011_rs485_config(struct uart_port *port, struct ktermios *termios,
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
- if (port->rs485.flags & SER_RS485_ENABLED)
+ if ((port->rs485.flags & SER_RS485_ENABLED) &&
+ !(rs485->flags & SER_RS485_ENABLED)) {
+ u32 cr = pl011_read(uap, REG_CR);
+
+ /*
+ * Leaving RS485 mode, which only enables the transmitter while
+ * sending. Don't stop it, as that stalls a DMA transfer still
+ * in flight. Keep the transmitter and receiver enabled.
+ */
+ uap->rs485_tx_started = false;
+ cr |= UART011_CR_TXE | UART011_CR_RXE;
+ pl011_write(cr, uap, REG_CR);
+ } else if (port->rs485.flags & SER_RS485_ENABLED) {
pl011_rs485_tx_stop(uap);
+ }
/* Make sure auto RTS is disabled */
if (rs485->flags & SER_RS485_ENABLED) {
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 047/670] nvme-tcp: fix io_work priority inversion when send_mutex is held
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (45 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 046/670] serial: amba-pl011: keep transmitter enabled when disabling RS485 Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 048/670] PCI: Skip Target Speed quirk on clamped ports with no link Greg Kroah-Hartman
` (624 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Seiji Nishikawa, Keith Busch,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Seiji Nishikawa <snishika@redhat.com>
[ Upstream commit 5db358f3a7f9c33717622c1597d15c4c91997b19 ]
Commit f42d4796ee10 ("nvme-tcp: fix I/O stalls on congested sockets")
added a check in nvme_tcp_io_work() that sets pending to true when the
queue has pending requests and the socket is writeable. The check is
placed after the mutex_trylock() block, so it also runs when
mutex_trylock(&queue->send_mutex) failed and io_work did not send
anything.
When .queue_rq sends a request directly from its own context, it holds
send_mutex and can give up the CPU in lock_sock_nested() when another
task needs the CPU, for example the io_work kworker of the same queue,
which runs on the same CPU. Then io_work cannot take send_mutex, but
the requests are still on req_list and the socket is writeable, so
pending is set to true. io_work loops until the deadline and queues
itself again on io_cpu, without sleeping.
This is a priority inversion. io_work runs on the high priority
nvme_tcp_wq and cannot make progress until send_mutex is released, but
it keeps running. The task holding send_mutex runs at normal priority
and needs the CPU to release it. The scheduler keeps giving the CPU to
io_work, so the task holding send_mutex may not run again, and the
requests on the queue are not sent and time out.
This is the same problem that commit 70f437fb4395 ("nvme-tcp: fix
io_work priority inversion") fixed. That commit removed
"pending = !llist_empty(&queue->req_list)" from the path where
mutex_trylock() fails, and let the task holding send_mutex queue
io_work again in nvme_tcp_queue_request() after it releases the mutex.
The new check brings back the same behavior in a different form.
Two things make this easier to hit. nvme_tcp_queue_request() sends
directly only when it runs on io_cpu, so the task that takes send_mutex
is on the same CPU as the io_work kworker of that queue when it takes
the mutex. Also, when the tasks are in a cgroup with the cpu controller
enabled, the whole group competes with the nice -20 kworker as one
entity, so each task in the group gets even less CPU time.
We hit this on a 6 CPU VM running a database on nvme-tcp storage. In
the vmcore, 2 tasks held send_mutex of 2 queues and were runnable in
lock_sock_nested() for 103 seconds, while the kworkers for those queues
kept running io_work on their CPUs. All database tasks were in one
cgroup, which got only about 0.3% of the CPU against the nice -20
kworker. Requests timed out, and blk_mq_timeout_work() waited in
synchronize_srcu() for the tasks still in .queue_rq.
Only do the pending check if io_work could take send_mutex. If it could
not, the task holding send_mutex sends what it can in
nvme_tcp_send_all(), and queues io_work again after it releases the
mutex if requests are still pending, so no request is left behind.
Fixes: f42d4796ee10 ("nvme-tcp: fix I/O stalls on congested sockets")
Cc: stable@vger.kernel.org # v6.16+
Signed-off-by: Seiji Nishikawa <snishika@redhat.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Seiji Nishikawa <snishika@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/nvme/host/tcp.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 67d02cfb47ec7..82cf9419a6be4 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -1446,9 +1446,11 @@ static void nvme_tcp_io_work(struct work_struct *w)
do {
bool pending = false;
+ bool got_send_mutex = false;
int result;
if (mutex_trylock(&queue->send_mutex)) {
+ got_send_mutex = true;
result = nvme_tcp_try_send(queue);
mutex_unlock(&queue->send_mutex);
if (result > 0)
@@ -1463,8 +1465,13 @@ static void nvme_tcp_io_work(struct work_struct *w)
else if (unlikely(result < 0))
return;
- /* did we get some space after spending time in recv? */
- if (nvme_tcp_queue_has_pending(queue) &&
+ /*
+ * did we get some space after spending time in recv?
+ * Only check this if we could take send_mutex. Otherwise
+ * the task holding it sends the requests and queues io_work
+ * again after it releases the mutex.
+ */
+ if (got_send_mutex && nvme_tcp_queue_has_pending(queue) &&
sk_stream_is_writeable(queue->sock->sk))
pending = true;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 048/670] PCI: Skip Target Speed quirk on clamped ports with no link
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (46 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 047/670] nvme-tcp: fix io_work priority inversion when send_mutex is held Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 049/670] mlxsw: Initialize register query payloads Greg Kroah-Hartman
` (623 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Andreas Wild, Maciej W. Rozycki,
Bjorn Helgaas, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej W. Rozycki <macro@orcam.me.uk>
[ Upstream commit ff8a969f7dc8e79ea6113abcfa983e070b2b585a ]
Since commit 72780f796468 ("PCI: Always lift 2.5GT/s restriction in PCIe
failed link retraining") the Target Speed quirk lifts a firmware-imposed
2.5GT/s restriction on any downstream port, without checking whether the
link is up. Where nothing is plugged in, the retraining that follows can
never complete, so each attempt costs PCIE_LINK_RETRAIN_TIMEOUT_MS. The
quirk makes two of them -- the initial one and the restore on the error
path -- adding a fixed 2 s to every boot.
On an MSI PRO Z690-A WIFI DDR4 (Intel 600 Series PCH) with one empty x1
slot, running v7.2-rc5:
0.541 pci 0000:00:1c.0: removing 2.5GT/s downstream link speed restriction
1.541 pci 0000:00:1c.0: retraining failed
2.541 pci 0000:00:1c.2: [8086:7aba] type 01 class 0x060400
Where the Link Speed has already been clamped at 2.5GT/s and no link has
been established there is nothing worth doing, which is what the kerneldoc
for the quirk already describes: the restriction is to be lifted where
firmware arranged it "and the port reports its link already being up".
Bail out early in that case, before either the ASM2824 workaround or the
removal of the restriction is considered.
Ports whose link is up are unaffected, and so is the ASM2824 workaround,
which is reached with the Target Link Speed not clamped.
With this applied the quirk returns without touching the port: both
messages are gone, enumeration proceeds from 0000:00:1c.0 to 0000:00:1c.2
in 1 ms rather than 2 s, and the systemd "kernel" boot phase goes from
3.011 s to 1.036 s.
Fixes: 72780f796468 ("PCI: Always lift 2.5GT/s restriction in PCIe failed link retraining")
Reported-by: Andreas Wild <andiwild@gmail.com>
Closes: https://lore.kernel.org/lkml/20260801092152.5643-1-andiwild@gmail.com/
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221801
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Signed-off-by: Andreas Wild <andiwild@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Andreas Wild <andiwild@gmail.com>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260801201244.4421-1-andiwild@gmail.com
[ Andreas: this tree predates pcie_lbms_seen() and pcie_set_target_speed()
and still tests LBMS and DLLLA in one expression, so the hunk did not
apply. Split that test the same way as upstream and compare the
LNKCTL2 Target Link Speed field against PCI_EXP_LNKCTL2_TLS_2_5GT
directly, as the existing code further down already does. ]
Signed-off-by: Andreas Wild <andiwild@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pci/quirks.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 8cfa7a3f55cb3..5b266583acb57 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -93,8 +93,12 @@ int pcie_failed_link_retrain(struct pci_dev *dev)
pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &lnkctl2);
pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
oldlnkctl2 = lnkctl2;
- if ((lnksta & (PCI_EXP_LNKSTA_LBMS | PCI_EXP_LNKSTA_DLLLA)) ==
- PCI_EXP_LNKSTA_LBMS) {
+ if (lnksta & PCI_EXP_LNKSTA_DLLLA) {
+ ;
+ } else if ((lnkctl2 & PCI_EXP_LNKCTL2_TLS) ==
+ PCI_EXP_LNKCTL2_TLS_2_5GT) {
+ return ret;
+ } else if (lnksta & PCI_EXP_LNKSTA_LBMS) {
pci_info(dev, "broken device, retraining non-functional downstream link at 2.5GT/s\n");
lnkctl2 &= ~PCI_EXP_LNKCTL2_TLS;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 049/670] mlxsw: Initialize register query payloads
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (47 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 048/670] PCI: Skip Target Speed quirk on clamped ports with no link Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 050/670] io_uring/cancel: drop sqd->lock while SQPOLL waits Greg Kroah-Hartman
` (622 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Til Kaiser, Ido Schimmel,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Til Kaiser <mail@tk154.de>
[ Upstream commit 15b7a86a8888dc6a8fd19e181757e32389de9064 ]
MFGD register queries can exhaust EMAD retries and leave Mellanox
Spectrum switches stuck during boot or shutdown when running OpenWrt
built with GCC 15.
An example failure is shown below with the second line wrapped:
EMAD retries (5/5) (tid=9b544fc100001f35)
EMAD reg access failed (tid=9b544fc100001f35,reg_id=90f0(mfgd),
type=query,status=0(operation performed))
On an SN2100, the failure occurs during driver teardown on reboot.
On an SN3420, it occurs while probing mlxsw_spectrum during boot.
The register query API transmits the supplied payload to the device
before replacing it with the response. Both MFGD callers pass an
uninitialized stack buffer, so the request contains arbitrary register
field values and reserved bits. This makes the request depend on stack
contents and compiler code generation.
Initialize both MFGD query buffers in the firmware fatal event
configuration and reporter test paths. The initialization has been
confirmed to eliminate the boot and shutdown hangs on both switches.
The subsequent read-modify-write still preserves the other fields
returned by the device.
Also initialize the FORE fan fault query and the MOGCR mirroring policer
base query, which pass entirely uninitialized payloads. Restore the MTMP
query initialization in the temperature history reset path, where only
the slot and sensor index fields are set before querying the register.
This follows commit 5b0907407e7f ("mlxsw: core: Zero payload buffers for
couple of registers"), which initialized other query payloads after a
firmware field length bug caused firmware to consume uninitialized data.
Tested with firmware 2020.1148 and with 2016.3900 from linux-firmware.
Fixes: 7d83ee111008 ("mlxsw: core: Introduce fw_fatal health reporter")
Fixes: 2c6a33cd334b ("mlxsw: core: Extend hwmon interface with fan fault attribute")
Fixes: 4039504e6a0c ("mlxsw: spectrum_span: Allow setting policer on a SPAN agent")
Fixes: b890ad418e1f ("mlxsw: core_hwmon: Extend internal structures to support multi hwmon objects")
Cc: stable@vger.kernel.org
Signed-off-by: Til Kaiser <mail@tk154.de>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20261014173117.26305-1-mail@tk154.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
(cherry picked from commit 15b7a86a8888dc6a8fd19e181757e32389de9064)
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/mellanox/mlxsw/core.c | 4 ++--
drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 4 ++--
drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
index 4a79c0d7e7ad8..feaeb4118f0bc 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c
@@ -2002,7 +2002,7 @@ mlxsw_core_health_fw_fatal_test(struct devlink_health_reporter *reporter,
struct netlink_ext_ack *extack)
{
struct mlxsw_core *mlxsw_core = devlink_health_reporter_priv(reporter);
- char mfgd_pl[MLXSW_REG_MFGD_LEN];
+ char mfgd_pl[MLXSW_REG_MFGD_LEN] = {0};
int err;
/* Read the register first to make sure no other bits are changed. */
@@ -2023,7 +2023,7 @@ mlxsw_core_health_fw_fatal_ops = {
static int mlxsw_core_health_fw_fatal_config(struct mlxsw_core *mlxsw_core,
bool enable)
{
- char mfgd_pl[MLXSW_REG_MFGD_LEN];
+ char mfgd_pl[MLXSW_REG_MFGD_LEN] = {0};
int err;
/* Read the register first to make sure no other bits are changed. */
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
index 9c12e1feb6437..e39a8b0a57095 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
@@ -120,7 +120,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev,
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
- char mtmp_pl[MLXSW_REG_MTMP_LEN];
+ char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0};
unsigned long val;
int index;
int err;
@@ -177,7 +177,7 @@ static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev,
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
- char fore_pl[MLXSW_REG_FORE_LEN];
+ char fore_pl[MLXSW_REG_FORE_LEN] = {0};
bool fault;
int err;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
index 32d2e61f2b823..91fb77c8e20d6 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
@@ -1720,7 +1720,7 @@ static int mlxsw_sp2_span_init(struct mlxsw_sp *mlxsw_sp)
static int mlxsw_sp2_span_policer_id_base_set(struct mlxsw_sp *mlxsw_sp,
u16 policer_id_base)
{
- char mogcr_pl[MLXSW_REG_MOGCR_LEN];
+ char mogcr_pl[MLXSW_REG_MOGCR_LEN] = {0};
int err;
err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mogcr), mogcr_pl);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 050/670] io_uring/cancel: drop sqd->lock while SQPOLL waits
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (48 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 049/670] mlxsw: Initialize register query payloads Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 051/670] io_uring/sqpoll: dont attach to a thread that is canceling Greg Kroah-Hartman
` (621 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Chris Mason, Jens Axboe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Mason <mason@kernel.org>
Commit cb0306c52ffae083a86fb283de67875ae7a9500e upstream.
An exiting SQPOLL thread calls io_uring_cancel_generic() with sqd->lock
held, and keeps it across cond_resched() and the sleep until nothing is
in flight anymore. A zero-copy send notification can't be canceled and
stays pending as long as the peer doesn't read, so the lock is held for
as long as a user cares to. io_ring_exit_work() needs it to park the
thread, and so do IORING_REGISTER_IOWQ_AFF and IOWQ_MAX_WORKERS. With
64 such rings sharing the thread, every iou_exit slot sleeps on the lock
and no ring gets freed for anyone.
Drop the lock around cond_resched() and the sleep, like the main loop of
the thread does. Each walk of ctx_list is still under one hold, and
nothing is kept across the unlock. The thread drops its io-wq, frees its
tctx and clears sqd->thread under one hold after the loop, so whoever
holds the lock and finds sqd->thread set can still use them.
Fixes: 63809137ebb5 ("io_uring: flush notifiers after sendzc")
Signed-off-by: Chris Mason <mason@kernel.org>
[axboe: adapted to the schedule_timeout() based loop]
Signed-off-by: Jens Axboe <axboe@kernel.dk>
[axboe: io_uring_cancel_generic() is in io_uring.c in 6.12, and uses a
schedule() based wait loop]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/io_uring.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index 52759ee3bd6c9..09551e3907f91 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -3282,7 +3282,16 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
}
if (loop) {
+ /*
+ * A request that runs in io-wq and doesn't end makes
+ * each round come here. Don't hold sqd->lock for that
+ * long either.
+ */
+ if (sqd)
+ mutex_unlock(&sqd->lock);
cond_resched();
+ if (sqd)
+ mutex_lock(&sqd->lock);
continue;
}
@@ -3300,8 +3309,20 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
* avoids a race where a completion comes in before we did
* prepare_to_wait().
*/
- if (inflight == tctx_inflight(tctx, !cancel_all))
+ if (inflight == tctx_inflight(tctx, !cancel_all)) {
+ /*
+ * A zero-copy notification can't be canceled, and a
+ * peer that doesn't read keeps it pending. Don't hold
+ * sqd->lock while waiting for it, or whoever wants the
+ * lock sleeps as long. No ring is used across this,
+ * the next round walks ->ctx_list anew.
+ */
+ if (sqd)
+ mutex_unlock(&sqd->lock);
schedule();
+ if (sqd)
+ mutex_lock(&sqd->lock);
+ }
end_wait:
finish_wait(&tctx->wait, &wait);
} while (1);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 051/670] io_uring/sqpoll: dont attach to a thread that is canceling
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (49 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 050/670] io_uring/cancel: drop sqd->lock while SQPOLL waits Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 052/670] io_uring/sqpoll: dont set IO_SQ_THREAD_SHOULD_STOP on thread exit Greg Kroah-Hartman
` (620 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Karl Mehltretter, Jens Axboe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <axboe@kernel.dk>
Commit 22d9db9fd64a493525d692b32c556875b7254665 upstream.
io_sq_offload_create() refuses to attach a ring to an SQPOLL thread
that has already gone, by checking sqd->thread under sqd->lock. Since
the thread drops the lock while io_uring_cancel_generic() waits for its
requests, that check can run while the thread is on its way out and
still see it. The new ring is then added to ctx_list, io_uring_setup()
succeeds, the thread finishes canceling and exits without ever having
looked at the ring, and io_uring_enter() fails with -EOWNERDEAD.
Only a thread that exits on a fatal signal can be caught like this, as
the stop bit is set once the last ring has let go of the sqd, when no fd
is left to attach through. A fatal signal is group wide and attaching
needs the same thread group, so the attacher is on its way out as well.
Still, make the check see it: set the stop bit before canceling,
whatever the reason for the exit, and test it when attaching.
Reported-by: Karl Mehltretter <kmehltretter@gmail.com>
Fixes: cb0306c52ffa ("io_uring/cancel: drop sqd->lock while SQPOLL waits")
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/sqpoll.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/io_uring/sqpoll.c b/io_uring/sqpoll.c
index 696aba6bbf81d..6ce73c93a721a 100644
--- a/io_uring/sqpoll.c
+++ b/io_uring/sqpoll.c
@@ -435,6 +435,12 @@ static int io_sq_thread(void *data)
if (retry_list)
io_sq_tw(&retry_list, UINT_MAX);
+ /*
+ * Cancelation drops sqd->lock while it waits, and a ring could attach
+ * to a thread that is on its way out. A fatal signal doesn't set the
+ * bit, so set it here for io_sq_offload_create() to see.
+ */
+ set_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
io_uring_cancel_generic(true, sqd);
rcu_assign_pointer(sqd->thread, NULL);
put_task_struct(current);
@@ -503,7 +509,10 @@ __cold int io_sq_offload_create(struct io_ring_ctx *ctx,
list_add(&ctx->sqd_list, &sqd->ctx_list);
io_sqd_update_thread_idle(sqd);
/* don't attach to a dying SQPOLL thread, would be racy */
- ret = (attached && !sqd->thread) ? -ENXIO : 0;
+ ret = 0;
+ if (attached && (!sqd->thread ||
+ test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state)))
+ ret = -ENXIO;
io_sq_thread_unpark(sqd);
if (ret < 0)
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 052/670] io_uring/sqpoll: dont set IO_SQ_THREAD_SHOULD_STOP on thread exit
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (50 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 051/670] io_uring/sqpoll: dont attach to a thread that is canceling Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 053/670] io_uring/sqpoll: do the return-to-userspace work in the SQPOLL thread Greg Kroah-Hartman
` (619 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+675af112519ca34f5502,
Shuai Liu, Jens Axboe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuai Liu <847807867@qq.com>
Commit fca3ff9e2eee7d285585daf51942e0b5e2be354a upstream.
io_sq_thread_stop() carries a WARN_ON_ONCE() asserting that
IO_SQ_THREAD_SHOULD_STOP isn't set yet, i.e. that stopping the SQPOLL
thread is never attempted twice. Since commit 22d9db9fd64a
("io_uring/sqpoll: don't attach to a thread that is canceling"), the
SQPOLL thread itself sets that bit on its way out, so that
io_sq_offload_create() won't attach a new ring to a thread that is
canceling.
When the thread exits on a fatal signal, the bit is thus set before the
ring teardown gets to io_sq_thread_stop(), which now triggers the
warning on every such exit:
WARNING: io_uring/sqpoll.c:88 at io_sq_thread_stop
Workqueue: iou_exit io_ring_exit_work
Call Trace:
io_put_sq_data
io_sq_thread_finish
io_ring_ctx_free
io_ring_exit_work
Introduce a separate IO_SQ_THREAD_EXITING bit for the thread marking
itself as on its way out, and check it in io_sq_offload_create() along
with IO_SQ_THREAD_SHOULD_STOP. IO_SQ_THREAD_SHOULD_STOP regains its
original meaning, "a stop has been requested", and the WARN_ON_ONCE()
holds again.
Reproduced with an SQPOLL ring and an immediate fatal signal: the
warning fires on v7.3.0+ (22d9db9fd64a present) and is gone with this
change.
Reported-by: syzbot+675af112519ca34f5502@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=675af112519ca34f5502
Fixes: 22d9db9fd64a ("io_uring/sqpoll: don't attach to a thread that is canceling")
Signed-off-by: Shuai Liu <847807867@qq.com>
Link: https://patch.msgid.link/tencent_BB08960D79E0261B5C1EB1E589787734E907@qq.com
[axboe: trim excessive comment]
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/sqpoll.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/io_uring/sqpoll.c b/io_uring/sqpoll.c
index 6ce73c93a721a..09cd74c4d0dd2 100644
--- a/io_uring/sqpoll.c
+++ b/io_uring/sqpoll.c
@@ -26,6 +26,7 @@
enum {
IO_SQ_THREAD_SHOULD_STOP = 0,
IO_SQ_THREAD_SHOULD_PARK,
+ IO_SQ_THREAD_EXITING,
};
void io_sq_thread_unpark(struct io_sq_data *sqd)
@@ -438,9 +439,10 @@ static int io_sq_thread(void *data)
/*
* Cancelation drops sqd->lock while it waits, and a ring could attach
* to a thread that is on its way out. A fatal signal doesn't set the
- * bit, so set it here for io_sq_offload_create() to see.
+ * stop bit, so mark the thread as exiting here for
+ * io_sq_offload_create() to see.
*/
- set_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
+ set_bit(IO_SQ_THREAD_EXITING, &sqd->state);
io_uring_cancel_generic(true, sqd);
rcu_assign_pointer(sqd->thread, NULL);
put_task_struct(current);
@@ -511,7 +513,8 @@ __cold int io_sq_offload_create(struct io_ring_ctx *ctx,
/* don't attach to a dying SQPOLL thread, would be racy */
ret = 0;
if (attached && (!sqd->thread ||
- test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state)))
+ test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state) ||
+ test_bit(IO_SQ_THREAD_EXITING, &sqd->state)))
ret = -ENXIO;
io_sq_thread_unpark(sqd);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 053/670] io_uring/sqpoll: do the return-to-userspace work in the SQPOLL thread
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (51 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 052/670] io_uring/sqpoll: dont set IO_SQ_THREAD_SHOULD_STOP on thread exit Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 054/670] io_uring/cancel: count all requests that a CANCEL_ALL cancels Greg Kroah-Hartman
` (618 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Shakeel Butt, Jens Axboe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shakeel Butt <shakeel.butt@linux.dev>
Commit f013b695506491c5202a412a6568313549c81f50 upstream.
The SQPOLL thread never returns to userspace. io_sq_tw() runs its
task_work, but the rest of resume_user_mode_work(), like memory.high
reclaim and block cgroup throttling, only runs when the thread exits.
So memory.high reclaim only happens inside a charge, with sqd->lock and
ctx->uring_lock held, and not at all if the charges can't block.
This used to work. The loop called io_run_task_work(), which does this
work since commit b5d3ae202fbf ("io_uring: handle TIF_NOTIFY_RESUME
when checking for task_work"). Commit af5d68f8892f ("io_uring/sqpoll:
manage task_work privately") replaced that call with io_sq_tw().
Call resume_user_mode_work() at the top of the loop when
TIF_NOTIFY_RESUME is set, with sqd->lock dropped. It runs once per pass,
so a pass that charges two or more batches still reclaims inside the
charge, as before.
Tested in a VM with memory.high=64M and swap on zram. An SQPOLL ring
reads 256M from /dev/zero into untouched memory, 64K at a time. Before,
the thread made 337 calls to __mem_cgroup_handle_over_high(), all from
inside the charge. After, it makes 704, all from the top of the loop.
memory.peak stays at 64M. With 1M reads, 296 of its 385 calls still come
from inside the charge. Both runs take about 50% longer, and the extra
time is in the handler, which now runs more often. Without memory.high
pressure, the test never calls resume_user_mode_work() and the times
do not change. Lockdep showed no warnings, also with io_uring_register()
racing for sqd->lock.
Fixes: af5d68f8892f ("io_uring/sqpoll: manage task_work privately")
Cc: stable@vger.kernel.org
Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>
Link: https://patch.msgid.link/20261101022146.309201-1-shakeel.butt@linux.dev
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/sqpoll.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/io_uring/sqpoll.c b/io_uring/sqpoll.c
index 09cd74c4d0dd2..130da8f8f67b1 100644
--- a/io_uring/sqpoll.c
+++ b/io_uring/sqpoll.c
@@ -355,6 +355,18 @@ static int io_sq_thread(void *data)
timeout = jiffies + sqd->sq_thread_idle;
}
+ /*
+ * The SQPOLL thread never returns to userspace, so do the
+ * return-to-userspace work, like memory.high reclaim, here.
+ * It can sleep for a long time, so drop sqd->lock.
+ */
+ if (test_thread_flag(TIF_NOTIFY_RESUME)) {
+ mutex_unlock(&sqd->lock);
+ resume_user_mode_work(NULL);
+ mutex_lock(&sqd->lock);
+ sqd->sq_cpu = raw_smp_processor_id();
+ }
+
cap_entries = !list_is_singular(&sqd->ctx_list);
list_for_each_entry(ctx, &sqd->ctx_list, sqd_list) {
int ret = __io_sq_thread(ctx, sqd, cap_entries, &ist);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 054/670] io_uring/cancel: count all requests that a CANCEL_ALL cancels
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (52 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 053/670] io_uring/sqpoll: do the return-to-userspace work in the SQPOLL thread Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 055/670] io_uring/poll: cancel all matching requests in one pass Greg Kroah-Hartman
` (617 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Shang En Sim, Jens Axboe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shang En Sim <sim@shangen.org>
Commit 21ddbb14f7c3baab50a2a6c13ee375edc2bbe031 upstream.
With IORING_ASYNC_CANCEL_ALL, __io_async_cancel() counts one for each
io_try_cancel() call that cancels something. io_futex_cancel() and
io_waitid_cancel() cancel every match in one call and return how many,
so four futex waits cancelled with CANCEL_ALL give a result of 1.
Add the number that they return.
Cc: stable@vger.kernel.org
Fixes: 194bb58c6090 ("io_uring: add support for futex wake and wait")
Fixes: f31ecf671ddc ("io_uring: add IORING_OP_WAITID support")
Signed-off-by: Shang En Sim <sim@shangen.org>
Link: https://patch.msgid.link/20261030050319.1448530-2-sim@shangen.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/cancel.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/io_uring/cancel.c b/io_uring/cancel.c
index 13d5d4f2924f8..16dd8af6ac981 100644
--- a/io_uring/cancel.c
+++ b/io_uring/cancel.c
@@ -189,7 +189,8 @@ static int __io_async_cancel(struct io_cancel_data *cd,
break;
if (!all)
return ret;
- nr++;
+ /* futex and waitid return how many they cancelled */
+ nr += max(ret, 1);
} while (1);
/* slow path, try all io-wq's */
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 055/670] io_uring/poll: cancel all matching requests in one pass
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (53 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 054/670] io_uring/cancel: count all requests that a CANCEL_ALL cancels Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 056/670] io_uring/poll: dont poll a writer for a read side hangup Greg Kroah-Hartman
` (616 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Shang En Sim, Jens Axboe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shang En Sim <sim@shangen.org>
Commit 9eff9c07e927dcd9c57150cd6fb3d4ec76f00480 upstream.
With IORING_ASYNC_CANCEL_ALL, __io_async_cancel() calls io_try_cancel()
until nothing is found, and io_poll_cancel() cancels one request per
call, starting each lookup at the beginning of the hash. A cancelled
request stays hashed until its task work runs, so every lookup walks
past the ones already cancelled. Cancelling K of N pending polls visits
about K*N/2 requests in one io_uring_enter(), with uring_lock held.
A single CANCEL_FD|ALL on 80000 polls on one eventfd takes 17.06s,
0.02s with this change. With voluntary preemption the soft lockup
watchdog fires:
watchdog: BUG: soft lockup - CPU#1 stuck for 26s! [repro:100]
RIP: 0010:io_cancel_req_match+0x19/0xa0
io_poll_cancel+0x73/0x170
io_try_cancel+0x7b/0xf0
__io_async_cancel+0x41/0x110
Walk the hash once and cancel every match, as io_cancel_remove() does
for futex and waitid. Cancel by user_data only needs its own bucket.
__io_async_cancel() still loops until nothing is found, so a request
that io-wq parks in the poll hash meanwhile is still cancelled.
A cancel that matches one request now walks the whole hash twice instead
of stopping at the match.
Cc: stable@vger.kernel.org
Fixes: 8e29da69fead ("io_uring: add support for IORING_ASYNC_CANCEL_ALL")
Signed-off-by: Shang En Sim <sim@shangen.org>
Link: https://patch.msgid.link/20261030050319.1448530-3-sim@shangen.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>
[axboe: 6.12 has bucket locks and two poll hash tables, take each bucket
lock while walking it, and sum what both tables cancelled]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/cancel.c | 2 +-
io_uring/poll.c | 54 ++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 50 insertions(+), 6 deletions(-)
diff --git a/io_uring/cancel.c b/io_uring/cancel.c
index 16dd8af6ac981..727166a2ba3e9 100644
--- a/io_uring/cancel.c
+++ b/io_uring/cancel.c
@@ -189,7 +189,7 @@ static int __io_async_cancel(struct io_cancel_data *cd,
break;
if (!all)
return ret;
- /* futex and waitid return how many they cancelled */
+ /* poll, futex and waitid return how many they cancelled */
nr += max(ret, 1);
} while (1);
diff --git a/io_uring/poll.c b/io_uring/poll.c
index 31454c27072bc..39418fe05d59c 100644
--- a/io_uring/poll.c
+++ b/io_uring/poll.c
@@ -892,14 +892,52 @@ static int io_poll_disarm(struct io_kiocb *req)
return 0;
}
+/*
+ * Cancel every request matching @cd in one pass. Cancelled requests stay
+ * hashed until their task work runs, so finding them one at a time would
+ * walk past all the earlier ones on each lookup.
+ */
+static int io_poll_cancel_all(struct io_ring_ctx *ctx, struct io_cancel_data *cd,
+ struct io_hash_table *table)
+{
+ unsigned int nr_buckets = 1U << table->hash_bits;
+ unsigned int i = 0;
+ struct hlist_node *tmp;
+ struct io_kiocb *req;
+ int nr = 0;
+
+ if (!(cd->flags & (IORING_ASYNC_CANCEL_FD | IORING_ASYNC_CANCEL_OP |
+ IORING_ASYNC_CANCEL_ANY))) {
+ /* keyed by user_data, so only one bucket can match */
+ i = hash_long(cd->data, table->hash_bits);
+ nr_buckets = i + 1;
+ }
+
+ for (; i < nr_buckets; i++) {
+ struct io_hash_bucket *hb = &table->hbs[i];
+
+ spin_lock(&hb->lock);
+ hlist_for_each_entry_safe(req, tmp, &hb->list, hash_node) {
+ if (!io_cancel_req_match(req, cd))
+ continue;
+ io_poll_cancel_req(req);
+ nr++;
+ }
+ spin_unlock(&hb->lock);
+ }
+ return nr;
+}
+
static int __io_poll_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd,
struct io_hash_table *table)
{
struct io_hash_bucket *bucket;
struct io_kiocb *req;
- if (cd->flags & (IORING_ASYNC_CANCEL_FD | IORING_ASYNC_CANCEL_OP |
- IORING_ASYNC_CANCEL_ANY))
+ if (cd->flags & (IORING_ASYNC_CANCEL_ALL | IORING_ASYNC_CANCEL_ANY))
+ return io_poll_cancel_all(ctx, cd, table) ?: -ENOENT;
+
+ if (cd->flags & (IORING_ASYNC_CANCEL_FD | IORING_ASYNC_CANCEL_OP))
req = io_poll_file_find(ctx, cd, table, &bucket);
else
req = io_poll_find(ctx, false, cd, table, &bucket);
@@ -914,16 +952,22 @@ static int __io_poll_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd,
int io_poll_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd,
unsigned issue_flags)
{
- int ret;
+ bool all = cd->flags & (IORING_ASYNC_CANCEL_ALL | IORING_ASYNC_CANCEL_ANY);
+ int ret, nr;
ret = __io_poll_cancel(ctx, cd, &ctx->cancel_table);
- if (ret != -ENOENT)
+ if (ret != -ENOENT && !all)
return ret;
+ nr = max(ret, 0);
io_ring_submit_lock(ctx, issue_flags);
ret = __io_poll_cancel(ctx, cd, &ctx->cancel_table_locked);
io_ring_submit_unlock(ctx, issue_flags);
- return ret;
+ if (!all)
+ return ret;
+ /* with ALL or ANY, both tables return how many they cancelled */
+ nr += max(ret, 0);
+ return nr ?: -ENOENT;
}
static __poll_t io_poll_parse_events(const struct io_uring_sqe *sqe,
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 056/670] io_uring/poll: dont poll a writer for a read side hangup
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (54 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 055/670] io_uring/poll: cancel all matching requests in one pass Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 057/670] io_uring/poll: dont poll a writer for urgent data Greg Kroah-Hartman
` (615 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lukáš Lalinský,
Jens Axboe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <axboe@kernel.dk>
Commit 74c1f1048e4401d6a953ab2299b14ace1ad6a899 upstream.
io_init_poll_iocb() adds EPOLLRDHUP to every poll, including the async
poll of a send that waits for buffer space. Once the peer has shut down
its sending side, the socket keeps reporting EPOLLRDHUP, so each re-arm
in __io_arm_poll_handler() finds a ready mask and the request is issued
again. The send still can't make progress, the request burns through
APOLL_MAX_RETRY in a few milliseconds and ends up in io-wq.
A send in io-wq blocks until the peer reads, but sendmsg and writev go
through ____sys_sendmsg() and sock_write_iter(), which turn O_NONBLOCK
into MSG_DONTWAIT, and the application gets -EAGAIN for a request that
never asked for a non-blocking send.
Only add EPOLLRDHUP for polls that want to read. A peer that stopped
sending is no event for a writer, and a poll that asks for it explicitly
still gets it.
Fixes: 464dca612bc6 ("io_uring: mask in error/nval/hangup consistently for poll")
Reported-by: Lukáš Lalinský <lukas@lalinsky.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/poll.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/io_uring/poll.c b/io_uring/poll.c
index 39418fe05d59c..7884ea7b23c5a 100644
--- a/io_uring/poll.c
+++ b/io_uring/poll.c
@@ -169,12 +169,24 @@ static void io_poll_tw_hash_eject(struct io_kiocb *req, struct io_tw_state *ts)
}
}
+#define IO_POLL_UNMASK (EPOLLERR|EPOLLHUP|EPOLLNVAL)
+
+static __poll_t io_poll_unmask(__poll_t events)
+{
+ /*
+ * A peer that stopped sending is an event for a reader, but a write
+ * only poll must stay armed until the file is writable again.
+ */
+ if (events & (EPOLLIN | EPOLLRDNORM | EPOLLRDBAND))
+ return IO_POLL_UNMASK | EPOLLRDHUP;
+ return IO_POLL_UNMASK;
+}
+
static void io_init_poll_iocb(struct io_poll *poll, __poll_t events)
{
poll->head = NULL;
-#define IO_POLL_UNMASK (EPOLLERR|EPOLLHUP|EPOLLNVAL|EPOLLRDHUP)
/* mask in events that we always want/need */
- poll->events = events | IO_POLL_UNMASK;
+ poll->events = events | io_poll_unmask(events);
INIT_LIST_HEAD(&poll->wait.entry);
init_waitqueue_func_entry(&poll->wait, io_poll_wake);
}
@@ -1112,7 +1124,7 @@ int io_poll_remove(struct io_kiocb *req, unsigned int issue_flags)
poll->events &= ~0xffff;
poll->events |= poll_update->events & 0xffff;
- poll->events |= IO_POLL_UNMASK;
+ poll->events |= io_poll_unmask(poll->events);
}
if (poll_update->update_user_data)
preq->cqe.user_data = poll_update->new_user_data;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 057/670] io_uring/poll: dont poll a writer for urgent data
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (55 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 056/670] io_uring/poll: dont poll a writer for a read side hangup Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 058/670] io_uring/rsrc: hold uring_lock across index-alloc put_user Greg Kroah-Hartman
` (614 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lukáš Lalinský,
Jens Axboe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <axboe@kernel.dk>
Commit edeac4546a71b6c1db4ba006a2dbf7c863f54e9a upstream.
io_arm_poll_handler() starts the mask of every async poll with EPOLLPRI,
for a reader and a writer alike. A TCP socket reports EPOLLPRI for as
long as urgent data sits unread, so once the peer has sent a byte with
MSG_OOB, the async poll of a send that waits for buffer space is ready
on every re-arm. The request spins through task_work and
__io_arm_poll_handler() until APOLL_MAX_RETRY is used up and io-wq takes
it, the same spin that EPOLLRDHUP caused for a half-closed peer.
While it spins, the request is neither in the poll hash nor in io-wq. A
cancel issued right after the send gets -ENOENT and the send stays
pending, until a later cancel finds it in io-wq.
Only add EPOLLPRI for polls that want to read. Urgent data is an event
for a recv, not for a writer.
Fixes: d7718a9d25a6 ("io_uring: use poll driven retry for files that support it")
Reported-by: Lukáš Lalinský <lukas@lalinsky.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
[axboe: 6.12 sets up the mask in io_arm_poll_handler() itself, with
EPOLLET]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/poll.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/io_uring/poll.c b/io_uring/poll.c
index 7884ea7b23c5a..c1a9f697a0231 100644
--- a/io_uring/poll.c
+++ b/io_uring/poll.c
@@ -757,7 +757,7 @@ int io_arm_poll_handler(struct io_kiocb *req, unsigned issue_flags)
const struct io_issue_def *def = &io_issue_defs[req->opcode];
struct async_poll *apoll;
struct io_poll_table ipt;
- __poll_t mask = POLLPRI | POLLERR | EPOLLET;
+ __poll_t mask = POLLERR | EPOLLET;
int ret;
/*
@@ -774,7 +774,8 @@ int io_arm_poll_handler(struct io_kiocb *req, unsigned issue_flags)
mask |= EPOLLONESHOT;
if (def->pollin) {
- mask |= EPOLLIN | EPOLLRDNORM;
+ /* urgent data is an event for a reader only */
+ mask |= EPOLLIN | EPOLLRDNORM | EPOLLPRI;
/* If reading from MSG_ERRQUEUE using recvmsg, ignore POLLIN */
if (req->flags & REQ_F_CLEAR_POLLIN)
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 058/670] io_uring/rsrc: hold uring_lock across index-alloc put_user
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (56 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 057/670] io_uring/poll: dont poll a writer for urgent data Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 059/670] fsverity: Explicitly require FMODE_READ to retrieve hashes Greg Kroah-Hartman
` (613 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Yuansheng Yang, Jens Axboe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuansheng Yang <0xbeac@gmail.com>
Commit d7c7037253f6935af243570635d71b4920b5a4ea upstream.
io_files_update_with_index_alloc() installs a fixed file via
io_fixed_fd_install(), which drops ->uring_lock when the request runs on
io-wq, then put_user()s the allocated slot back to userspace. If that
faults, the error path calls __io_close_fixed() by slot index after
re-taking the lock.
The slot can be closed and reused between the install and that cleanup:
another fixed CLOSE plus open/accept/pipe/socket, or a FILES_UPDATE, can
put an unrelated file into the same slot. The error path then removes
that file instead of the one this request installed, ending an unrelated
file's fixed-table reference early. This is a correctness/DoS issue, not
a use-after-free: fixed-file requests hold an io_rsrc_node reference, so
the node and file stay alive until they are done.
Hold ->uring_lock across __io_fixed_fd_install() and put_user(), and do
the failure cleanup with io_fixed_fd_remove() under the same lock. This
is the same class as the io_pipe_fixed() fix in a3d7ee11289f. Faulting
while holding ->uring_lock is fine, the registration paths already do
it.
Fixes: a7c41b4687f5 ("io_uring: let IORING_OP_FILES_UPDATE support choosing fixed file slots")
Signed-off-by: Yuansheng Yang <0xbeac@gmail.com>
Link: https://patch.msgid.link/20261104154655.81876-1-0xbeac@gmail.com
[axboe: various touch-ups]
Signed-off-by: Jens Axboe <axboe@kernel.dk>
[axboe: 6.12 uses copy_to_user() for the slot rather than put_user(),
and ->file_data for the table check]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/rsrc.c | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c
index ad7ad35545d6c..168c6987435ed 100644
--- a/io_uring/rsrc.c
+++ b/io_uring/rsrc.c
@@ -562,11 +562,12 @@ static int io_files_update_with_index_alloc(struct io_kiocb *req,
{
struct io_rsrc_update *up = io_kiocb_to_cmd(req, struct io_rsrc_update);
__s32 __user *fds = u64_to_user_ptr(up->arg);
+ struct io_ring_ctx *ctx = req->ctx;
unsigned int done;
struct file *file;
int ret, fd;
- if (!req->ctx->file_data)
+ if (!ctx->file_data)
return -ENXIO;
for (done = 0; done < up->nr_args; done++) {
@@ -580,15 +581,25 @@ static int io_files_update_with_index_alloc(struct io_kiocb *req,
ret = -EBADF;
break;
}
- ret = io_fixed_fd_install(req, issue_flags, file,
- IORING_FILE_INDEX_ALLOC);
- if (ret < 0)
+ /*
+ * Hold the lock across the copy_to_user(), if it's dropped the
+ * slot can be closed and reused before the error path runs.
+ */
+ io_ring_submit_lock(ctx, issue_flags);
+ ret = __io_fixed_fd_install(ctx, file,
+ IORING_FILE_INDEX_ALLOC);
+ if (ret < 0) {
+ io_ring_submit_unlock(ctx, issue_flags);
+ fput(file);
break;
+ }
if (copy_to_user(&fds[done], &ret, sizeof(ret))) {
- __io_close_fixed(req->ctx, issue_flags, ret);
+ io_fixed_fd_remove(ctx, ret);
+ io_ring_submit_unlock(ctx, issue_flags);
ret = -EFAULT;
break;
}
+ io_ring_submit_unlock(ctx, issue_flags);
}
if (done)
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 059/670] fsverity: Explicitly require FMODE_READ to retrieve hashes
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (57 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 058/670] io_uring/rsrc: hold uring_lock across index-alloc put_user Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 060/670] xor: add missing vzeroupper to AVX code Greg Kroah-Hartman
` (612 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Andrey Albershteyn, Eric Biggers,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <ebiggers@kernel.org>
commit 1acb4fd2d011c4bd6cc961095ae17361c71ff61a upstream.
The comment in fsverity_ioctl_read_metadata(), which justifies not
checking for FMODE_READ, doesn't consider that the nonstandard access
mode 3 (ioctl-only) exists.
Opening an ioctl-only fd generally requires read (and write) permission.
However, there are gaps with certain LSMs: an ioctl-only fd requests
read (and write) permission via security_inode_permission, but not
security_file_open. With certain LSMs relying on the latter, such as
Landlock and AppArmor, an ioctl-only fd can be opened without the LSM
granting read (and write) permission.
Since FS_IOC_READ_VERITY_METADATA returns hashes of file contents
blocks, it should require read permission. This also applies to
FS_IOC_MEASURE_VERITY, which returns a hash for the whole file.
Meanwhile, ioctl-only fds are a rarely-used feature, not known to be
used with either ioctl.
Therefore, just disallow these ioctls on ioctl-only file descriptors,
similar to what was already done with FS_IOC_ENABLE_VERITY.
More specifically, explicitly check for FMODE_READ. This also covers
write-only fds to non-verity files which otherwise would have failed
with ENODATA. This change in error code for write-only fds should be
fine too, as these ioctls cannot be usefully used with write-only fds
anyway, but it's worth noting as another technicality.
Fixes: 4dd893d832cf ("fs-verity: implement FS_IOC_MEASURE_VERITY ioctl")
Fixes: e17fe6579de0 ("fs-verity: add FS_IOC_READ_VERITY_METADATA ioctl")
Cc: stable@vger.kernel.org
Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>
Link: https://patch.msgid.link/20261022211522.1489943-1-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
Documentation/filesystems/fsverity.rst | 3 +++
fs/verity/measure.c | 10 ++++++++++
fs/verity/read_metadata.c | 14 ++++++++++----
3 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/Documentation/filesystems/fsverity.rst b/Documentation/filesystems/fsverity.rst
index 0e2fac7a16da1..f879e052d4ecc 100644
--- a/Documentation/filesystems/fsverity.rst
+++ b/Documentation/filesystems/fsverity.rst
@@ -170,6 +170,7 @@ fatal signal), no changes are made to the file.
FS_IOC_ENABLE_VERITY can fail with the following errors:
- ``EACCES``: the process does not have write access to the file
+- ``EBADF``: the file descriptor is not open for reading
- ``EBADMSG``: the builtin signature is malformed
- ``EBUSY``: this ioctl is already running on the file
- ``EEXIST``: the file already has verity enabled
@@ -233,6 +234,7 @@ regardless of the size of the file.
FS_IOC_MEASURE_VERITY can fail with the following errors:
+- ``EBADF``: the file descriptor is not open for reading
- ``EFAULT``: the caller provided inaccessible memory
- ``ENODATA``: the file is not a verity file
- ``ENOTTY``: this type of filesystem does not implement fs-verity
@@ -305,6 +307,7 @@ blocks from disk without actually verifying the path to the root node.
FS_IOC_READ_VERITY_METADATA can fail with the following errors:
+- ``EBADF``: the file descriptor is not open for reading
- ``EFAULT``: the caller provided inaccessible memory
- ``EINTR``: the ioctl was interrupted before any data was read
- ``EINVAL``: reserved fields were set, or ``offset + length``
diff --git a/fs/verity/measure.c b/fs/verity/measure.c
index 91ce39ced77b8..b5af400c725e8 100644
--- a/fs/verity/measure.c
+++ b/fs/verity/measure.c
@@ -30,6 +30,16 @@ int fsverity_ioctl_measure(struct file *filp, void __user *_uarg)
const struct fsverity_hash_alg *hash_alg;
struct fsverity_digest arg;
+ /*
+ * This ioctl returns a hash of the file contents, so it should require
+ * read permission. Disallow it on ioctl-only (i.e., nonstandard access
+ * mode 3) fds, which can in some cases be acquired without passing all
+ * LSM read-permission checks. Also disallow write-only fds, which can
+ * refer only to non-verity files which would fail with ENODATA anyway.
+ */
+ if (!(filp->f_mode & FMODE_READ))
+ return -EBADF;
+
vi = fsverity_get_info(inode);
if (!vi)
return -ENODATA; /* not a verity file */
diff --git a/fs/verity/read_metadata.c b/fs/verity/read_metadata.c
index f58432772d9ea..680792701ba29 100644
--- a/fs/verity/read_metadata.c
+++ b/fs/verity/read_metadata.c
@@ -156,13 +156,19 @@ int fsverity_ioctl_read_metadata(struct file *filp, const void __user *uarg)
int length;
void __user *buf;
+ /*
+ * This ioctl returns file contents block hashes, so it should require
+ * read permission. Disallow it on ioctl-only (i.e., nonstandard access
+ * mode 3) fds, which can in some cases be acquired without passing all
+ * LSM read-permission checks. Also disallow write-only fds, which can
+ * refer only to non-verity files which would fail with ENODATA anyway.
+ */
+ if (!(filp->f_mode & FMODE_READ))
+ return -EBADF;
+
vi = fsverity_get_info(inode);
if (!vi)
return -ENODATA; /* not a verity file */
- /*
- * Note that we don't have to explicitly check that the file is open for
- * reading, since verity files can only be opened for reading.
- */
if (copy_from_user(&arg, uarg, sizeof(arg)))
return -EFAULT;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 060/670] xor: add missing vzeroupper to AVX code
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (58 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 059/670] fsverity: Explicitly require FMODE_READ to retrieve hashes Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 061/670] raid6: add missing vzeroupper to AVX-512 code Greg Kroah-Hartman
` (611 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Biggers, Andrew Morton,
Christoph Hellwig, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <ebiggers@kernel.org>
commit 7b8fc26c40d6cf4c6751a045c9e42bbb7e78d81b upstream.
Since the AVX optimized XOR code uses YMM registers, execute vzeroupper
before returning from it. This is needed to avoid degrading the
performance of any later SSE code that may happen to be executed.
(Backported to the old organization of the XOR code.)
Link: https://lore.kernel.org/20260831212248.213805-1-ebiggers@kernel.org
Fixes: ea4d26ae24e5 ("raid5: add AVX optimized RAID5 checksumming")
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: <stable@vger.kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/include/asm/xor_avx.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/x86/include/asm/xor_avx.h b/arch/x86/include/asm/xor_avx.h
index 7f81dd5897f41..c6450acd055d1 100644
--- a/arch/x86/include/asm/xor_avx.h
+++ b/arch/x86/include/asm/xor_avx.h
@@ -50,6 +50,7 @@ do { \
p1 = (unsigned long *)((uintptr_t)p1 + 512);
}
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -81,6 +82,7 @@ do { \
p2 = (unsigned long *)((uintptr_t)p2 + 512);
}
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -116,6 +118,7 @@ do { \
p3 = (unsigned long *)((uintptr_t)p3 + 512);
}
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -155,6 +158,7 @@ do { \
p4 = (unsigned long *)((uintptr_t)p4 + 512);
}
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 061/670] raid6: add missing vzeroupper to AVX-512 code
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (59 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 060/670] xor: add missing vzeroupper to AVX code Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 062/670] wifi: rtw88: TX report with long timeout for non-PCIE devices Greg Kroah-Hartman
` (610 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Biggers, Andrew Morton,
Christoph Hellwig, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <ebiggers@kernel.org>
commit b82cf9e49c1be7cf1fd8e1bd806b0cdd25ab8127 upstream.
Since the AVX-512 optimized RAID6 code uses ZMM registers, execute
vzeroupper before returning from it. This is needed to avoid degrading
the performance of any later SSE code that may happen to be executed.
Link: https://lore.kernel.org/20260831212316.213896-1-ebiggers@kernel.org
Fixes: e0a491c12968 ("lib/raid6: Add AVX512 optimized gen_syndrome functions")
Fixes: 13c520b2993c ("lib/raid6: Add AVX512 optimized recovery functions")
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: <stable@vger.kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
lib/raid6/avx512.c | 6 ++++++
lib/raid6/recov_avx512.c | 2 ++
2 files changed, 8 insertions(+)
diff --git a/lib/raid6/avx512.c b/lib/raid6/avx512.c
index 9c3e822e1adf5..30956989e7d74 100644
--- a/lib/raid6/avx512.c
+++ b/lib/raid6/avx512.c
@@ -95,6 +95,7 @@ static void raid6_avx5121_gen_syndrome(int disks, size_t bytes, void **ptrs)
}
asm volatile("sfence" : : : "memory");
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -154,6 +155,7 @@ static void raid6_avx5121_xor_syndrome(int disks, int start, int stop,
}
asm volatile("sfence" : : : "memory");
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -227,6 +229,7 @@ static void raid6_avx5122_gen_syndrome(int disks, size_t bytes, void **ptrs)
}
asm volatile("sfence" : : : "memory");
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -311,6 +314,7 @@ static void raid6_avx5122_xor_syndrome(int disks, int start, int stop,
}
asm volatile("sfence" : : : "memory");
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -417,6 +421,7 @@ static void raid6_avx5124_gen_syndrome(int disks, size_t bytes, void **ptrs)
}
asm volatile("sfence" : : : "memory");
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -550,6 +555,7 @@ static void raid6_avx5124_xor_syndrome(int disks, int start, int stop,
"m" (q[d+128]), "m" (q[d+192]));
}
asm volatile("sfence" : : : "memory");
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
const struct raid6_calls raid6_avx512x4 = {
diff --git a/lib/raid6/recov_avx512.c b/lib/raid6/recov_avx512.c
index fd9e15bf3f30f..c8a152d9ab6da 100644
--- a/lib/raid6/recov_avx512.c
+++ b/lib/raid6/recov_avx512.c
@@ -221,6 +221,7 @@ static void raid6_2data_recov_avx512(int disks, size_t bytes, int faila,
#endif
}
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -363,6 +364,7 @@ static void raid6_datap_recov_avx512(int disks, size_t bytes, int faila,
#endif
}
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 062/670] wifi: rtw88: TX report with long timeout for non-PCIE devices
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (60 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 061/670] raid6: add missing vzeroupper to AVX-512 code Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 063/670] ACPI: CPPC: Validate FFH register fields before hardware access Greg Kroah-Hartman
` (609 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ping-Ke Shih, Luka Gejak,
Josef Schlehofer, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ping-Ke Shih <pkshih@realtek.com>
[ Upstream commit 7cde94dab0e74434ccc0a387d7ad373fb3becda0 ]
Many USB and SDIO devices can't report TX status within 500 ms, and
extending to 2500 ms as tested USB/SDIO devices can fix the problem [1].
To avoid adding chip ID one by one, and this change looks harmless.
Keep PCIE using short timeout, and others use long timeout.
[1] https://lore.kernel.org/linux-wireless/20260921165343.8131-1-pepe.schlehofer@gmail.com/
Cc: stable@vger.kernel.org
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Reviewed-by: Luka Gejak <luka.gejak@linux.dev>
Tested-by: Josef Schlehofer <pepe.schlehofer@gmail.com>
Link: https://patch.msgid.link/20260924004637.9958-1-pkshih@realtek.com
[ Adjust the removed condition. This tree has no RTL8723BS support and
lacks commit 4d688f22ebbf ("wifi: rtw88: tx: extend the TX report purge
timeout to RTL8723BS"), so the old check has no rtw_is_8723bs() part.
The resulting code is the same as upstream. ]
Signed-off-by: Josef Schlehofer <pepe.schlehofer@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/realtek/rtw88/tx.c | 9 +++++----
drivers/net/wireless/realtek/rtw88/tx.h | 3 ++-
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c
index 0c8817bf46c74..959ae66776aa4 100644
--- a/drivers/net/wireless/realtek/rtw88/tx.c
+++ b/drivers/net/wireless/realtek/rtw88/tx.c
@@ -191,7 +191,7 @@ void rtw_tx_report_purge_timer(struct timer_list *t)
void rtw_tx_report_enqueue(struct rtw_dev *rtwdev, struct sk_buff *skb, u8 sn)
{
struct rtw_tx_report *tx_report = &rtwdev->tx_report;
- unsigned long timeout = RTW_TX_PROBE_TIMEOUT;
+ unsigned long timeout;
unsigned long flags;
u8 *drv_data;
@@ -203,9 +203,10 @@ void rtw_tx_report_enqueue(struct rtw_dev *rtwdev, struct sk_buff *skb, u8 sn)
__skb_queue_tail(&tx_report->queue, skb);
spin_unlock_irqrestore(&tx_report->q_lock, flags);
- if (rtwdev->chip->id == RTW_CHIP_TYPE_8723D &&
- rtwdev->hci.type == RTW_HCI_TYPE_USB)
- timeout = msecs_to_jiffies(2500);
+ if (rtwdev->hci.type == RTW_HCI_TYPE_PCIE)
+ timeout = RTW_TX_PROBE_TIMEOUT_SHORT;
+ else
+ timeout = RTW_TX_PROBE_TIMEOUT_LONG;
mod_timer(&tx_report->purge_timer, jiffies + timeout);
}
diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h
index 3d544fd7f60f5..f361713ece9f0 100644
--- a/drivers/net/wireless/realtek/rtw88/tx.h
+++ b/drivers/net/wireless/realtek/rtw88/tx.h
@@ -7,7 +7,8 @@
#define RTK_TX_MAX_AGG_NUM_MASK 0x1f
-#define RTW_TX_PROBE_TIMEOUT msecs_to_jiffies(500)
+#define RTW_TX_PROBE_TIMEOUT_SHORT msecs_to_jiffies(500)
+#define RTW_TX_PROBE_TIMEOUT_LONG msecs_to_jiffies(2500)
struct rtw_tx_desc {
__le32 w0;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 063/670] ACPI: CPPC: Validate FFH register fields before hardware access
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (61 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 062/670] wifi: rtw88: TX report with long timeout for non-PCIE devices Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 064/670] ACPI: CPPC: Propagate errors from cross-CPU FFH calls Greg Kroah-Hartman
` (608 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Loehle, Sumit Gupta,
Rafael J. Wysocki, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Loehle <christian.loehle@arm.com>
commit 6b016c5c96448c0a5f09328d37f66562d154a5e5 upstream.
The x86 CPPC FFH accessors construct masks and shift values using the
firmware's Bit Width and Bit Offset without checking that the field fits
in an MSR. A zero-width field or a field extending beyond bit 63 can
therefore cause an invalid shift. The safe MSR accessors only handle an
access fault, not invalid field arithmetic after a successful read.
Also, the 64-bit GAS address is implicitly narrowed to the 32-bit MSR
number. A descriptor with nonzero upper address bits can access a different
MSR from the one described by firmware.
The arm64 AMU counter readers have the same unchecked field arithmetic.
Validate the field bounds before reading a counter, including both
descriptors in the paired counter path.
Dispatch FFH accesses before decoding the GAS Access Size in the common
read and write paths. Otherwise, a large access_width can trigger an
invalid shift in GET_BIT_WIDTH() before the architecture validates its
register. That field has architecture-specific FFH semantics and is not
needed by the generic memory/port accessor on this path.
Validate x86 MSR addresses and share the field-bounds checks between
related accessors within each architecture.
Fixes: a6cbcdd5ab5f ("ACPI / CPPC: Add support for functional fixed hardware address")
Fixes: 68c5debcc06d ("arm64: implement CPPC FFH support using AMUs")
Fixes: f489c948028b ("ACPI: CPPC: Fix access width used for PCC registers")
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Christian Loehle <christian.loehle@arm.com>
Tested-by: Sumit Gupta <sumitg@nvidia.com>
Link: https://patch.msgid.link/20260916162805.1039247-17-christian.loehle@arm.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Christian Loehle <christian.loehle@arm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/arm64/kernel/topology.c | 9 +++++++++
arch/x86/kernel/acpi/cppc.c | 15 +++++++++++++++
drivers/acpi/cppc_acpi.c | 10 ++++++----
3 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 052e9b9945fea..721df857d7376 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -318,10 +318,19 @@ bool cpc_ffh_supported(void)
return true;
}
+static bool cpc_ffh_reg_valid(const struct cpc_reg *reg)
+{
+ return reg->bit_width && reg->bit_width <= 64 &&
+ reg->bit_offset <= 64 - reg->bit_width;
+}
+
int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
{
int ret = -EOPNOTSUPP;
+ if (!cpc_ffh_reg_valid(reg))
+ return -EINVAL;
+
switch ((u64)reg->address) {
case 0x0:
ret = counters_read_on_cpu(cpu, cpu_read_corecnt, val);
diff --git a/arch/x86/kernel/acpi/cppc.c b/arch/x86/kernel/acpi/cppc.c
index 12fc5f5534052..d9cfed143b797 100644
--- a/arch/x86/kernel/acpi/cppc.c
+++ b/arch/x86/kernel/acpi/cppc.c
@@ -4,6 +4,8 @@
* Copyright (c) 2016, Intel Corporation.
*/
+#include <linux/limits.h>
+
#include <acpi/cppc_acpi.h>
#include <asm/msr.h>
#include <asm/processor.h>
@@ -43,10 +45,20 @@ bool cpc_ffh_supported(void)
return true;
}
+static bool cpc_ffh_reg_valid(const struct cpc_reg *reg)
+{
+ return reg->address <= U32_MAX && reg->bit_width &&
+ reg->bit_width <= 64 &&
+ reg->bit_offset <= 64 - reg->bit_width;
+}
+
int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val)
{
int err;
+ if (!cpc_ffh_reg_valid(reg))
+ return -EINVAL;
+
err = rdmsrl_safe_on_cpu(cpunum, reg->address, val);
if (!err) {
u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1,
@@ -63,6 +75,9 @@ int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
u64 rd_val;
int err;
+ if (!cpc_ffh_reg_valid(reg))
+ return -EINVAL;
+
err = rdmsrl_safe_on_cpu(cpunum, reg->address, &rd_val);
if (!err) {
u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1,
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 8ad6d12b77727..241083e6d9174 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1028,6 +1028,9 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
}
*val = 0;
+ if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE)
+ return cpc_read_ffh(cpu, reg, val);
+
size = GET_BIT_WIDTH(reg);
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
@@ -1054,8 +1057,6 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
}
else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
vaddr = reg_res->sys_mem_vaddr;
- else if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE)
- return cpc_read_ffh(cpu, reg, val);
else
return acpi_os_read_memory((acpi_physical_address)reg->address,
val, size);
@@ -1101,6 +1102,9 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
struct cpc_desc *cpc_desc;
unsigned long flags;
+ if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE)
+ return cpc_write_ffh(cpu, reg, val);
+
size = GET_BIT_WIDTH(reg);
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
@@ -1125,8 +1129,6 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
}
else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
vaddr = reg_res->sys_mem_vaddr;
- else if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE)
- return cpc_write_ffh(cpu, reg, val);
else
return acpi_os_write_memory((acpi_physical_address)reg->address,
val, size);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 064/670] ACPI: CPPC: Propagate errors from cross-CPU FFH calls
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (62 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 063/670] ACPI: CPPC: Validate FFH register fields before hardware access Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 065/670] ACPI: CPPC: Accept requests to retain immutable autonomous selection Greg Kroah-Hartman
` (607 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Loehle, Sumit Gupta,
Rafael J. Wysocki, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Loehle <christian.loehle@arm.com>
commit 36e96b469da24868f727b4cd168d7cf01cbd163d upstream.
The arm64 and RISC-V CPPC FFH accessors ignore the return value of
smp_call_function_single(). If the target CPU is offline, the call can
return -ENXIO without running the callback. The accessors then consume
callback output which was never initialized and may report success.
CPU offlining leaves the CPU's CPPC sysfs attributes present. On arm64,
the AMU feature mask does not exclude an offline CPU, so a paired counter
read can expose uninitialized stack values through feedback_ctrs. RISC-V
has the same problem in both SBI and CSR reads, and its write paths also
inspect an uninitialized callback status after a failed cross-CPU call.
Return the SMP call error before using callback output. The arm64 single
and paired counter readers already check the helper's return value. For
RISC-V, also check the callback status before copying a read value: an
unsupported CSR sets the error but does not initialize the value.
Fixes: 68c5debcc06d ("arm64: implement CPPC FFH support using AMUs")
Fixes: 30f3ffbee86b ("ACPI: RISC-V: Add CPPC driver")
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Christian Loehle <christian.loehle@arm.com>
Tested-by: Sumit Gupta <sumitg@nvidia.com>
Link: https://patch.msgid.link/20260916162805.1039247-18-christian.loehle@arm.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Christian Loehle <christian.loehle@arm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/arm64/kernel/topology.c | 4 +---
drivers/acpi/riscv/cppc.c | 26 ++++++++++++++++++++------
2 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 721df857d7376..326cf60d8d584 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -289,9 +289,7 @@ int counters_read_on_cpu(int cpu, smp_call_func_t func, u64 *val)
if (WARN_ON_ONCE(irqs_disabled()))
return -EPERM;
- smp_call_function_single(cpu, func, val, 1);
-
- return 0;
+ return smp_call_function_single(cpu, func, val, 1);
}
/*
diff --git a/drivers/acpi/riscv/cppc.c b/drivers/acpi/riscv/cppc.c
index 10a2b554b3ccf..ef3b052f9dad6 100644
--- a/drivers/acpi/riscv/cppc.c
+++ b/drivers/acpi/riscv/cppc.c
@@ -99,6 +99,7 @@ bool cpc_ffh_supported(void)
int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
{
struct sbi_cppc_data data;
+ int ret;
if (WARN_ON_ONCE(irqs_disabled()))
return -EPERM;
@@ -109,19 +110,27 @@ int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
data.reg = FFH_CPPC_SBI_REG(reg->address);
- smp_call_function_single(cpu, sbi_cppc_read, &data, 1);
+ ret = smp_call_function_single(cpu, sbi_cppc_read, &data, 1);
+ if (ret)
+ return ret;
+ if (data.ret.error)
+ return sbi_err_map_linux_errno(data.ret.error);
*val = data.ret.value;
- return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
+ return 0;
} else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) {
data.reg = FFH_CPPC_CSR_NUM(reg->address);
- smp_call_function_single(cpu, cppc_ffh_csr_read, &data, 1);
+ ret = smp_call_function_single(cpu, cppc_ffh_csr_read, &data, 1);
+ if (ret)
+ return ret;
+ if (data.ret.error)
+ return data.ret.error;
*val = data.ret.value;
- return data.ret.error;
+ return 0;
}
return -EINVAL;
@@ -130,6 +139,7 @@ int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
int cpc_write_ffh(int cpu, struct cpc_reg *reg, u64 val)
{
struct sbi_cppc_data data;
+ int ret;
if (WARN_ON_ONCE(irqs_disabled()))
return -EPERM;
@@ -141,14 +151,18 @@ int cpc_write_ffh(int cpu, struct cpc_reg *reg, u64 val)
data.reg = FFH_CPPC_SBI_REG(reg->address);
data.val = val;
- smp_call_function_single(cpu, sbi_cppc_write, &data, 1);
+ ret = smp_call_function_single(cpu, sbi_cppc_write, &data, 1);
+ if (ret)
+ return ret;
return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
} else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) {
data.reg = FFH_CPPC_CSR_NUM(reg->address);
data.val = val;
- smp_call_function_single(cpu, cppc_ffh_csr_write, &data, 1);
+ ret = smp_call_function_single(cpu, cppc_ffh_csr_write, &data, 1);
+ if (ret)
+ return ret;
return data.ret.error;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 065/670] ACPI: CPPC: Accept requests to retain immutable autonomous selection
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (63 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 064/670] ACPI: CPPC: Propagate errors from cross-CPU FFH calls Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 066/670] writeback: keep cleanup_offline_cgwb()s scan out of syncs Greg Kroah-Hartman
` (606 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Loehle, Sumit Gupta,
Rafael J. Wysocki, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Loehle <christian.loehle@arm.com>
commit 4bcc60d326c5acaa28c5913259decb22a33a83a1 upstream.
ACPI permits Autonomous Selection Enable to be Integer 1 when the platform
always selects performance autonomously. cppc_get_auto_sel() returns that
value, but cppc_set_auto_sel() rejects the Integer even when asked to keep
autonomous selection enabled. AMD shared-memory initialization consequently
fails in active or guided mode after successfully reading the capability.
Accept a request to keep this immutable field enabled without issuing a
register access. Expose the immutable encoding to callers, separately from
the current value of a writable register.
Before an AMD shared-memory transition to passive mode, reject immutable
autonomous selection on any present CPU. Otherwise a guided-to-passive
transition ignores the failed disable and reports the wrong mode, while
active-to-passive unregisters the working driver before passive policy
initialization fails. Check under the driver mode lock before invoking
either transition, including known offline CPUs.
Serialize this capability query with descriptor publication and removal.
ACPI processor removal drops the descriptor before taking the CPU hotplug
write lock, so the caller's cpus_read_lock() alone cannot protect the
lookup. Unpublish under the same mutex before releasing a descriptor,
including when adding its kobject fails.
The cppc-cpufreq auto_select attribute can also request one while
autonomous selection is already enabled. If the subsequent bounds update
fails, its rollback requests zero and clears the cached mode regardless
of the previous state. For an immutable field the disable request fails,
leaving the cached mode wrong. Save and restore the previous mode instead.
This also avoids disabling an already-enabled writable control on that
error path.
Fixes: c984f5d5d45b ("ACPI: CPPC: Add auto select register read/write support")
Fixes: ea3db45ae476 ("cpufreq: cppc: Update MIN_PERF/MAX_PERF in target callbacks")
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Christian Loehle <christian.loehle@arm.com>
Tested-by: Sumit Gupta <sumitg@nvidia.com>
Link: https://patch.msgid.link/20260916162805.1039247-19-christian.loehle@arm.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Christian Loehle <christian.loehle@arm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/acpi/cppc_acpi.c | 48 ++++++++++++++++++++++++++++++++++--
drivers/cpufreq/amd-pstate.c | 23 ++++++++++++++---
include/acpi/cppc_acpi.h | 6 +++++
3 files changed, 71 insertions(+), 6 deletions(-)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 241083e6d9174..95ab801679e83 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -36,6 +36,7 @@
#include <linux/delay.h>
#include <linux/iopoll.h>
#include <linux/ktime.h>
+#include <linux/mutex.h>
#include <linux/rwsem.h>
#include <linux/wait.h>
#include <linux/topology.h>
@@ -94,6 +95,16 @@ static DEFINE_PER_CPU(int, cpu_pcc_subspace_idx);
*/
static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);
+/* Protect immutable capability queries against descriptor removal. */
+static DEFINE_MUTEX(cpc_desc_lock);
+
+static void cpc_set_desc(unsigned int cpu, struct cpc_desc *desc)
+{
+ mutex_lock(&cpc_desc_lock);
+ per_cpu(cpc_desc_ptr, cpu) = desc;
+ mutex_unlock(&cpc_desc_lock);
+}
+
/* pcc mapped address + header size + offset within PCC subspace */
#define GET_PCC_VADDR(offs, pcc_ss_id) (pcc_data[pcc_ss_id]->pcc_comm_addr + \
0x8 + (offs))
@@ -910,12 +921,12 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
}
/* Plug PSD data into this CPU's CPC descriptor. */
- per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr;
+ cpc_set_desc(pr->id, cpc_ptr);
ret = kobject_init_and_add(&cpc_ptr->kobj, &cppc_ktype, &cpu_dev->kobj,
"acpi_cppc");
if (ret) {
- per_cpu(cpc_desc_ptr, pr->id) = NULL;
+ cpc_set_desc(pr->id, NULL);
kobject_put(&cpc_ptr->kobj);
goto out_free;
}
@@ -967,6 +978,8 @@ void acpi_cppc_processor_exit(struct acpi_processor *pr)
if (!cpc_ptr)
return;
+ cpc_set_desc(pr->id, NULL);
+
/* Free all the mapped sys mem areas for this CPU */
for (i = 2; i < cpc_ptr->num_entries; i++) {
addr = cpc_ptr->cpc_regs[i-2].sys_mem_vaddr;
@@ -1278,6 +1291,11 @@ static int cppc_set_reg_val(int cpu, enum cppc_regs reg_idx, u64 val)
reg = &cpc_desc->cpc_regs[reg_idx];
+ /* Integer 1 describes autonomous selection that is always enabled. */
+ if (reg_idx == AUTO_SEL_ENABLE && reg->type == ACPI_TYPE_INTEGER &&
+ reg->cpc_entry.int_value == 1)
+ return val == 1 ? 0 : -EOPNOTSUPP;
+
/* if a register is writeable, it must be a buffer and not null */
if ((reg->type != ACPI_TYPE_BUFFER) || IS_NULL_REG(®->cpc_entry.reg)) {
pr_debug("CPC register is not supported\n");
@@ -1634,6 +1652,32 @@ int cppc_get_auto_sel(int cpu, bool *enable)
}
EXPORT_SYMBOL_GPL(cppc_get_auto_sel);
+/**
+ * cppc_auto_sel_is_immutable - Check for always-enabled autonomous selection.
+ * @cpu: CPU whose _CPC descriptor to check.
+ *
+ * Context: Process context.
+ * Return: true for Integer 1, false for a register or an absent descriptor.
+ */
+bool cppc_auto_sel_is_immutable(int cpu)
+{
+ struct cpc_desc *cpc_desc;
+ struct cpc_register_resource *reg;
+ bool immutable = false;
+
+ mutex_lock(&cpc_desc_lock);
+ cpc_desc = per_cpu(cpc_desc_ptr, cpu);
+ if (cpc_desc) {
+ reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE];
+ immutable = reg->type == ACPI_TYPE_INTEGER &&
+ reg->cpc_entry.int_value == 1;
+ }
+ mutex_unlock(&cpc_desc_lock);
+
+ return immutable;
+}
+EXPORT_SYMBOL_GPL(cppc_auto_sel_is_immutable);
+
/**
* cppc_set_auto_sel - Write autonomous selection register.
* @cpu : CPU to which to write register.
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 88dffbd65fccd..7d51877c536f1 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -1285,7 +1285,7 @@ static ssize_t amd_pstate_show_status(char *buf)
int amd_pstate_update_status(const char *buf, size_t size)
{
- int mode_idx;
+ int cpu, mode_idx, ret = 0;
if (size > strlen("passive") || size < strlen("active"))
return -EINVAL;
@@ -1295,10 +1295,25 @@ int amd_pstate_update_status(const char *buf, size_t size)
if (mode_idx < 0 || mode_idx >= AMD_PSTATE_MAX)
return -EINVAL;
- if (mode_state_machine[cppc_state][mode_idx])
- return mode_state_machine[cppc_state][mode_idx](mode_idx);
+ if (!mode_state_machine[cppc_state][mode_idx])
+ return 0;
- return 0;
+ if (mode_idx == AMD_PSTATE_PASSIVE &&
+ !cpu_feature_enabled(X86_FEATURE_CPPC)) {
+ cpus_read_lock();
+ /* Check offline CPUs too, before changing or removing the driver. */
+ for_each_present_cpu(cpu) {
+ if (cppc_auto_sel_is_immutable(cpu)) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ }
+ cpus_read_unlock();
+ if (ret)
+ return ret;
+ }
+
+ return mode_state_machine[cppc_state][mode_idx](mode_idx);
}
EXPORT_SYMBOL_GPL(amd_pstate_update_status);
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index 31767c65be20c..5fe0aa7a6c5a9 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -160,6 +160,7 @@ extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val);
extern int cppc_get_epp_perf(int cpunum, u64 *epp_perf);
extern int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable);
extern int cppc_get_auto_sel(int cpu, bool *enable);
+bool cppc_auto_sel_is_immutable(int cpu);
extern int cppc_set_auto_sel(int cpu, bool enable);
extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
extern int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator);
@@ -233,6 +234,11 @@ static inline int cppc_get_auto_sel(int cpu, bool *enable)
{
return -EOPNOTSUPP;
}
+static inline bool cppc_auto_sel_is_immutable(int cpu)
+{
+ return false;
+}
+
static inline int cppc_set_auto_sel(int cpu, bool enable)
{
return -EOPNOTSUPP;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 066/670] writeback: keep cleanup_offline_cgwb()s scan out of syncs
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (64 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 065/670] ACPI: CPPC: Accept requests to retain immutable autonomous selection Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 067/670] genirq/kexec: Do not take the bus lock of an interrupt chip on the crash path Greg Kroah-Hartman
` (605 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Tejun Heo, Liz Fong-Jones, Jan Kara,
Christian Brauner (Amutable), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Liz Fong-Jones <lizf@honeycomb.io>
[ Upstream commit 90c96612460e6accddbda5a195e6ddaa391ecde0 ]
On a filesystem mounted with lazytime, sync() and syncfs() can return
without persisting timestamp updates of inodes attached to a dying
cgroup wb, so a crash after the sync loses them. File data and sizes are
not affected.
Since commit f6988c90671e ("writeback: bound cleanup_offline_cgwb()
rescans by rotating scanned inodes"), isw_prepare_wbs_switch() moves the
inodes it walks to the newest end of the list. When a pass fills its isw
before reaching an inode that got its lazytime update after a sync's
cutoff, the walked inodes land past it on b_dirty_time, and the sync's
queue_io(), which stops at the first inode dirtied after the cutoff,
misses them. The late inode has to be one without a pending lazytime
update; one already on b_dirty_time keeps its position.
The window is narrow. cleanup_offline_cgwbs_workfn() skips wbs with
anything on b_dirty, b_io or b_more_io, so the scan has to land between
wb_writeback() fixing dirtied_before and taking list_lock for its first
queue_io(), unless a multi-pass drain started before the wb got dirty
IO.
Take wb_switch_rwsem for read across the scan, as
process_inode_switch_wbs() does for the switches.
Fixes: f6988c90671e ("writeback: bound cleanup_offline_cgwb() rescans by rotating scanned inodes")
Cc: stable@vger.kernel.org
Suggested-by: Tejun Heo <tj@kernel.org>
Link: https://lore.kernel.org/all/0bc5d58533f10b4841807be3025daa11@kernel.org/
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Liz Fong-Jones <lizf@honeycomb.io>
Link: https://patch.msgid.link/20261017040710.1174009-1-lizf@honeycomb.io
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
[ Take wb_switch_rwsem before this branch's rcu_read_lock(), as
down_read() can sleep. ]
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Liz Fong-Jones <lizf@honeycomb.io>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/fs-writeback.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 435f14b7e2cca..3b67018191df1 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -757,6 +757,13 @@ bool cleanup_offline_cgwb(struct bdi_writeback *wb)
new_wb = &wb->bdi->wb; /* wb_get() is noop for bdi's wb */
nr = 0;
+ /*
+ * The scan moves walked inodes to the newest end of b_dirty_time,
+ * past ones it didn't reach. If one of those was dirtied after a
+ * sync's cutoff, the sync's queue_io() stops there and misses the
+ * moved ones. Exclude syncs as process_inode_switch_wbs() does.
+ */
+ down_read(&wb->bdi->wb_switch_rwsem);
/*
* Paired with synchronize_rcu() in cgroup_writeback_umount().
* Holding rcu_read_lock across the SB_ACTIVE check, the inode grab
@@ -779,6 +786,7 @@ bool cleanup_offline_cgwb(struct bdi_writeback *wb)
restart = isw_prepare_wbs_switch(new_wb, isw, &wb->b_dirty_time,
&nr);
spin_unlock(&wb->list_lock);
+ up_read(&wb->bdi->wb_switch_rwsem);
/* no attached inodes? bail out */
if (nr == 0) {
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 067/670] genirq/kexec: Do not take the bus lock of an interrupt chip on the crash path
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (65 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 066/670] writeback: keep cleanup_offline_cgwb()s scan out of syncs Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 068/670] pppoe: delete session hash entries by pointer match Greg Kroah-Hartman
` (604 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Thomas Gleixner, Igor Velkov,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Igor Velkov <iav@iav.lv>
commit 717862eac6eff0eea8ac30a0c0de0bed84922aab upstream.
machine_kexec_mask_interrupts() calls irq_set_irqchip_state() for every
started interrupt. That function takes the bus lock of the chip and
desc->lock, and syncs the chip when it drops them. On the crash path
interrupts are off and the other CPUs are stopped, so a chip whose bus
transfer is completed by an interrupt never returns from the sync.
On RK3399 boards with an RK808 PMIC the RTC alarm interrupt belongs to
the regmap-irq chip of the RK808, which sits on I2C. rk808_irq_chip sets
init_ack_masked, so regmap_irq_sync_unlock() writes the ack register on
every unlock, and the I2C controller needs its own interrupt to finish
the transfer. A panic with a crash kernel loaded prints
SMP: stopping secondary CPUs
and then nothing until the watchdog resets the board.
machine_kexec_mask_interrupts() takes neither lock for the other
operations on the descriptor. Move the search for the chip that
implements irq_set_irqchip_state() into __irq_set_irqchip_state(), which
takes no locks, and call it from machine_kexec_mask_interrupts().
Fixes: 78fd584cdec0 ("arm64: kdump: implement machine_crash_shutdown()")
Suggested-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Igor Velkov <iav@iav.lv>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20261015-kexec-irq-bus-lock-v2-1-2af15f0757b6@iav.lv
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/irq/internals.h | 1 +
kernel/irq/kexec.c | 2 +-
kernel/irq/manage.c | 49 +++++++++++++++++++++---------------------
3 files changed, 27 insertions(+), 25 deletions(-)
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 7062a99a1ddd2..0b60f8aa62868 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -77,6 +77,7 @@ enum {
#include "settings.h"
extern int __irq_set_trigger(struct irq_desc *desc, unsigned long flags);
+extern int __irq_set_irqchip_state(struct irq_desc *desc, enum irqchip_irq_state which, bool val);
extern void __disable_irq(struct irq_desc *desc);
extern void __enable_irq(struct irq_desc *desc);
diff --git a/kernel/irq/kexec.c b/kernel/irq/kexec.c
index 0f9548c1708dd..58d92a7f2af1c 100644
--- a/kernel/irq/kexec.c
+++ b/kernel/irq/kexec.c
@@ -25,7 +25,7 @@ void machine_kexec_mask_interrupts(void)
* First try to remove the active state from an interrupt which is forwarded
* to a VM. If the interrupt is not forwarded, try to EOI the interrupt.
*/
- check_eoi = irq_set_irqchip_state(i, IRQCHIP_STATE_ACTIVE, false);
+ check_eoi = __irq_set_irqchip_state(desc, IRQCHIP_STATE_ACTIVE, false);
}
if (check_eoi && chip->irq_eoi && irqd_irq_inprogress(&desc->irq_data))
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 67b1c5a352014..927a6e52a58c9 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -2867,6 +2867,28 @@ int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which,
}
EXPORT_SYMBOL_GPL(irq_get_irqchip_state);
+int __irq_set_irqchip_state(struct irq_desc *desc, enum irqchip_irq_state which, bool val)
+{
+ struct irq_data *data = irq_desc_get_irq_data(desc);
+ struct irq_chip *chip;
+
+ do {
+ chip = irq_data_get_irq_chip(data);
+
+ if (WARN_ON_ONCE(!chip))
+ return -ENODEV;
+
+ if (chip->irq_set_irqchip_state)
+ break;
+
+ data = irqd_get_parent_data(data);
+ } while (data);
+
+ if (data)
+ return chip->irq_set_irqchip_state(data, which, val);
+ return -EINVAL;
+}
+
/**
* irq_set_irqchip_state - set the state of a forwarded interrupt.
* @irq: Interrupt line that is forwarded to a VM
@@ -2883,36 +2905,15 @@ int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which,
bool val)
{
struct irq_desc *desc;
- struct irq_data *data;
- struct irq_chip *chip;
unsigned long flags;
- int err = -EINVAL;
+ int err;
desc = irq_get_desc_buslock(irq, &flags, 0);
if (!desc)
- return err;
-
- data = irq_desc_get_irq_data(desc);
-
- do {
- chip = irq_data_get_irq_chip(data);
- if (WARN_ON_ONCE(!chip)) {
- err = -ENODEV;
- goto out_unlock;
- }
- if (chip->irq_set_irqchip_state)
- break;
-#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
- data = data->parent_data;
-#else
- data = NULL;
-#endif
- } while (data);
+ return -EINVAL;
- if (data)
- err = chip->irq_set_irqchip_state(data, which, val);
+ err = __irq_set_irqchip_state(desc, which, val);
-out_unlock:
irq_put_desc_busunlock(desc, flags);
return err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 068/670] pppoe: delete session hash entries by pointer match
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (66 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 067/670] genirq/kexec: Do not take the bus lock of an interrupt chip on the crash path Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 069/670] xfs: flag excessive delalloc rt extents as corruption Greg Kroah-Hartman
` (603 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Qingfang Deng, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qingfang Deng <qingfang.deng@linux.dev>
[ Upstream commit b5b8c81836e2bec7b444dfa2b14fd14e912e9d63 ]
pppoe_connect() copies the requested PPPoE address to a socket before
attempting to insert the socket into the session hash table. If the
tuple already exists, __set_item() returns -EALREADY, but the copied
address and ifindex remain set on the failed socket.
Closing that socket then deletes the existing socket's hash entry
through pppoe_release(), preventing it from receiving further session
traffic. An unprivileged process in the same network namespace can
trigger this through a duplicate connection attempt.
To avoid the accidental delete, pass the pppox_sock to __delete_item(),
and unlink only an entry whose pointer matches the requested socket.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Qingfang Deng <qingfang.deng@linux.dev>
Link: https://patch.msgid.link/20261020092118.47416-1-qingfang.deng@linux.dev
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
[ Resolve conflict, and remove const qualifier of pppox_sock to match
hash_item(). ]
Signed-off-by: Qingfang Deng <qingfang.deng@linux.dev>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ppp/pppoe.c | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 8ff2024dde604..293b6fb1c1e98 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -194,18 +194,16 @@ static int __set_item(struct pppoe_net *pn, struct pppox_sock *po)
return 0;
}
-static void __delete_item(struct pppoe_net *pn, __be16 sid,
- char *addr, int ifindex)
+static void __delete_item(struct pppoe_net *pn, struct pppox_sock *po)
{
- int hash = hash_item(sid, addr);
+ int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote);
struct pppox_sock *ret, **src;
ret = pn->hash_table[hash];
src = &pn->hash_table[hash];
while (ret) {
- if (cmp_addr(&ret->pppoe_pa, sid, addr) &&
- ret->pppoe_ifindex == ifindex) {
+ if (ret == po) {
*src = ret->next;
break;
}
@@ -255,11 +253,10 @@ static inline struct pppox_sock *get_item_by_addr(struct net *net,
return pppox_sock;
}
-static inline void delete_item(struct pppoe_net *pn, __be16 sid,
- char *addr, int ifindex)
+static void delete_item(struct pppoe_net *pn, struct pppox_sock *po)
{
write_lock_bh(&pn->hash_lock);
- __delete_item(pn, sid, addr, ifindex);
+ __delete_item(pn, po);
write_unlock_bh(&pn->hash_lock);
}
@@ -599,8 +596,7 @@ static int pppoe_release(struct socket *sock)
* protect "po" from concurrent updates
* on pppoe_flush_dev
*/
- delete_item(pn, po->pppoe_pa.sid, po->pppoe_pa.remote,
- po->pppoe_ifindex);
+ delete_item(pn, po);
sock_orphan(sk);
sock->sk = NULL;
@@ -651,8 +647,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
if (stage_session(po->pppoe_pa.sid)) {
pppox_unbind_sock(sk);
pn = pppoe_pernet(sock_net(sk));
- delete_item(pn, po->pppoe_pa.sid,
- po->pppoe_pa.remote, po->pppoe_ifindex);
+ delete_item(pn, po);
if (po->pppoe_dev) {
dev_put(po->pppoe_dev);
po->pppoe_dev = NULL;
@@ -703,8 +698,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
error = ppp_register_net_channel(dev_net(dev), &po->chan);
if (error) {
- delete_item(pn, po->pppoe_pa.sid,
- po->pppoe_pa.remote, po->pppoe_ifindex);
+ delete_item(pn, po);
goto err_put;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 069/670] xfs: flag excessive delalloc rt extents as corruption
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (67 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 068/670] pppoe: delete session hash entries by pointer match Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 070/670] xfs: mark cow extents bad if theres no rmap mapping for them Greg Kroah-Hartman
` (602 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit 2b47be015a5e54f4a3d62afa636ba593de9b67f6 ]
LOLLM observed that we should not allow repairs to proceed if the count
of delayed-allocation realtime extents exceeds the number of free rt
extents because we can't install negative numbers into the superblock.
It's unclear how we could end up in that state in real life, but let's
at least complain loudly about it if we ever encounter it.
Cc: stable@vger.kernel.org # v6.2
Fixes: e74331d6fa2c21 ("xfs: online checking of the free rt extent count")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
[ sashal: removed the xfs_has_zoned() check because zoned filesystem support is absent ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/fscounters.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c
index 98634c668b56c..ac7e6329e46e8 100644
--- a/fs/xfs/scrub/fscounters.c
+++ b/fs/xfs/scrub/fscounters.c
@@ -606,6 +606,13 @@ xchk_fscounters(
try_again = true;
}
+ if (fsc->frextents < fsc->frextents_delayed) {
+ if (fsc->frozen)
+ xchk_set_incomplete(sc);
+ else
+ try_again = true;
+ }
+
if (!xchk_fscount_within_range(sc, frextents, &mp->m_frextents,
fsc->frextents - fsc->frextents_delayed)) {
if (fsc->frozen)
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 070/670] xfs: mark cow extents bad if theres no rmap mapping for them
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (68 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 069/670] xfs: flag excessive delalloc rt extents as corruption Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 071/670] xfs: rescan the AGs if incore delalloc counter is negative Greg Kroah-Hartman
` (601 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit 2ffc0619c9c2881443c5fffb10db8f2bc0aa2ce8 ]
LOLLM noticed that we fail to mark cow staging extents as bad if there's
a cow staging extent but no rmap record for the cow staging event.
Close this gap.
Cc: stable@vger.kernel.org # v6.8
Fixes: dbbdbd0086320a ("xfs: repair problems in CoW forks")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
[ sashal: Replaced xfs_gbno_to_fsb() and xfs_agbno_to_fsb() calls with the existing XFS_AGB_TO_FSB() macro. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/cow_repair.c | 66 +++++++++++++++++++++++++--------------
1 file changed, 42 insertions(+), 24 deletions(-)
diff --git a/fs/xfs/scrub/cow_repair.c b/fs/xfs/scrub/cow_repair.c
index e8f7cfd4dd22b..853744729577b 100644
--- a/fs/xfs/scrub/cow_repair.c
+++ b/fs/xfs/scrub/cow_repair.c
@@ -194,30 +194,37 @@ xrep_cow_mark_missing_staging_rmap(
void *priv)
{
struct xrep_cow *xc = priv;
- xfs_fsblock_t fsbno;
- xfs_agblock_t rec_bno;
- xfs_extlen_t rec_len;
- unsigned int adj;
+ const xfs_agblock_t rec_end =
+ rec->rm_startblock + rec->rm_blockcount;
+ int error = 0;
- if (rec->rm_owner == XFS_RMAP_OWN_COW)
- return 0;
-
- rec_bno = rec->rm_startblock;
- rec_len = rec->rm_blockcount;
- if (rec_bno < xc->irec_startbno) {
- adj = xc->irec_startbno - rec_bno;
- rec_len -= adj;
- rec_bno += adj;
+ /* Was there a gap since the last rmap? */
+ if (xc->next_bno < rec->rm_startblock) {
+ error = xrep_cow_mark_file_range(xc,
+ XFS_AGB_TO_FSB(xc->sc->mp, cur->bc_ag.pag->pag_agno,
+ xc->next_bno),
+ rec->rm_startblock - xc->next_bno);
+ if (error)
+ return error;
}
- if (rec_bno + rec_len > xc->irec_startbno + xc->irec.br_blockcount) {
- adj = (rec_bno + rec_len) -
- (xc->irec_startbno + xc->irec.br_blockcount);
- rec_len -= adj;
+ if (rec->rm_owner != XFS_RMAP_OWN_COW) {
+ const xfs_agblock_t bad_bno =
+ max(xc->irec_startbno, rec->rm_startblock);
+ const xfs_agblock_t irec_end =
+ xc->irec_startbno + xc->irec.br_blockcount;
+ const xfs_extlen_t bad_end = min(irec_end, rec_end);
+
+ error = xrep_cow_mark_file_range(xc,
+ XFS_AGB_TO_FSB(xc->sc->mp, cur->bc_ag.pag->pag_agno,
+ bad_bno),
+ bad_end - bad_bno);
+ if (error)
+ return error;
}
- fsbno = XFS_AGB_TO_FSB(xc->sc->mp, cur->bc_ag.pag->pag_agno, rec_bno);
- return xrep_cow_mark_file_range(xc, fsbno, rec_len);
+ xc->next_bno = max(xc->next_bno, rec_end);
+ return error;
}
/*
@@ -235,10 +242,12 @@ xrep_cow_find_bad(
struct xfs_perag *pag;
struct xfs_scrub *sc = xc->sc;
xfs_agnumber_t agno;
+ xfs_agblock_t irec_end;
int error;
agno = XFS_FSB_TO_AGNO(sc->mp, xc->irec.br_startblock);
xc->irec_startbno = XFS_FSB_TO_AGBNO(sc->mp, xc->irec.br_startblock);
+ irec_end = xc->irec_startbno + xc->irec.br_blockcount;
pag = xfs_perag_get(sc->mp, agno);
if (!pag)
@@ -250,7 +259,7 @@ xrep_cow_find_bad(
/* Mark any CoW fork extents that are shared. */
rc_low.rc_startblock = xc->irec_startbno;
- rc_high.rc_startblock = xc->irec_startbno + xc->irec.br_blockcount - 1;
+ rc_high.rc_startblock = irec_end - 1;
rc_low.rc_domain = rc_high.rc_domain = XFS_REFC_DOMAIN_SHARED;
error = xfs_refcount_query_range(sc->sa.refc_cur, &rc_low, &rc_high,
xrep_cow_mark_shared_staging, xc);
@@ -259,7 +268,7 @@ xrep_cow_find_bad(
/* Make sure there are CoW staging extents for the whole mapping. */
rc_low.rc_startblock = xc->irec_startbno;
- rc_high.rc_startblock = xc->irec_startbno + xc->irec.br_blockcount - 1;
+ rc_high.rc_startblock = irec_end - 1;
rc_low.rc_domain = rc_high.rc_domain = XFS_REFC_DOMAIN_COW;
xc->next_bno = xc->irec_startbno;
error = xfs_refcount_query_range(sc->sa.refc_cur, &rc_low, &rc_high,
@@ -267,12 +276,11 @@ xrep_cow_find_bad(
if (error)
goto out_sa;
- if (xc->next_bno < xc->irec_startbno + xc->irec.br_blockcount) {
+ if (xc->next_bno < irec_end) {
error = xrep_cow_mark_file_range(xc,
XFS_AGB_TO_FSB(sc->mp, pag->pag_agno,
xc->next_bno),
- xc->irec_startbno + xc->irec.br_blockcount -
- xc->next_bno);
+ irec_end - xc->next_bno);
if (error)
goto out_sa;
}
@@ -281,11 +289,21 @@ xrep_cow_find_bad(
rm_low.rm_startblock = xc->irec_startbno;
memset(&rm_high, 0xFF, sizeof(rm_high));
rm_high.rm_startblock = xc->irec_startbno + xc->irec.br_blockcount - 1;
+ xc->next_bno = xc->irec_startbno;
error = xfs_rmap_query_range(sc->sa.rmap_cur, &rm_low, &rm_high,
xrep_cow_mark_missing_staging_rmap, xc);
if (error)
goto out_sa;
+ if (xc->next_bno < irec_end) {
+ error = xrep_cow_mark_file_range(xc,
+ XFS_AGB_TO_FSB(sc->mp, pag->pag_agno,
+ xc->next_bno),
+ irec_end - xc->next_bno);
+ if (error)
+ goto out_sa;
+ }
+
/*
* If userspace is forcing us to rebuild the CoW fork or someone turned
* on the debugging knob, replace everything in the CoW fork.
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 071/670] xfs: rescan the AGs if incore delalloc counter is negative
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (69 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 070/670] xfs: mark cow extents bad if theres no rmap mapping for them Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 072/670] xfs: dont queue rmap update twice when reaping a fork Greg Kroah-Hartman
` (600 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit 47b1e941bb55f735d82ba2649412260da78b98f8 ]
LOLLM complains that percpu_counter_sum can return a negative number but
we instead misinterpret that into a huge unsigned value and do bad
things to fdblocks. It shouldn't do that, so let's add a retry loop and
an attempt to freeze the filesystem to (hopefully) zero out the incore
delalloc counter. It probably won't work, but at least failing the
repair beats doing the wrong thing.
Cc: stable@vger.kernel.org # v5.2
Fixes: 75efa57d0bf5fc ("xfs: add online scrub for superblock counters")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
[ sashal: Changed the realtime error return to goto out_unlock because the bitmap lock is still held. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/fscounters.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c
index ac7e6329e46e8..ad23343c52f71 100644
--- a/fs/xfs/scrub/fscounters.c
+++ b/fs/xfs/scrub/fscounters.c
@@ -296,7 +296,7 @@ xchk_fscount_aggregate_agcounts(
{
struct xfs_mount *mp = sc->mp;
struct xfs_perag *pag;
- uint64_t delayed;
+ int64_t delayed;
xfs_agnumber_t agno;
int tries = 8;
int error = 0;
@@ -359,6 +359,11 @@ xchk_fscount_aggregate_agcounts(
* of the computation.
*/
delayed = percpu_counter_sum(&mp->m_delalloc_blks);
+ if (delayed < 0) {
+ ASSERT(delayed >= 0);
+ xchk_set_incomplete(sc);
+ return -EFSCORRUPTED;
+ }
fsc->fdblocks -= delayed;
trace_xchk_fscounters_calc(mp, fsc->icount, fsc->ifree, fsc->fdblocks,
@@ -416,6 +421,7 @@ xchk_fscount_count_frextents(
struct xchk_fscounters *fsc)
{
struct xfs_mount *mp = sc->mp;
+ int64_t delayed;
int error;
fsc->frextents = 0;
@@ -431,7 +437,14 @@ xchk_fscount_count_frextents(
goto out_unlock;
}
- fsc->frextents_delayed = percpu_counter_sum(&mp->m_delalloc_rtextents);
+ delayed = percpu_counter_sum(&mp->m_delalloc_rtextents);
+ if (delayed < 0) {
+ ASSERT(delayed >= 0);
+ xchk_set_incomplete(sc);
+ error = -EFSCORRUPTED;
+ goto out_unlock;
+ }
+ fsc->frextents_delayed = delayed;
out_unlock:
xfs_rtbitmap_unlock_shared(sc->mp, XFS_RBMLOCK_BITMAP);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 072/670] xfs: dont queue rmap update twice when reaping a fork
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (70 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 071/670] xfs: rescan the AGs if incore delalloc counter is negative Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 073/670] xfs: complain loudly when dirtree checker finds broken links Greg Kroah-Hartman
` (599 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit 219ff8a734d8438e24eb346a847c9b1ad9b7ab5d ]
LOLLM noticed that xrep_reap_bmapi_iter calls xfs_bmap_unmap_extent and
xfs_rmap_unmap_extent to remove a mapping from a file fork and its
reverse mapping. However, xfs_bmap_del_extent_real also queues a
deferred rmap removal log item, which means that we incorrectly queue
two rmap removal operations. Fix that by removing the extra call and
updating the comment to mention this subtlety that I forgot, having
written the code. :P
Cc: stable@vger.kernel.org # v6.10
Fixes: 5befb047b9f4de ("xfs: add the ability to reap entire inode forks")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
[ sashal: Adapted rs->ip and rs->whichfork references to direct ip and whichfork arguments. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/reap.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/xfs/scrub/reap.c b/fs/xfs/scrub/reap.c
index 4ce345ae4565e..0c827798ade67 100644
--- a/fs/xfs/scrub/reap.c
+++ b/fs/xfs/scrub/reap.c
@@ -905,12 +905,12 @@ xrep_reap_bmapi_iter(
/*
* Schedule removal of the mapping from the fork. We use
* deferred log intents in this function to control the exact
- * sequence of metadata updates.
+ * sequence of metadata updates. The BUI queues a RUI to
+ * remove the reverse mapping.
*/
xfs_bmap_unmap_extent(sc->tp, ip, whichfork, imap);
xfs_trans_mod_dquot_byino(sc->tp, ip, XFS_TRANS_DQ_BCOUNT,
-(int64_t)imap->br_blockcount);
- xfs_rmap_unmap_extent(sc->tp, ip, whichfork, imap);
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 073/670] xfs: complain loudly when dirtree checker finds broken links
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (71 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 072/670] xfs: dont queue rmap update twice when reaping a fork Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 074/670] xfs: reinitialize dquot block if non-first dquot cant load Greg Kroah-Hartman
` (598 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit e09438cab72c2c6a32665829d4186155346bfee8 ]
LOLLM observed that the directory tree walk code bails out if it finds
broken parent pointers along the way. However, it flattens the return
code to zero, which means that we can end up in the repair code having
not completed the scan. We should never proceed with a repair in this
state, so let's mark the scrub incomplete and exit.
Cc: stable@vger.kernel.org # v6.10
Fixes: 928b721a11789a ("xfs: teach online scrub to find directory tree structure problems")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
[ sashal: Retained xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino) instead of upstream's xchk_ip_xref_set_corrupt(sc, sc->ip). ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/dirtree.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/fs/xfs/scrub/dirtree.c b/fs/xfs/scrub/dirtree.c
index 8933506c4830a..35848cbfae929 100644
--- a/fs/xfs/scrub/dirtree.c
+++ b/fs/xfs/scrub/dirtree.c
@@ -849,7 +849,8 @@ xchk_dirtree_find_paths_to_root(
* A parent pointer of @sc->ip is bad, don't
* bother continuing.
*/
- break;
+ xchk_set_incomplete(sc);
+ return error;
}
if (error == -ESTALE) {
/* This had better be an invalidation. */
@@ -970,6 +971,7 @@ xchk_dirtree(
* parent pointers are corrupt; this scan cannot be completed
* without full information.
*/
+ xchk_set_incomplete(sc);
xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
error = 0;
goto out_scanlock;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 074/670] xfs: reinitialize dquot block if non-first dquot cant load
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (72 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 073/670] xfs: complain loudly when dirtree checker finds broken links Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:43 ` [PATCH 6.12 075/670] xfs: forcibly reset quota timers when upgrading to bigtime during repair Greg Kroah-Hartman
` (597 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit faa9aa9e846332aaad78096a2cebfeafe68a7776 ]
LOLLM noticed that the early exit logic in xrep_quota_block is defective
because it only looks in the first ondisk dquot for corruption that
would prevent dquots from loading. We need to scan all the dquots in
the block, not just the first one.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Stable-dep-of: 780212c8d810 ("xfs: forcibly reset quota timers when upgrading to bigtime during repair")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/quota_repair.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/fs/xfs/scrub/quota_repair.c b/fs/xfs/scrub/quota_repair.c
index 95d5bb8c10032..368be503334fa 100644
--- a/fs/xfs/scrub/quota_repair.c
+++ b/fs/xfs/scrub/quota_repair.c
@@ -299,7 +299,6 @@ xrep_quota_block(
xfs_dqid_t id)
{
struct xfs_dqblk *dqblk;
- struct xfs_disk_dquot *ddq;
struct xfs_quotainfo *qi = sc->mp->m_quotainfo;
struct xfs_def_quota *defq = xfs_get_defquota(qi, dqtype);
struct xfs_buf *bp = NULL;
@@ -321,14 +320,21 @@ xrep_quota_block(
break;
case 0:
dqblk = bp->b_addr;
- ddq = &dqblk[0].dd_diskdq;
+ error = 0;
/*
* If there's nothing that would impede a dqiterate, we're
* done.
*/
- if ((ddq->d_type & XFS_DQTYPE_REC_MASK) == dqtype &&
- id == be32_to_cpu(ddq->d_id)) {
+ for (i = 0; i < qi->qi_dqperchunk; i++, dqblk++) {
+ struct xfs_disk_dquot *ddq = &dqblk->dd_diskdq;
+
+ if ((ddq->d_type & XFS_DQTYPE_REC_MASK) != dqtype ||
+ id + i != be32_to_cpu(ddq->d_id))
+ error++;
+ }
+
+ if (!error) {
xfs_trans_brelse(sc->tp, bp);
return 0;
}
@@ -341,7 +347,7 @@ xrep_quota_block(
dqblk = bp->b_addr;
bp->b_ops = &xfs_dquot_buf_ops;
for (i = 0; i < qi->qi_dqperchunk; i++, dqblk++) {
- ddq = &dqblk->dd_diskdq;
+ struct xfs_disk_dquot *ddq = &dqblk->dd_diskdq;
trace_xrep_disk_dquot(sc->mp, dqtype, id + i);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 075/670] xfs: forcibly reset quota timers when upgrading to bigtime during repair
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (73 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 074/670] xfs: reinitialize dquot block if non-first dquot cant load Greg Kroah-Hartman
@ 2026-11-13 15:43 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 076/670] xfs: dont try to repair rtsummary if the summary file isnt computed Greg Kroah-Hartman
` (596 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:43 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit 780212c8d8105eadb5f56b4c7aafb94937755582 ]
If we decide to upgrade a dquot to BIGTIME as part of repairing it, we
should zero out the timer fields so that they are re-evaluated and reset
in bigtime format instead of letting through whatever was in there
before.
Cc: stable@vger.kernel.org # v6.8
Fixes: a5b91555403e3a ("xfs: repair quotas")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/quota_repair.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/fs/xfs/scrub/quota_repair.c b/fs/xfs/scrub/quota_repair.c
index 368be503334fa..0def7a1b366a8 100644
--- a/fs/xfs/scrub/quota_repair.c
+++ b/fs/xfs/scrub/quota_repair.c
@@ -348,6 +348,8 @@ xrep_quota_block(
bp->b_ops = &xfs_dquot_buf_ops;
for (i = 0; i < qi->qi_dqperchunk; i++, dqblk++) {
struct xfs_disk_dquot *ddq = &dqblk->dd_diskdq;
+ bool was_bigtime =
+ !!(ddq->d_type & XFS_DQTYPE_BIGTIME);
trace_xrep_disk_dquot(sc->mp, dqtype, id + i);
@@ -356,8 +358,21 @@ xrep_quota_block(
ddq->d_type = dqtype;
ddq->d_id = cpu_to_be32(id + i);
- if (xfs_has_bigtime(sc->mp) && ddq->d_id)
+ if (xfs_has_bigtime(sc->mp) && ddq->d_id) {
+ /*
+ * If something was broken with this dquot and it was a
+ * non-bigtime dquot, we'll grant everyone a fresh
+ * grace period by zeroing the timer field rather than
+ * try to interpret what might be garbage.
+ */
+ if (!was_bigtime) {
+ ddq->d_btimer = 0;
+ ddq->d_itimer = 0;
+ ddq->d_rtbtimer = 0;
+ }
+
ddq->d_type |= XFS_DQTYPE_BIGTIME;
+ }
xrep_quota_fix_timer(sc->mp, ddq, ddq->d_blk_softlimit,
ddq->d_bcount, &ddq->d_btimer,
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 076/670] xfs: dont try to repair rtsummary if the summary file isnt computed
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (74 preceding siblings ...)
2026-11-13 15:43 ` [PATCH 6.12 075/670] xfs: forcibly reset quota timers when upgrading to bigtime during repair Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 077/670] xfs: reattach dquots after changing inode ids Greg Kroah-Hartman
` (595 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit 6e82b7641889ad0198f3bf17a5e4c6fe7aab0850 ]
LOLLM observed that we can erroneously try to repair the rtsummary file
if we've not yet computed its contents. That results in a corrupt
summary file, so let's add a flag to track whether or not the incore
data is complete.
Cc: stable@vger.kernel.org # v6.10
Fixes: abf039e2e4afde ("xfs: online repair of realtime summaries")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
[ sashal: Adapted xchk_rtsum_compute() to the existing mount-based realtime bitmap APIs. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/rtsummary.c | 9 ++++++++-
fs/xfs/scrub/rtsummary.h | 1 +
fs/xfs/scrub/rtsummary_repair.c | 2 +-
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/fs/xfs/scrub/rtsummary.c b/fs/xfs/scrub/rtsummary.c
index 746990ae0ec1e..942f93b1e22ed 100644
--- a/fs/xfs/scrub/rtsummary.c
+++ b/fs/xfs/scrub/rtsummary.c
@@ -201,15 +201,22 @@ xchk_rtsum_compute(
struct xfs_scrub *sc)
{
struct xfs_mount *mp = sc->mp;
+ struct xchk_rtsummary *rts = sc->buf;
unsigned long long rtbmp_blocks;
+ int error;
/* If the bitmap size doesn't match the computed size, bail. */
rtbmp_blocks = xfs_rtbitmap_blockcount(mp, mp->m_sb.sb_rextents);
if (XFS_FSB_TO_B(mp, rtbmp_blocks) != mp->m_rbmip->i_disk_size)
return -EFSCORRUPTED;
- return xfs_rtalloc_query_all(sc->mp, sc->tp, xchk_rtsum_record_free,
+ error = xfs_rtalloc_query_all(sc->mp, sc->tp, xchk_rtsum_record_free,
sc);
+ if (error)
+ return error;
+
+ rts->summary_computed = true;
+ return 0;
}
/* Compare the rtsummary file against the one we computed. */
diff --git a/fs/xfs/scrub/rtsummary.h b/fs/xfs/scrub/rtsummary.h
index e44b04cb6e2d5..af1ab64c3f212 100644
--- a/fs/xfs/scrub/rtsummary.h
+++ b/fs/xfs/scrub/rtsummary.h
@@ -17,6 +17,7 @@ struct xchk_rtsummary {
xfs_filblks_t rsumblocks;
unsigned int rsumlevels;
unsigned int resblks;
+ bool summary_computed;
/* suminfo position of xfile as we write buffers to disk. */
xfs_rtsumoff_t prep_wordoff;
diff --git a/fs/xfs/scrub/rtsummary_repair.c b/fs/xfs/scrub/rtsummary_repair.c
index 7deeb948cb702..536f0b8e3bfd0 100644
--- a/fs/xfs/scrub/rtsummary_repair.c
+++ b/fs/xfs/scrub/rtsummary_repair.c
@@ -110,7 +110,7 @@ xrep_rtsummary(
return -EOPNOTSUPP;
/* Walk away if we disagree on the size of the rt bitmap. */
- if (rts->rbmblocks != mp->m_sb.sb_rbmblocks)
+ if (rts->rbmblocks != mp->m_sb.sb_rbmblocks || !rts->summary_computed)
return 0;
/* Make sure any problems with the fork are fixed. */
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 077/670] xfs: reattach dquots after changing inode ids
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (75 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 076/670] xfs: dont try to repair rtsummary if the summary file isnt computed Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 078/670] smb: client: reject FIND data areas that run past the received response Greg Kroah-Hartman
` (594 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit 2f528e4a8f89daa6d0cc64b044f6f94c018fe9ae ]
LOLLM noticed that xrep_inode_ids can change the user, group, or project
id of any given file. When this happens, we need to detach any existing
incore dquot and attach the correct ones.
Cc: stable@vger.kernel.org # v6.8
Fixes: 2d295fe65776d1 ("xfs: repair inode records")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
[ sashal: adapted quota attachment for missing metadata-directory support and xfs_qm_dqget_inode() returning locked dquots ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/inode_repair.c | 132 +++++++++++++++++++++++++++++++++++-
1 file changed, 131 insertions(+), 1 deletion(-)
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index 6be4551bffbd3..fa84a2efee431 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -38,6 +38,8 @@
#include "xfs_log_priv.h"
#include "xfs_health.h"
#include "xfs_symlink_remote.h"
+#include "xfs_dquot_item.h"
+#include "xfs_dquot.h"
#include "scrub/xfs_scrub.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
@@ -1570,6 +1572,20 @@ xrep_inode_ids(
trace_xrep_inode_ids(sc);
+ /*
+ * We changed one of the file IDs, so we must detach the dquots to
+ * prevent further changes from being accounted to them, and try to
+ * attach the dquot for the new id to absorb any other block usage
+ * changes. We can't do that right now because the existing dquots
+ * might be attached to the scrub transaction and we're in the middle
+ * of fixing the inode, so we'll switch the incore dquot pointers
+ * later.
+ *
+ * Schedule a quotacheck so the accounting discrepancies will get fixed
+ * eventually. We'll have to repeat this later when we do the actual
+ * switch.
+ */
+
if (!uid_valid(VFS_I(sc->ip)->i_uid)) {
i_uid_write(VFS_I(sc->ip), 0);
dirty = true;
@@ -1876,6 +1892,112 @@ xrep_inode_unlinked(
return 0;
}
+#ifdef CONFIG_XFS_QUOTA
+static inline bool
+xrep_inode_need_reset_dquots(
+ struct xfs_scrub *sc)
+{
+ struct xfs_mount *mp = sc->mp;
+ struct xfs_inode *ip = sc->ip;
+
+ if (!XFS_IS_QUOTA_ON(mp))
+ return false;
+ if (xfs_is_quota_inode(&mp->m_sb, I_INO(ip)))
+ return false;
+
+ if (XFS_IS_UQUOTA_ON(sc->mp) &&
+ (!ip->i_udquot || ip->i_udquot->q_id != i_uid_read(VFS_I(ip))))
+ return true;
+ if (XFS_IS_GQUOTA_ON(sc->mp) &&
+ (!ip->i_gdquot || ip->i_gdquot->q_id != i_gid_read(VFS_I(ip))))
+ return true;
+ if (XFS_IS_PQUOTA_ON(sc->mp) &&
+ (!ip->i_pdquot || ip->i_pdquot->q_id != ip->i_projid))
+ return true;
+
+ return false;
+}
+
+/* Switch dquot, return dqtype if we need quotacheck */
+static xfs_dqtype_t
+xrep_inode_switch_dquot(
+ struct xfs_scrub *sc,
+ xfs_dqtype_t type,
+ struct xfs_dquot **dqp)
+{
+ xfs_dqtype_t ret = 0;
+ xfs_dqid_t id = xfs_qm_id_for_quotatype(sc->ip, type);
+
+ if (*dqp != NULL && (*dqp)->q_id != id) {
+ xfs_qm_dqrele(*dqp);
+ *dqp = NULL;
+ }
+
+ if (!*dqp) {
+ if (!xfs_qm_dqget_inode(sc->ip, type, true, dqp))
+ xfs_dqunlock(*dqp);
+ ret = type;
+ }
+ return ret;
+}
+
+static int
+xrep_inode_reset_dquots(
+ struct xfs_scrub *sc)
+{
+ xfs_dqtype_t need = 0;
+ int error;
+
+ /*
+ * If we changed the file IDs, then we need to drop the transaction so
+ * that we can detach the dquots and attach new ones.
+ *
+ * Commit the scrub transaction so that there are no dangling
+ * references to any dquots that might get detached, and retain the
+ * ILOCK, as required by the dqattach code.
+ *
+ * Note that dqattach can cycle the ILOCK when creating a new dquot, so
+ * this must be the very last thing that the repair function does.
+ */
+ error = xrep_trans_commit(sc);
+ if (error)
+ return error;
+
+ if (XFS_IS_UQUOTA_ON(sc->mp))
+ need |= xrep_inode_switch_dquot(sc, XFS_DQTYPE_USER,
+ &sc->ip->i_udquot);
+ if (XFS_IS_GQUOTA_ON(sc->mp))
+ need |= xrep_inode_switch_dquot(sc, XFS_DQTYPE_GROUP,
+ &sc->ip->i_gdquot);
+ if (XFS_IS_PQUOTA_ON(sc->mp))
+ need |= xrep_inode_switch_dquot(sc, XFS_DQTYPE_PROJ,
+ &sc->ip->i_pdquot);
+
+ xchk_iunlock(sc, XFS_ILOCK_EXCL);
+
+ /*
+ * Now that we've updated the dquots, force quotacheck once again.
+ * In theory we could be racing against a concurrent quotacheck.
+ * Note that we can't hold the ILOCK when allocating a transaction.
+ */
+ error = xchk_trans_alloc(sc, 0);
+ if (error)
+ return error;
+
+ if (need & XFS_DQTYPE_USER)
+ xrep_force_quotacheck(sc, XFS_DQTYPE_USER);
+ if (need & XFS_DQTYPE_GROUP)
+ xrep_force_quotacheck(sc, XFS_DQTYPE_GROUP);
+ if (need & XFS_DQTYPE_PROJ)
+ xrep_force_quotacheck(sc, XFS_DQTYPE_PROJ);
+
+ return 0;
+}
+#else
+# define xrep_inode_need_reset_dquots(sc) (false)
+# define xrep_inode_reset_dquots(sc) (0)
+#endif
+
/* Repair an inode's fields. */
int
xrep_inode(
@@ -1930,5 +2052,13 @@ xrep_inode(
if (error)
return error;
- return xrep_defer_finish(sc);
+ error = xrep_defer_finish(sc);
+ if (error)
+ return error;
+
+ /* Must come last */
+ if (xrep_inode_need_reset_dquots(sc))
+ return xrep_inode_reset_dquots(sc);
+
+ return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 078/670] smb: client: reject FIND data areas that run past the received response
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (76 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 077/670] xfs: reattach dquots after changing inode ids Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 079/670] raid6: add missing vzeroupper to AVX2 code Greg Kroah-Hartman
` (593 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Diego Oliva, David Howells,
Paulo Alcantara, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Diego Oliva <diego@bynar.io>
[ Upstream commit 29bd6773187cb5c1bbbdf90d677c6add7d58af26 ]
CIFSFindFirst() and CIFSFindNext() take the directory entries of a
TRANS2_FIND_FIRST2 or TRANS2_FIND_NEXT2 response from DataOffset for
DataCount bytes. validate_t2() bounds DataOffset at 1024 and
ParameterCount + DataCount by the byte count, and nothing compares
DataOffset + DataCount with the number of bytes SendReceive() copied
into the buffer.
smb_init() places the request and the response in the same
cifs_request allocation and cifs_buf_get() clears only the start of
it, so a short response whose data area extends past its end has
srch_entries_start point at bytes of the request that was just sent,
or at whatever the allocation held before, and those bytes are parsed
as directory entries. cifs_readdir() and find_cifs_entry() walk the
entries with nxt_dir_entry(), which checks every entry but the first
of a response against the end of the SMB; cifs_query_path_info() and
cifs_backup_query_path_info() read the first entry with no check at
all. Those reads stay inside the allocation, but what they return is
not part of the response. The last entry, which LastNameOffset locates
relative to the data area, is bounded against the received response
by an earlier patch of this series, as is every entry that
cifs_fill_dirent() parses; the walk itself and the two query functions
are not.
SMB1 is not negotiated by default; reaching this code requires an
explicit vers=1.0 mount.
Reject a response whose data area extends past the received length,
with the -EINVAL that validate_t2() returns for the other malformed
transaction responses. cifs_query_path_info() and
cifs_backup_query_path_info() still read a whole entry from a data
area that may be smaller than one; that is not changed here.
A conforming server is not affected. The data block of a transaction
response is part of the SMB, so DataOffset + DataCount cannot exceed
the smbCalcSize() bytes that SendReceive() copies; coalesce_t2()
appends each secondary response to the data area and adds its length
to both DataCount and the byte count, which keeps that relation.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: Bynario AI
Signed-off-by: Diego Oliva <diego@bynar.io>
Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
[ sashal: adjusted declaration context to account for the missing in_len variable ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/cifssmb.c | 31 +++++++++++++++++++++++++------
1 file changed, 25 insertions(+), 6 deletions(-)
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index 8062b0328e07d..c893b9fed8a02 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -4005,8 +4005,9 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
/* level 257 SMB_ */
TRANSACTION2_FFIRST_REQ *pSMB = NULL;
TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
- T2_FFIRST_RSP_PARMS *parms;
+ unsigned int data_off, data_count;
struct nls_table *nls_codepage;
+ T2_FFIRST_RSP_PARMS *parms;
unsigned int lnoff;
__u16 params, byte_count;
int bytes_returned = 0;
@@ -4125,11 +4126,19 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
+ data_off = le16_to_cpu(pSMBr->t2.DataOffset);
+ data_count = le16_to_cpu(pSMBr->t2.DataCount);
+ if (data_off + data_count > (unsigned int)bytes_returned) {
+ cifs_dbg(VFS, "%s: data area offset %u count %u past response length %d\n",
+ __func__, data_off, data_count, bytes_returned);
+ cifs_buf_release(pSMB);
+ return -EINVAL;
+ }
+
psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE);
psrch_inf->ntwrk_buf_start = (char *)pSMBr;
psrch_inf->smallBuf = false;
- psrch_inf->srch_entries_start = (char *)&pSMBr->hdr.Protocol +
- le16_to_cpu(pSMBr->t2.DataOffset);
+ psrch_inf->srch_entries_start = (char *)&pSMBr->hdr.Protocol + data_off;
parms = (T2_FFIRST_RSP_PARMS *)((char *)&pSMBr->hdr.Protocol +
le16_to_cpu(pSMBr->t2.ParameterOffset));
@@ -4162,8 +4171,9 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
{
TRANSACTION2_FNEXT_REQ *pSMB = NULL;
TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
- T2_FNEXT_RSP_PARMS *parms;
+ unsigned int data_off, data_count;
unsigned int name_len;
+ T2_FNEXT_RSP_PARMS *parms;
unsigned int lnoff;
__u16 params, byte_count;
char *response_data;
@@ -4246,13 +4256,22 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
cifs_buf_release(pSMB);
return rc;
}
+
+ data_off = le16_to_cpu(pSMBr->t2.DataOffset);
+ data_count = le16_to_cpu(pSMBr->t2.DataCount);
+ if (data_off + data_count > (unsigned int)bytes_returned) {
+ cifs_dbg(VFS, "%s: data area offset %u count %u past response length %d\n",
+ __func__, data_off, data_count, bytes_returned);
+ cifs_buf_release(pSMB);
+ return -EINVAL;
+ }
+
/* BB fixme add lock for file (srch_info) struct here */
psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE);
response_data = (char *)&pSMBr->hdr.Protocol +
le16_to_cpu(pSMBr->t2.ParameterOffset);
parms = (T2_FNEXT_RSP_PARMS *)response_data;
- response_data = (char *)&pSMBr->hdr.Protocol +
- le16_to_cpu(pSMBr->t2.DataOffset);
+ response_data = (char *)&pSMBr->hdr.Protocol + data_off;
if (psrch_inf->smallBuf)
cifs_small_buf_release(psrch_inf->ntwrk_buf_start);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 079/670] raid6: add missing vzeroupper to AVX2 code
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (77 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 078/670] smb: client: reject FIND data areas that run past the received response Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 080/670] mm/damon/core: skip applying scheme if region split for quota fails Greg Kroah-Hartman
` (592 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Biggers, Andrew Morton,
Christoph Hellwig, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <ebiggers@kernel.org>
commit 24f1241cdb056fd630e6710a916e0f7c8c910a70 upstream.
Since the AVX2 optimized RAID6 code uses YMM registers, execute vzeroupper
before returning from it. This is needed to avoid degrading the
performance of any later SSE code that may happen to be executed.
Link: https://lore.kernel.org/20260831212308.213855-1-ebiggers@kernel.org
Fixes: 2c935842bdb4 ("lib/raid6: Add AVX2 optimized gen_syndrome functions")
Fixes: 7056741fd9fc ("lib/raid6: Add AVX2 optimized recovery functions")
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: <stable@vger.kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
lib/raid6/avx2.c | 6 ++++++
lib/raid6/recov_avx2.c | 2 ++
2 files changed, 8 insertions(+)
diff --git a/lib/raid6/avx2.c b/lib/raid6/avx2.c
index 059024234dce1..2d03ce97f655d 100644
--- a/lib/raid6/avx2.c
+++ b/lib/raid6/avx2.c
@@ -76,6 +76,7 @@ static void raid6_avx21_gen_syndrome(int disks, size_t bytes, void **ptrs)
}
asm volatile("sfence" : : : "memory");
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -124,6 +125,7 @@ static void raid6_avx21_xor_syndrome(int disks, int start, int stop,
}
asm volatile("sfence" : : : "memory");
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -186,6 +188,7 @@ static void raid6_avx22_gen_syndrome(int disks, size_t bytes, void **ptrs)
}
asm volatile("sfence" : : : "memory");
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -254,6 +257,7 @@ static void raid6_avx22_xor_syndrome(int disks, int start, int stop,
}
asm volatile("sfence" : : : "memory");
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -347,6 +351,7 @@ static void raid6_avx24_gen_syndrome(int disks, size_t bytes, void **ptrs)
}
asm volatile("sfence" : : : "memory");
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -457,6 +462,7 @@ static void raid6_avx24_xor_syndrome(int disks, int start, int stop,
asm volatile("vmovntdq %%ymm14,%0" : "=m" (q[d+96]));
}
asm volatile("sfence" : : : "memory");
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
diff --git a/lib/raid6/recov_avx2.c b/lib/raid6/recov_avx2.c
index 4e8095403ee28..a7fd1ba177f1b 100644
--- a/lib/raid6/recov_avx2.c
+++ b/lib/raid6/recov_avx2.c
@@ -180,6 +180,7 @@ static void raid6_2data_recov_avx2(int disks, size_t bytes, int faila,
#endif
}
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
@@ -297,6 +298,7 @@ static void raid6_datap_recov_avx2(int disks, size_t bytes, int faila,
#endif
}
+ asm volatile("vzeroupper");
kernel_fpu_end();
}
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 080/670] mm/damon/core: skip applying scheme if region split for quota fails
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (78 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 079/670] raid6: add missing vzeroupper to AVX2 code Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 081/670] mm/damon/paddr: respect folio end for DAMOS actions except STAT Greg Kroah-Hartman
` (591 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, SJ Park, Andrew Morton, Usama Arif,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <sj@kernel.org>
[ Upstream commit 90c2fa6adfed7abe0935506a43cdff3a05c1fff0 ]
Patch series "mm/damon: fix DAMOS bugs in core, paddr and vaddr".
Fix misc bugs of DAMOS. Patch 1 makes DAMOS less stress memory allocator
under extreme situation. Patches 2 and 3 fix wrong folios walking in
DAMON_PADDR. Patches 4 and 5 fix wrong folios walking in DAMON_VADDR.
Patches 6-8 handle extreme and unlikely memory situations that can cause
divide by zero and underflow.
All bugs are discovered by Sashiko.
This patch (of 8):
damos_apply_scheme() splits a region and apply the action to the subregion
if it is needed for not violating the quota. The split operation
(damon_split_region_at()) could fail for allocation failure. In the case,
the quota could be violated. From the user's perspective, DAMOS becomes
more aggressive than expected under the extreme situation. Handle the
failure.
The user impact is not critical. The failure of damon_split_region_at()
is unlikely since it is arguably too small to fail. Also DAMOS being
aggressive is limited to the single region. Users can set min_nr_regions
to set the maximum size of each region. If it is reasonably set, the
transient overhead shouldn't be critical.
The issue was discovered [1] by Sashiko.
6.12.y porting notes. Modify damon_split_region_at() to return
failures. It is a part of commit c60874860762 ("mm/damon/core: handle
region split failure in apply_min_nr_regions()"). Without it, build
fails.
Link: https://lore.kernel.org/20260901131850.98037-1-sj@kernel.org
Link: https://lore.kernel.org/20260901131850.98037-2-sj@kernel.org
Link: https://lore.kernel.org/20260718171523.87547-1-sj@kernel.org [1]
Fixes: 2b8a248d5873 ("mm/damon/schemes: implement size quota for schemes application speed control")
Signed-off-by: SJ Park <sj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Usama Arif <usamaarif642@gmail.com>
Cc: <stable@vger.kernel.org> # 5.16.x
Signed-off-by: SJ Park <sj@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/damon/core.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 3142776e2e0ee..200cadceed148 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1274,7 +1274,7 @@ static void kdamond_reset_aggregated(struct damon_ctx *c)
}
}
-static void damon_split_region_at(struct damon_target *t,
+static int damon_split_region_at(struct damon_target *t,
struct damon_region *r, unsigned long sz_r);
static bool __damos_valid_target(struct damon_region *r, struct damos *s)
@@ -1478,7 +1478,8 @@ static void damos_apply_scheme(struct damon_ctx *c, struct damon_target *t,
DAMON_MIN_REGION);
if (!sz)
goto update_stat;
- damon_split_region_at(t, r, sz);
+ if (damon_split_region_at(t, r, sz))
+ goto update_stat;
}
if (damos_filter_out(c, t, r, s))
return;
@@ -1870,15 +1871,17 @@ static void kdamond_merge_regions(struct damon_ctx *c, unsigned int threshold,
*
* r the region to be split
* sz_r size of the first sub-region that will be made
+ *
+ * Return: 0 on success, negative error code otherwise.
*/
-static void damon_split_region_at(struct damon_target *t,
+static int damon_split_region_at(struct damon_target *t,
struct damon_region *r, unsigned long sz_r)
{
struct damon_region *new;
new = damon_new_region(r->ar.start + sz_r, r->ar.end);
if (!new)
- return;
+ return -ENOMEM;
r->ar.end = new->ar.start;
@@ -1888,6 +1891,7 @@ static void damon_split_region_at(struct damon_target *t,
new->nr_accesses = r->nr_accesses;
damon_insert_region(new, r, damon_next_region(r), t);
+ return 0;
}
/* Split every region in the given target into 'nr_subs' regions */
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 081/670] mm/damon/paddr: respect folio end for DAMOS actions except STAT
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (79 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 080/670] mm/damon/core: skip applying scheme if region split for quota fails Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 082/670] mm/damon/core: filter out damos address filter-split failed region Greg Kroah-Hartman
` (590 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, SJ Park, Andrew Morton, Usama Arif,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <sj@kernel.org>
[ Upstream commit 1613ac9edf385c35f171a25610e2706a7e6afad6 ]
A few functions for applying DAMOS actions including pageout, lru_[de]prio
and migrate_{hot,cold} in DAMON physical address space operation set
(paddr) collect folios of the given region by getting the folios of
region-internal addresses. Then, those functions apply the action to the
collected folios at once. The collection starts from the region start
address and advances the address by the size of the folio of the address
until it goes out of the region. If the start address is in the middle of
a large folio, and if the next folios are small, some of the next folios
could be skipped. Fix the issue by advancing the address to exactly the
start address of the next folio.
The user impact is that DAMOS action is applied to less than expected
amount of memory. Given the best effort nature of DAMON, it is no big
problem, but it is clearly a bug that is better to be fixed.
The issue was discovered [1] by Sashiko.
Link: https://lore.kernel.org/20260901131850.98037-4-sj@kernel.org
Link: https://lore.kernel.org/20260517234112.89245-1-sj@kernel.org [1]
Fixes: 3a06696305e7 ("mm/damon/ops: have damon_get_folio return folio even for tail pages")
Signed-off-by: SJ Park <sj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Usama Arif <usamaarif642@gmail.com>
Cc: <stable@vger.kernel.org> # 6.15.x
(cherry picked from commit 1613ac9edf385c35f171a25610e2706a7e6afad6)
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/damon/paddr.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
index a6b1de97b1e8a..6bac269cd679e 100644
--- a/mm/damon/paddr.c
+++ b/mm/damon/paddr.c
@@ -273,7 +273,7 @@ static unsigned long damon_pa_pageout(struct damon_region *r, struct damos *s)
else
list_add(&folio->lru, &folio_list);
put_folio:
- addr += folio_size(folio);
+ addr = PFN_PHYS(folio_pfn(folio)) + folio_size(folio);
folio_put(folio);
}
if (install_young_filter)
@@ -306,7 +306,7 @@ static inline unsigned long damon_pa_mark_accessed_or_deactivate(
folio_deactivate(folio);
applied += folio_nr_pages(folio);
put_folio:
- addr += folio_size(folio);
+ addr = PFN_PHYS(folio_pfn(folio)) + folio_size(folio);
folio_put(folio);
}
return applied * PAGE_SIZE;
@@ -483,7 +483,7 @@ static unsigned long damon_pa_migrate(struct damon_region *r, struct damos *s)
folio_is_file_lru(folio));
list_add(&folio->lru, &folio_list);
put_folio:
- addr += folio_size(folio);
+ addr = PFN_PHYS(folio_pfn(folio)) + folio_size(folio);
folio_put(folio);
}
applied = damon_pa_migrate_pages(&folio_list, s->target_nid);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 082/670] mm/damon/core: filter out damos address filter-split failed region
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (80 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 081/670] mm/damon/paddr: respect folio end for DAMOS actions except STAT Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 083/670] mm/damon/core: remove unreachable damos charge_{target,addr}_from Greg Kroah-Hartman
` (589 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, SJ Park, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <sj@kernel.org>
[ Upstream commit bbeec2d8324d7aac438bb12dd2d22b184e0a8d43 ]
When an address type DAMOS filter is configured, DAMOS tries to split the
region for the filter range, and apply DAMOS action to the filter-in
region. The split operation (damon_split_region_at()) could fail from
allocation failure under extreme memory pressure. In the case, DAMOS
action could be applied more or less than expected, ignoring the address
filter.
The issue only rarely happens under extreme memory pressure. No crash or
leak happens. Occasionally not applying the action to a few regions
shouldn't be a real problem. But applying the action to a region that the
user has excluded via address filter could be a surprise depending on the
use case. It is only theoretical. No such real case is found yet.
Filter out the entire region if the split is failed. Update
damos_filter_match() signature to receive the error from split. Also
update kunit tests for the updated signature.
The issue was discovered [1] by sashiko.
Link: https://lore.kernel.org/20261020004119.106690-1-sj@kernel.org
Link: https://lore.kernel.org/20260801203121.117449-1-sj@kernel.org [1]
Fixes: ab9bda001b68 ("mm/damon/core: introduce address range type damos filter")
Signed-off-by: SJ Park <sj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: <stable@vger.kernel.org> # 6.6.x
Signed-off-by: SJ Park <sj@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/damon/core.c | 13 +++++++++----
mm/damon/tests/core-kunit.h | 11 ++++++-----
2 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 200cadceed148..7e64b2959bd01 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1377,13 +1377,14 @@ static void damos_update_stat(struct damos *s,
}
static bool __damos_filter_out(struct damon_ctx *ctx, struct damon_target *t,
- struct damon_region *r, struct damos_filter *filter)
+ struct damon_region *r, struct damos_filter *filter, int *err)
{
bool matched = false;
struct damon_target *ti;
int target_idx = 0;
unsigned long start, end;
+ *err = 0;
switch (filter->type) {
case DAMOS_FILTER_TYPE_TARGET:
damon_for_each_target(ti, ctx) {
@@ -1409,12 +1410,13 @@ static bool __damos_filter_out(struct damon_ctx *ctx, struct damon_target *t,
}
/* start before the range and overlap */
if (r->ar.start < start) {
- damon_split_region_at(t, r, start - r->ar.start);
+ *err = damon_split_region_at(t, r,
+ start - r->ar.start);
matched = false;
break;
}
/* start inside the range */
- damon_split_region_at(t, r, end - r->ar.start);
+ *err = damon_split_region_at(t, r, end - r->ar.start);
matched = true;
break;
default:
@@ -1428,9 +1430,12 @@ static bool damos_filter_out(struct damon_ctx *ctx, struct damon_target *t,
struct damon_region *r, struct damos *s)
{
struct damos_filter *filter;
+ bool matching;
+ int err;
damos_for_each_filter(filter, s) {
- if (__damos_filter_out(ctx, t, r, filter))
+ matching = __damos_filter_out(ctx, t, r, filter, &err);
+ if (matching || err)
return true;
}
return false;
diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h
index ff9f73579f7b3..6b7cd8149a0e2 100644
--- a/mm/damon/tests/core-kunit.h
+++ b/mm/damon/tests/core-kunit.h
@@ -527,6 +527,7 @@ static void damos_test_filter_out(struct kunit *test)
struct damon_target *t;
struct damon_region *r, *r2;
struct damos_filter *f;
+ int err;
f = damos_new_filter(DAMOS_FILTER_TYPE_ADDR, true);
f->addr_range = (struct damon_addr_range){
@@ -537,25 +538,25 @@ static void damos_test_filter_out(struct kunit *test)
damon_add_region(r, t);
/* region in the range */
- KUNIT_EXPECT_TRUE(test, __damos_filter_out(NULL, t, r, f));
+ KUNIT_EXPECT_TRUE(test, __damos_filter_out(NULL, t, r, f, &err));
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1);
/* region before the range */
r->ar.start = DAMON_MIN_REGION * 1;
r->ar.end = DAMON_MIN_REGION * 2;
- KUNIT_EXPECT_FALSE(test, __damos_filter_out(NULL, t, r, f));
+ KUNIT_EXPECT_FALSE(test, __damos_filter_out(NULL, t, r, f, &err));
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1);
/* region after the range */
r->ar.start = DAMON_MIN_REGION * 6;
r->ar.end = DAMON_MIN_REGION * 8;
- KUNIT_EXPECT_FALSE(test, __damos_filter_out(NULL, t, r, f));
+ KUNIT_EXPECT_FALSE(test, __damos_filter_out(NULL, t, r, f, &err));
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1);
/* region started before the range */
r->ar.start = DAMON_MIN_REGION * 1;
r->ar.end = DAMON_MIN_REGION * 4;
- KUNIT_EXPECT_FALSE(test, __damos_filter_out(NULL, t, r, f));
+ KUNIT_EXPECT_FALSE(test, __damos_filter_out(NULL, t, r, f, &err));
/* filter should have split the region */
KUNIT_EXPECT_EQ(test, r->ar.start, DAMON_MIN_REGION * 1);
KUNIT_EXPECT_EQ(test, r->ar.end, DAMON_MIN_REGION * 2);
@@ -570,7 +571,7 @@ static void damos_test_filter_out(struct kunit *test)
/* region started in the range */
r->ar.start = DAMON_MIN_REGION * 2;
r->ar.end = DAMON_MIN_REGION * 8;
- KUNIT_EXPECT_TRUE(test, __damos_filter_out(NULL, t, r, f));
+ KUNIT_EXPECT_TRUE(test, __damos_filter_out(NULL, t, r, f, &err));
/* filter should have split the region */
KUNIT_EXPECT_EQ(test, r->ar.start, DAMON_MIN_REGION * 2);
KUNIT_EXPECT_EQ(test, r->ar.end, DAMON_MIN_REGION * 6);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 083/670] mm/damon/core: remove unreachable damos charge_{target,addr}_from
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (81 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 082/670] mm/damon/core: filter out damos address filter-split failed region Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 084/670] xfs: reduce new btree slack factor if free space is negative Greg Kroah-Hartman
` (588 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, SJ Park, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <sj@kernel.org>
[ Upstream commit 5695abc4e742b947f586bfb6a080a80ad9957e5d ]
damos_quota->charge_{target,addr}_from saves the target and region the
scheme's quota limit is reached. damos_skip_charged_region() skips the
target and regions before the point. The target that was assigned to
charge_target_from could be dynamically removed from the context by the
runtime parameters update (aka commit) feature. In this case,
damos_skip_charged_region() cannot find if the point is passed or not,
so the scheme is effectively disabled.
Similarly, the user could also remove all the regions of the target
using the runtime parameters update feature. It would be uncommon to do
that, but it is a supported feature. Because the skip pointer detection
logic (damos_skip_charged_region()) works for each region of targets,
this result in the logic is entirely skipped and the scheme is
effectively disabled again.
The user impact is that the DAMOS scheme could suddenly stop working
under certain uses of the runtime parameters update feature. It could
surprise users. No crash or leak happens though. Users could also
simply work around by re-installing the scheme.
Catch the corner cases in damos_adjust_quota() and reset the pointers.
Link: https://lore.kernel.org/20261020023958.108276-1-sj@kernel.org
Fixes: da87878010e5 ("mm/damon/sysfs: support online inputs update")
Signed-off-by: SJ Park <sj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Closes: https://sashiko.dev/#/bug/linux-cd0c55fc-0cc8-45d8-9637-3334811c49b8
Cc: <stable@vger.kernel.org> # 5.19.x
Signed-off-by: SJ Park <sj@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/damon/core.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 7e64b2959bd01..fc4f9aa0a3620 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1687,6 +1687,26 @@ static void damos_set_effective_quota(struct damos_quota *quota)
quota->esz = esz;
}
+static void damos_fix_stale_charge_pointers(struct damon_ctx *c,
+ struct damos *s)
+{
+ struct damos_quota *quota;
+ struct damon_target *t;
+
+ quota = &s->quota;
+ if (!quota->charge_target_from)
+ return;
+ damon_for_each_target(t, c) {
+ if (t == quota->charge_target_from) {
+ if (damon_nr_regions(t) > 0)
+ return;
+ break;
+ }
+ }
+ quota->charge_target_from = NULL;
+ quota->charge_addr_from = 0;
+}
+
static void damos_adjust_quota(struct damon_ctx *c, struct damos *s)
{
struct damos_quota *quota = &s->quota;
@@ -1715,6 +1735,8 @@ static void damos_adjust_quota(struct damon_ctx *c, struct damos *s)
damos_set_effective_quota(quota);
}
+ damos_fix_stale_charge_pointers(c, s);
+
if (!c->ops.get_scheme_score)
return;
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 084/670] xfs: reduce new btree slack factor if free space is negative
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (82 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 083/670] mm/damon/core: remove unreachable damos charge_{target,addr}_from Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 085/670] mtd: rawnand: ndfc: use ioread32be/iowrite32be and allow COMPILE_TEST Greg Kroah-Hartman
` (587 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit 80f13dc7225eec318da7499c7a562d7a34d25e6a ]
LOLLM points out that if the incore fdblocks counter is negative, the
assignment to uint64_t will mask this possibly low space situation and
we don't pack the btree blocks as tightly as we probably ought to. If
it's the case that there's some free space and fdblocks is too low due
to an error in the superblock field, then we can end up failing btree
rebuilds due to ENOSPC unnecessarily. This is a corner case, but let's
fix it anyway.
Cc: stable@vger.kernel.org # v6.8
Fixes: be408417630427 ("xfs: implement block reservation accounting for btrees we're staging")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
[ sashal: Replaced upstream’s xfs_sum_freecounter() call with percpu_counter_sum_positive() on m_fdblocks to match the existing counter API. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/newbt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/xfs/scrub/newbt.c b/fs/xfs/scrub/newbt.c
index b818d9b215788..80f9bf7e399b4 100644
--- a/fs/xfs/scrub/newbt.c
+++ b/fs/xfs/scrub/newbt.c
@@ -60,7 +60,7 @@ xrep_newbt_estimate_slack(
free = sc->sa.pag->pagf_freeblks;
sz = xfs_ag_block_count(sc->mp, sc->sa.pag->pag_agno);
} else {
- free = percpu_counter_sum(&sc->mp->m_fdblocks);
+ free = percpu_counter_sum_positive(&sc->mp->m_fdblocks);
sz = sc->mp->m_sb.sb_dblocks;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 085/670] mtd: rawnand: ndfc: use ioread32be/iowrite32be and allow COMPILE_TEST
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (83 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 084/670] xfs: reduce new btree slack factor if free space is negative Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 086/670] mtd: rawnand: ndfc: add CONFIG_OF dependency Greg Kroah-Hartman
` (586 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Rosen Penev, Miquel Raynal,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <rosenp@gmail.com>
[ Upstream commit 4f2692a5383e4bdd43ae940cda012360f7217a2d ]
Replace ppc4xx-specific in_be32/out_be32 with generic ioread32be/
iowrite32be to make the driver portable. Add COMPILE_TEST dependency
to get build coverage on non-ppc4xx architectures.
While at it, replace 4xx with 44x. The latter was removed a while ago
and is only kept for compatibility.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/mtd/nand/raw/Kconfig | 2 +-
drivers/mtd/nand/raw/ndfc.c | 20 ++++++++++----------
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index d0aaccf72d781..0c39b4f346a69 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -71,7 +71,7 @@ config MTD_NAND_AU1550
config MTD_NAND_NDFC
tristate "IBM/MCC 4xx NAND controller"
- depends on 4xx
+ depends on 44x || COMPILE_TEST
select MTD_NAND_ECC_SW_HAMMING
select MTD_NAND_ECC_SW_HAMMING_SMC
help
diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c
index 3bb32a7c6d679..29198c4af5e6d 100644
--- a/drivers/mtd/nand/raw/ndfc.c
+++ b/drivers/mtd/nand/raw/ndfc.c
@@ -44,13 +44,13 @@ static void ndfc_select_chip(struct nand_chip *nchip, int chip)
uint32_t ccr;
struct ndfc_controller *ndfc = nand_get_controller_data(nchip);
- ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
+ ccr = ioread32be(ndfc->ndfcbase + NDFC_CCR);
if (chip >= 0) {
ccr &= ~NDFC_CCR_BS_MASK;
ccr |= NDFC_CCR_BS(chip + ndfc->chip_select);
} else
ccr |= NDFC_CCR_RESET_CE;
- out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
+ iowrite32be(ccr, ndfc->ndfcbase + NDFC_CCR);
}
static void ndfc_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl)
@@ -70,7 +70,7 @@ static int ndfc_ready(struct nand_chip *chip)
{
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
- return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
+ return ioread32be(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
}
static void ndfc_enable_hwecc(struct nand_chip *chip, int mode)
@@ -78,9 +78,9 @@ static void ndfc_enable_hwecc(struct nand_chip *chip, int mode)
uint32_t ccr;
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
- ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
+ ccr = ioread32be(ndfc->ndfcbase + NDFC_CCR);
ccr |= NDFC_CCR_RESET_ECC;
- out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
+ iowrite32be(ccr, ndfc->ndfcbase + NDFC_CCR);
wmb();
}
@@ -92,7 +92,7 @@ static int ndfc_calculate_ecc(struct nand_chip *chip,
uint8_t *p = (uint8_t *)&ecc;
wmb();
- ecc = in_be32(ndfc->ndfcbase + NDFC_ECC);
+ ecc = ioread32be(ndfc->ndfcbase + NDFC_ECC);
/* The NDFC uses Smart Media (SMC) bytes order */
ecc_code[0] = p[1];
ecc_code[1] = p[2];
@@ -114,7 +114,7 @@ static void ndfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
- *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA);
+ *p++ = ioread32be(ndfc->ndfcbase + NDFC_DATA);
}
static void ndfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
@@ -123,7 +123,7 @@ static void ndfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
- out_be32(ndfc->ndfcbase + NDFC_DATA, *p++);
+ iowrite32be(*p++, ndfc->ndfcbase + NDFC_DATA);
}
/*
@@ -223,13 +223,13 @@ static int ndfc_probe(struct platform_device *ofdev)
if (reg)
ccr |= be32_to_cpup(reg);
- out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
+ iowrite32be(ccr, ndfc->ndfcbase + NDFC_CCR);
/* Set the bank settings if given */
reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL);
if (reg) {
int offset = NDFC_BCFG0 + (ndfc->chip_select << 2);
- out_be32(ndfc->ndfcbase + offset, be32_to_cpup(reg));
+ iowrite32be(be32_to_cpup(reg), ndfc->ndfcbase + offset);
}
err = ndfc_chip_init(ndfc, ofdev->dev.of_node);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 086/670] mtd: rawnand: ndfc: add CONFIG_OF dependency
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (84 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 085/670] mtd: rawnand: ndfc: use ioread32be/iowrite32be and allow COMPILE_TEST Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 087/670] mtd: rawnand: ndfc: fix gcc uninitialized var Greg Kroah-Hartman
` (585 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Arnd Bergmann, Rosen Penev,
Miquel Raynal, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnd Bergmann <arnd@arndb.de>
[ Upstream commit 97f9e509d839f7e5b9a32105ae322e5223c86786 ]
When compile-testing on x86 without CONFIG_OF, the ndfc driver produces
a harmless warning:
drivers/mtd/nand/raw/ndfc.c: In function 'ndfc_probe':
include/linux/dev_printk.h:154:31: error: 'len' is used uninitialized [-Werror=uninitialized]
154 | dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
| ^
drivers/mtd/nand/raw/ndfc.c:196:17: note: in expansion of macro 'dev_err'
196 | dev_err(&ofdev->dev, "unable read reg property (%d)\n", len);
Limit compile-testing to configurations with CONFIG_OF to trivially
avoid this. The driver will still be built in allmodconfig and many
randconfig builds.
Fixes: 4f2692a5383e ("mtd: rawnand: ndfc: use ioread32be/iowrite32be and allow COMPILE_TEST")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Rosen Penev <rosenp@gmail.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/mtd/nand/raw/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 0c39b4f346a69..91fae26a3d91d 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -72,6 +72,7 @@ config MTD_NAND_AU1550
config MTD_NAND_NDFC
tristate "IBM/MCC 4xx NAND controller"
depends on 44x || COMPILE_TEST
+ depends on OF
select MTD_NAND_ECC_SW_HAMMING
select MTD_NAND_ECC_SW_HAMMING_SMC
help
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 087/670] mtd: rawnand: ndfc: fix gcc uninitialized var
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (85 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 086/670] mtd: rawnand: ndfc: add CONFIG_OF dependency Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 088/670] mtd: rawnand: ndfc: use devm_platform_ioremap_resource() Greg Kroah-Hartman
` (584 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, kernel test robot, Rosen Penev,
Miquel Raynal, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <rosenp@gmail.com>
[ Upstream commit cceca8cb776b03e83985578f84bd730c30d57f70 ]
Now that this can be built with COMPILE_TEST, an unassigned variable was
found. Set to 0 to fix the W=1 error under GCC.
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202606141301.iyVdFgl7-lkp@intel.com/
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/mtd/nand/raw/ndfc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c
index 29198c4af5e6d..a2e2238339ec1 100644
--- a/drivers/mtd/nand/raw/ndfc.c
+++ b/drivers/mtd/nand/raw/ndfc.c
@@ -188,7 +188,7 @@ static int ndfc_probe(struct platform_device *ofdev)
const __be32 *reg;
u32 ccr;
u32 cs;
- int err, len;
+ int err, len = 0;
/* Read the reg property to get the chip select */
reg = of_get_property(ofdev->dev.of_node, "reg", &len);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 088/670] mtd: rawnand: ndfc: use devm_platform_ioremap_resource()
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (86 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 087/670] mtd: rawnand: ndfc: fix gcc uninitialized var Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 089/670] net: bgmac: enable interrupts only after NAPI is ready Greg Kroah-Hartman
` (583 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Rosen Penev, Miquel Raynal,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <rosenp@gmail.com>
[ Upstream commit 0d66f9895f286d2fab396a71e6efeb95c4a7e5a6 ]
Replace the open-coded of_iomap()/iounmap() with the managed
devm_platform_ioremap_resource() helper. This fixes a mapping leak on
driver remove (the old code never called iounmap()) and simplifies the
error path by dropping the manual cleanup in ndfc_probe().
There is no overlapping memory-region concern introduced by this
change: each supported board DT describes a single ndfc node with a
unique 0x2000 register region, and the EBC parent uses dcr-reg rather
than a MEM reg resource, so the newly added request_mem_region() cannot
conflict with an existing reservation. Distinct chip selects map to
distinct 64-bit physical addresses, so CS instances do not overlap.
Fixes: a808ad3b0d28 ("[MTD] [NAND] ndfc driver")
Cc: stable@vger.kernel.org
Assisted-by: opencode:hy3-free
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/mtd/nand/raw/ndfc.c | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c
index a2e2238339ec1..677d05d628a5f 100644
--- a/drivers/mtd/nand/raw/ndfc.c
+++ b/drivers/mtd/nand/raw/ndfc.c
@@ -185,10 +185,15 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
static int ndfc_probe(struct platform_device *ofdev)
{
struct ndfc_controller *ndfc;
+ void __iomem *ndfcbase;
const __be32 *reg;
u32 ccr;
u32 cs;
- int err, len = 0;
+ int len = 0;
+
+ ndfcbase = devm_platform_ioremap_resource(ofdev, 0);
+ if (IS_ERR(ndfcbase))
+ return PTR_ERR(ndfcbase);
/* Read the reg property to get the chip select */
reg = of_get_property(ofdev->dev.of_node, "reg", &len);
@@ -210,11 +215,7 @@ static int ndfc_probe(struct platform_device *ofdev)
ndfc->ofdev = ofdev;
dev_set_drvdata(&ofdev->dev, ndfc);
- ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0);
- if (!ndfc->ndfcbase) {
- dev_err(&ofdev->dev, "failed to get memory\n");
- return -EIO;
- }
+ ndfc->ndfcbase = ndfcbase;
ccr = NDFC_CCR_BS(ndfc->chip_select);
@@ -232,13 +233,7 @@ static int ndfc_probe(struct platform_device *ofdev)
iowrite32be(be32_to_cpup(reg), ndfc->ndfcbase + offset);
}
- err = ndfc_chip_init(ndfc, ofdev->dev.of_node);
- if (err) {
- iounmap(ndfc->ndfcbase);
- return err;
- }
-
- return 0;
+ return ndfc_chip_init(ndfc, ofdev->dev.of_node);
}
static void ndfc_remove(struct platform_device *ofdev)
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 089/670] net: bgmac: enable interrupts only after NAPI is ready
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (87 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 088/670] mtd: rawnand: ndfc: use devm_platform_ioremap_resource() Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 090/670] nfsd: shorten extack string returned with dodgy listener Greg Kroah-Hartman
` (582 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Rosen Penev, Daniel Machon,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <rosenp@gmail.com>
[ Upstream commit ac1f6e58cb77bb66b8811f7d98703e0f076a8f65 ]
bgmac_open() calls bgmac_chip_init(), which unmasks the interrupts and
enables the MAC receiver, before request_irq() and napi_enable().
bgmac_enet_resume() also enables NAPI only after bgmac_chip_init().
When frames arrive in that window, the first RX interrupt masks all
interrupts in bgmac_interrupt() and calls napi_schedule() on a NAPI
instance that is still disabled, so nothing is scheduled. Nothing
unmasks the interrupts again, the RX ring fills up and the interface
stays deaf until it is brought down and up without traffic.
On an Asus RT-N16 (BCM4716) a single "ip link set eth0 down/up" while
a host sends UDP to the router left INT_MASK at 0, INT_STATUS with RX
pending and the RX DMA idle on a full ring, with the RX packet and
interrupt counters no longer moving. With this change, 10 of 10 such
cycles recovered on their own.
Request the IRQ and enable NAPI before the chip is initialized.
Fixes: dd4544f05469 ("bgmac: driver for GBit MAC core on BCMA bus")
Fixes: f3537b3494c0 ("net: ethernet: bgmac: driver power manangement")
Cc: stable@vger.kernel.org
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Reviewed-by: Daniel Machon <daniel.machon@microchip.com>
Link: https://patch.msgid.link/20261010070011.60403-1-rosenp@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/broadcom/bgmac.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index 6ffdc42294074..258b3b5a1cdb7 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -1183,9 +1183,6 @@ static int bgmac_open(struct net_device *net_dev)
if (err)
return err;
- /* Specs say about reclaiming rings here, but we do that in DMA init */
- bgmac_chip_init(bgmac);
-
err = request_irq(bgmac->irq, bgmac_interrupt, IRQF_SHARED,
net_dev->name, net_dev);
if (err < 0) {
@@ -1195,6 +1192,9 @@ static int bgmac_open(struct net_device *net_dev)
}
napi_enable(&bgmac->napi);
+ /* Specs say about reclaiming rings here, but we do that in DMA init */
+ bgmac_chip_init(bgmac);
+
phy_start(net_dev->phydev);
netif_start_queue(net_dev);
@@ -1609,10 +1609,10 @@ int bgmac_enet_resume(struct bgmac *bgmac)
if (rc)
return rc;
- bgmac_chip_init(bgmac);
-
napi_enable(&bgmac->napi);
+ bgmac_chip_init(bgmac);
+
netif_tx_lock(bgmac->net_dev);
netif_device_attach(bgmac->net_dev);
netif_tx_unlock(bgmac->net_dev);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 090/670] nfsd: shorten extack string returned with dodgy listener
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (88 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 089/670] net: bgmac: enable interrupts only after NAPI is ready Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 091/670] s390/vmcp: Initialize full session info to zero Greg Kroah-Hartman
` (581 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeff Layton, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <jlayton@kernel.org>
[ Upstream commit 8d7859d165dbdf6e8d77b76500fc990f26c8310d ]
The kernel test robot reports:
>> fs/nfsd/nfsctl.c:2253:4: warning: 'snprintf' will always be truncated; specified size is 80, but format string expands to at least 94 [-Wformat-truncation]
Shorten the extack string in this case so that it will fit in 80 chars.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260904-nfsd-nl-hang-v1-1-8c8035b6294d@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfsctl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 6ca903922fe9b..f2e1079bd0437 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -2269,7 +2269,7 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
bad_xprt);
else if (skipped_rpcb)
NL_SET_ERR_MSG_FMT(info->extack,
- "cannot create %s listener; rpcbind did not answer earlier, so some listeners are not registered",
+ "cannot create %s listener; rpcbind did not answer earlier",
bad_xprt);
else
NL_SET_ERR_MSG_FMT(info->extack,
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 091/670] s390/vmcp: Initialize full session info to zero
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (89 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 090/670] nfsd: shorten extack string returned with dodgy listener Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 092/670] PCI: Add enable_device() and disable_device() callbacks for bridges Greg Kroah-Hartman
` (580 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Borntraeger,
Heiko Carstens, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Borntraeger <borntraeger@linux.ibm.com>
[ Upstream commit f63eb4ee4a30fc5d8de07a229d92310e3c8d560c ]
The cma_alloc bit as well as the response can contain old data.
cma_release will not free the kmalloced memory in that case and
the response code might leak kernel stack data to CAP_SYS_ADMIN
users.
Cc: stable@vger.kernel.org
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
[borntraeger@linux.ibm.com: use kzalloc instead of kzalloc_obj for older versions]
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/s390/char/vmcp.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index c6d58335beb47..4fdc3f1dc8db3 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -105,13 +105,11 @@ static int vmcp_open(struct inode *inode, struct file *file)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- session = kmalloc(sizeof(*session), GFP_KERNEL);
+ session = kzalloc(sizeof(*session), GFP_KERNEL);
if (!session)
return -ENOMEM;
session->bufsize = PAGE_SIZE;
- session->response = NULL;
- session->resp_size = 0;
mutex_init(&session->mutex);
file->private_data = session;
return nonseekable_open(inode, file);
--
2.53.0
^ permalink raw reply related [flat|nested] 673+ messages in thread* [PATCH 6.12 092/670] PCI: Add enable_device() and disable_device() callbacks for bridges
2026-11-13 15:42 [PATCH 6.12 000/670] 6.12.118-rc1 review Greg Kroah-Hartman
` (90 preceding siblings ...)
2026-11-13 15:44 ` [PATCH 6.12 091/670] s390/vmcp: Initialize full session info to zero Greg Kroah-Hartman
@ 2026-11-13 15:44 ` Greg Kroah-Hartman
2026-11-13 15:44 ` [PATCH 6.12 093/670] PCI: rcar-gen4: Limit Max_Read_Request_Size to 256 Bytes Greg Kroah-Hartman
` (579 subsequent siblings)
671 siblings, 0 replies; 673+ messages in thread
From: Greg Kroah-Hartman @ 2026-11-13 15:44 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Marc Zyngier, Frank Li,
Bjorn Helgaas, Krzysztof Wilczyński, Manivannan Sadhasivam,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frank Li <Frank.Li@nxp.com>
[ Upstream commit a3751212a8eeece59d2018c455000f30ed7e5bb7 ]
Some PCI host bridges require special handling when enabling or
disabling PCI devices. For example, the i.MX95 platform has a lookup
table to map Requester IDs to StreamIDs, which the SMMU and MSI
controller use to identify the source of DMA accesses.
Without this mapping, DMA accesses may target unintended memory, which
would corrupt memory or read the wrong data.
Add a host bridge enable_device() hook the imx6 driver can use to
configure the Requester ID to StreamID mapping. The hardware table isn't
big enough to map all possible Requester IDs, so this hook may fail if
no table space is available. In that case, return failure from
pci_enable_device().
It might make more sense to make pci_set_master() decline to enable bus
mastering and return failure, but it currently doesn't have a way to return
failure.
Link: https://lore.kernel.org/r/20250114-imx95_lut-v9-1-39f58dbed03a@nxp.com
Tested-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
[kwilczynski: commit log]
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
Reviewed-by: Marc Zyngier <maz@kernel.org>
Acked-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pci/pci.c | 36 +++++++++++++++++++++++++++++++++++-
include/linux/pci.h | 2 ++
2 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2f575af94e094..b53ee0920bdcf 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2090,6 +2090,28 @@ int __weak pcibios_enable_device(struct pci_dev *dev, int bars)
return pci_enable_resources(dev, bars);
}
+static int pci_host_bridge_enable_device(struct pci_dev *dev)
+{
+ struct pci_host_bridge *host_bridge = pci_find_host_bridge(dev->bus);
+ int err;
+
+ if (host_bridge && host_bridge->enable_device) {
+ err = host_bridge->enable_device(host_bridge, dev);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static void pci_host_bridge_disable_device(struct pci_dev *dev)
+{
+ struct pci_host_bridge *host_bridge = pci_find_host_bridge(dev->bus);
+
+ if (host_bridge && host_bridge->disable_device)
+ host_bridge->disable_device(host_bridge, dev);
+}
+
static int do_pci_enable_device(struct pci_dev *dev, int bars)
{
int err;
@@ -2105,9 +2127,13 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
if (bridge)
pcie_aspm_powersave_config_link(bridge);
+ err = pci_host_bridge_enable_device(dev);
+ if (err)
+ return err;
+
err = pcibios_enable_device(dev, bars);
if (err < 0)
- return err;
+ goto err_enable;
pci_fixup_device(pci_fixup_enable, dev);
if (dev->msi_enabled || dev->msix_enabled)
@@ -2122,6 +2148,12 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
}
return 0;
+
+err_enable:
+ pci_host_bridge_disable_device(dev);
+
+ return err;
+
}
/**
@@ -2305,6 +2337,8 @@ void pci_disable_device(struct pci_dev *dev)
if (atomic_dec_return(&dev->enable_cnt) != 0)
return;
+ pci_host_bridge_disable_device(dev);
+
do_pci_disable_device(dev);
dev->is_busmaster = 0;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index c65de9e8aa8af..63c24b5bdce56 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -602,6 +602,8 @@ struct pci_host_bridge {
u8 (*swizzle_irq)(struct pci_dev *, u8 *); /* Platform IRQ swizzler */