* Re: [PATCH v4 1/8] media: virtio: Add protocol
From: Mauro Carvalho Chehab @ 2026-07-12 7:28 UTC (permalink / raw)
To: Brian Daniels
Cc: Mauro Carvalho Chehab, acourbot, adelva, aesteve, changyeon,
daniel.almeida, eperezma, gnurou, gurchetansingh, hverkuil,
jasowang, linux-kernel, linux-media, mst, nicolas.dufresne,
virtualization, xuanzhuo
In-Reply-To: <20260622204343.1994418-2-briandaniels@google.com>
On Mon, 22 Jun 2026 16:43:36 -0400
Brian Daniels <briandaniels@google.com> wrote:
> From: Alexandre Courbot <gnurou@gmail.com>
>
> Add the identifiers and structs used to implement the virtio interface
> as described in section 5.22 of version 1.4 of the virtio spec:
>
> https://docs.oasis-open.org/virtio/virtio/v1.4/csprd01/virtio-v1.4-csprd01-diff-from-v1.2-cs01.html#x1-82200022
>
> Signed-off-by: Alexandre Courbot <gnurou@gmail.com>
> Co-developed-by: Brian Daniels <briandaniels@google.com>
> Signed-off-by: Brian Daniels <briandaniels@google.com>
> ---
> drivers/media/virtio/protocol.h | 287 ++++++++++++++++++++++++++++++++
> 1 file changed, 287 insertions(+)
> create mode 100644 drivers/media/virtio/protocol.h
>
> diff --git a/drivers/media/virtio/protocol.h b/drivers/media/virtio/protocol.h
> new file mode 100644
> index 000000000..5878d107c
> --- /dev/null
> +++ b/drivers/media/virtio/protocol.h
> @@ -0,0 +1,287 @@
> +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0+ */
> +
> +/*
> + * Definitions of virtio-media protocol structures.
> + *
> + * Copyright (c) 2024-2025 Google LLC.
> + */
> +
> +#ifndef __VIRTIO_MEDIA_PROTOCOL_H
> +#define __VIRTIO_MEDIA_PROTOCOL_H
> +
> +#include <linux/videodev2.h>
> +#include <linux/bits.h>
> +
> +/*
> + * Virtio protocol definition.
> + */
> +
> +/**
> + * struct virtio_media_cmd_header - Header for all virtio-media commands.
> + * @cmd: one of VIRTIO_MEDIA_CMD_*.
> + * @__reserved: must be set to zero by the driver.
> + *
> + * This header starts all commands from the driver to the device on the
> + * commandq.
> + */
> +struct virtio_media_cmd_header {
> + u32 cmd;
> + u32 __reserved;
> +};
> +
> +/**
> + * struct virtio_media_resp_header - Header for all virtio-media responses.
> + * @status: 0 if the command was successful, or one of the standard Linux error
> + * codes.
> + * @__reserved: must be set to zero by the device.
> + *
> + * This header starts all responses from the device to the driver on the
> + * commandq.
> + */
> +struct virtio_media_resp_header {
> + u32 status;
> + u32 __reserved;
> +};
> +
> +/**
> + * VIRTIO_MEDIA_CMD_OPEN - Command for creating a new session.
> + *
> + * This is the equivalent of calling `open` on a V4L2 device node. Upon
> + * success, a session id is returned which can be used to perform other
> + * commands on the session, notably ioctls.
> + */
> +#define VIRTIO_MEDIA_CMD_OPEN 1
> +
> +/**
> + * struct virtio_media_cmd_open - Driver command for VIRTIO_MEDIA_CMD_OPEN.
> + * @hdr: header with cmd member set to VIRTIO_MEDIA_CMD_OPEN.
> + */
> +struct virtio_media_cmd_open {
> + struct virtio_media_cmd_header hdr;
> +};
> +
> +/**
> + * struct virtio_media_resp_open - Device response for VIRTIO_MEDIA_CMD_OPEN.
> + * @hdr: header containing the status of the command.
> + * @session_id: if hdr.status == 0, contains the id of the newly created
> + * session.
> + * @__reserved: must be set to zero by the device.
> + */
> +struct virtio_media_resp_open {
> + struct virtio_media_resp_header hdr;
> + u32 session_id;
> + u32 __reserved;
> +};
> +
> +/**
> + * VIRTIO_MEDIA_CMD_CLOSE - Command for closing an active session.
> + *
> + * This is the equivalent of calling `close` on a previously opened V4L2
> + * session. All resources associated with this session will be freed and the
> + * session ID shall not be used again after queueing this command.
> + *
> + * This command does not require a response from the device.
> + */
> +#define VIRTIO_MEDIA_CMD_CLOSE 2
> +
> +/**
> + * struct virtio_media_cmd_close - Driver command for VIRTIO_MEDIA_CMD_CLOSE.
> + * @hdr: header with cmd member set to VIRTIO_MEDIA_CMD_CLOSE.
> + * @session_id: id of the session to close.
> + * @__reserved: must be set to zero by the driver.
> + */
> +struct virtio_media_cmd_close {
> + struct virtio_media_cmd_header hdr;
> + u32 session_id;
> + u32 __reserved;
> +};
> +
> +/**
> + * VIRTIO_MEDIA_CMD_IOCTL - Driver command for executing an ioctl.
> + *
> + * This command asks the device to run one of the `VIDIOC_*` ioctls on the
> + * active session.
> + *
> + * The code of the ioctl is extracted from the VIDIOC_* definitions in
> + * `videodev2.h`, and consists of the second argument of the `_IO*` macro.
> + *
> + * Each ioctl has a payload, which is defined by the third argument of the
> + * `_IO*` macro defining it. It can be writable by the driver (`_IOW`), the
> + * device (`_IOR`), or both (`_IOWR`).
> + *
> + * If an ioctl is writable by the driver, it must be followed by a
> + * driver-writable descriptor containing the payload.
> + *
> + * If an ioctl is writable by the device, it must be followed by a
> + * device-writable descriptor of the size of the payload that the device will
> + * write into.
> + *
> + */
> +#define VIRTIO_MEDIA_CMD_IOCTL 3
> +
> +/**
> + * struct virtio_media_cmd_ioctl - Driver command for VIRTIO_MEDIA_CMD_IOCTL.
> + * @hdr: header with cmd member set to VIRTIO_MEDIA_CMD_IOCTL.
> + * @session_id: id of the session to run the ioctl on.
> + * @code: code of the ioctl to run.
> + */
> +struct virtio_media_cmd_ioctl {
> + struct virtio_media_cmd_header hdr;
> + u32 session_id;
> + u32 code;
> +};
> +
> +/**
> + * struct virtio_media_resp_ioctl - Device response for VIRTIO_MEDIA_CMD_IOCTL.
> + * @hdr: header containing the status of the ioctl.
> + */
> +struct virtio_media_resp_ioctl {
> + struct virtio_media_resp_header hdr;
> +};
> +
> +/**
> + * struct virtio_media_sg_entry - Description of part of a scattered guest
> + * memory.
> + * @start: start guest address of the memory segment.
> + * @len: length of this memory segment.
> + * @__reserved: must be set to zero by the driver.
> + */
> +struct virtio_media_sg_entry {
> + u64 start;
> + u32 len;
> + u32 __reserved;
> +};
> +
> +#define VIRTIO_MEDIA_MMAP_FLAG_RW BIT(0)
> +
> +/**
> + * VIRTIO_MEDIA_CMD_MMAP - Command for mapping a MMAP buffer into the driver's
> + * address space.
> + *
> + */
> +#define VIRTIO_MEDIA_CMD_MMAP 4
> +
> +/**
> + * struct virtio_media_cmd_mmap - Driver command for VIRTIO_MEDIA_CMD_MMAP.
> + * @hdr: header with cmd member set to VIRTIO_MEDIA_CMD_MMAP.
> + * @session_id: ID of the session we are mapping for.
> + * @flags: combination of VIRTIO_MEDIA_MMAP_FLAG_*.
> + * @offset: mem_offset field of the plane to map, as returned by
> + * VIDIOC_QUERYBUF.
> + */
> +struct virtio_media_cmd_mmap {
> + struct virtio_media_cmd_header hdr;
> + u32 session_id;
> + u32 flags;
> + u32 offset;
> +};
> +
> +/**
> + * struct virtio_media_resp_mmap - Device response for VIRTIO_MEDIA_CMD_MMAP.
> + * @hdr: header containing the status of the command.
> + * @driver_addr: offset into SHM region 0 of the start of the mapping.
> + * @len: length of the mapping.
> + */
> +struct virtio_media_resp_mmap {
> + struct virtio_media_resp_header hdr;
> + u64 driver_addr;
> + u64 len;
> +};
> +
> +/**
> + * VIRTIO_MEDIA_CMD_MUNMAP - Unmap a MMAP buffer previously mapped using
> + * VIRTIO_MEDIA_CMD_MMAP.
> + */
> +#define VIRTIO_MEDIA_CMD_MUNMAP 5
> +
> +/**
> + * struct virtio_media_cmd_munmap - Driver command for VIRTIO_MEDIA_CMD_MUNMAP.
> + * @hdr: header with cmd member set to VIRTIO_MEDIA_CMD_MUNMAP.
> + * @driver_addr: offset into SHM region 0 at which the buffer has been
> + * previously
> + * mapped.
> + */
> +struct virtio_media_cmd_munmap {
> + struct virtio_media_cmd_header hdr;
> + u64 driver_addr;
> +};
> +
> +/**
> + * struct virtio_media_resp_munmap - Device response for
> + * VIRTIO_MEDIA_CMD_MUNMAP.
> + * @hdr: header containing the status of the command.
> + */
> +struct virtio_media_resp_munmap {
> + struct virtio_media_resp_header hdr;
> +};
> +
> +/* The values for these events are set by the virtio-media specification. */
> +#define VIRTIO_MEDIA_EVT_ERROR 0
> +#define VIRTIO_MEDIA_EVT_DQBUF 1
> +#define VIRTIO_MEDIA_EVT_EVENT 2
As I mentioned on v3, media also has events. Some userspace apps may
need them to do some optimizations related to buffer sync, source
changes, motion detection and such. See the specs:
https://linuxtv.org/downloads/v4l-dvb-apis-new/userspace-api/v4l/vidioc-dqevent.html#event-type
https://linuxtv.org/downloads/v4l-dvb-apis-new/driver-api/v4l2-event.html
As the virtio driver may end needing such events in the future,
it needs to start numbering its private events after:
#define V4L2_EVENT_PRIVATE_START 0x08000000
which is where driver-specific events should be placed.
Thanks,
Mauro
^ permalink raw reply
* Re: [PATCH v4 0/8] media: add virtio-media driver
From: Albert Esteve @ 2026-07-13 7:00 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Brian Daniels, Mauro Carvalho Chehab, acourbot, adelva, changyeon,
daniel.almeida, eperezma, gnurou, gurchetansingh, hverkuil,
jasowang, linux-kernel, linux-media, mst, nicolas.dufresne,
virtualization, xuanzhuo
In-Reply-To: <20260712091036.5b0f170c@foz.lan>
On Sun, Jul 12, 2026 at 9:10 AM Mauro Carvalho Chehab
<mchehab+huawei@kernel.org> wrote:
>
> On Mon, 22 Jun 2026 16:43:35 -0400
> Brian Daniels <briandaniels@google.com> wrote:
>
> > From: Alexandre Courbot <gnurou@gmail.com>
> >
> > Add the first version of the virtio-media driver.
> >
> > This driver acts roughly as a V4L2 relay between user-space and the
> > virtio virtual device on the host, so it is relatively simple, yet
> > unconventional. It doesn't use VB2 or other frameworks typically used in
> > a V4L2 driver, and most of its complexity resides in correctly and
> > efficiently building the virtio descriptor chain to pass to the host,
> > avoiding copies whenever possible. This is done by
> > scatterlist_builder.[ch].
> >
> > This version supports MMAP buffers, while USERPTR buffers can also be
> > enabled through a driver option. DMABUF support is still pending.
>
> In practice, USERPTR was used on several drivers that wanted to
> share buffers between V4L2 and GPU (so, a previous approach before
> DMABUF implementation).
>
> On my tests with this driver, I was unable use a 1080p camera with
> V4L2 and GPU on crossvm. Lower resolutions worked. No idea if this
> was a limitation of crossvm (I only used it to test this driver)
> or if it is due to a poor MMAP implementation.
>
>
>
> > Compliance Testing
> >
> > This was tested using v4l2-compliance. Since virtio-media serves as
> > a proxy to host devices for the guest VMs, we expect the guest
> > compliance test to essentially match the host compliance test for the
> > same device.
> >
> > NOTE: v4l2-compliance changes its test behavior depending on the driver
> > name. In the guest, the driver name for virtio-media proxied-devices is
> > always "virtio-media", even if the actual host device has a driver name
> > of e.g. "uvcvideo". To ensure the test is consistent between the host
> > and the guest, I created a patch for the v4l2-compliance tool that
> > allows you to override the driver name. All test results that follow use
> > this patch:
> > https://lore.kernel.org/r/20260528163448.4031965-1-briandaniels@google.com/
>
> As mentioned before, please submit this with their rationale in
> separate as a [PATCH v4l-utils] to linux-media ML.
>
> >
> > All tests used a Logitech USB Webcam C925e.
>
> Please test it displaying inside crossvm - or even better to QEMU if
> you manage to add virtio-media support to it.
>
> Being at QEMU makes a lot easier for everyone to test it.
Hi,
Regarding the QEMU support mention, I created this series in QEMU to
add the virtio-media PCI device:
https://lore.kernel.org/all/20260630112310.552606-1-aesteve@redhat.com/
Testing was done using an older driver version at
https://github.com/chromeos/virtio-media/tree/main/driver as described
in the cover letter. But I can try testing it with this series. Either
way, the procedure for using QEMU is in the cover letter, so anyone
can try it.
BR,
Albert.
>
>
> Thanks,
> Mauro
>
^ permalink raw reply
* Re:Re: [PATCH] vhost/net: Fill virtio_net_hdr GSO/csum metadata on RX
From: Xiong Weimin @ 2026-07-13 8:04 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: jasowang, xiongweimin, netdev, virtualization
In-Reply-To: <20260713025549-mutt-send-email-mst@kernel.org>
Hi Michael,
Thanks for the review.
On why VHOST_NET_F_VIRTIO_NET_HDR:
We hit this with vhost-user backends that do not expose IFF_VNET_HDR
(e.g. DPDK/custom socket backends). When the guest negotiates
VHOST_NET_F_VIRTIO_NET_HDR, vhost is responsible for supplying
virtio_net_hdr on RX. The current code always zeroes the header
(GSO_NONE), so guests that negotiated GUEST_TSO*/GUEST_CSUM never
receive correct offload metadata even when the socket skb has it.
The goal is to make RX offload metadata correct for that configuration.
TX TSO is intentionally left for a follow-up series.
On the race you pointed out:
You're right — peeking the skb under sk_receive_queue.lock and then
building the header after dropping the lock is racy if another context
can dequeue the skb before recvmsg() runs. I see why the header filling
ended up in tun, where the backend owns the skb lifecycle.
I can think of a few options:
a) Drop this approach and not use VHOST_NET_F_VIRTIO_NET_HDR for
these backends (keep zeroed headers / no guest offload).
b) Move the metadata extraction to the backend (similar to tun).
c) Hold the receive-queue lock across peek + recvmsg if that is
acceptable for this path (I need to check whether recvmsg can
be called under that lock).
Could you suggest which direction you'd prefer? I'm happy to respin
once we agree on the right integration point.
I'll also fix the multiline comment to follow the net convention:
/* When VHOST_NET_F_VIRTIO_NET_HDR is set, vhost supplies virtio_net_hdr.
* Populate GSO/checksum metadata from the socket skb ...
*/
Thanks,
Weimin
At 2026-07-13 15:03:39, "Michael S. Tsirkin" <mst@redhat.com> wrote:
>On Mon, Jul 13, 2026 at 09:04:42AM +0800, weimin xiong wrote:
>> From: xiongweimin <xiongweimin@kylinos.cn>
>>
>> When VHOST_NET_F_VIRTIO_NET_HDR is set, vhost supplies virtio_net_hdr to
>> the guest but previously always wrote a zeroed header (GSO_NONE). Guests
>> that rely on GUEST_TSO*/GUEST_CSUM therefore never saw offload metadata.
>
>Right. Question is why are you using VHOST_NET_F_VIRTIO_NET_HDR?
>
>>
>> Peek the socket skb before recvmsg and populate the header with
>> virtio_net_hdr_from_skb(). Also advertise the corresponding guest offload
>> feature bits from VHOST_GET_FEATURES.
>>
>> TX TSO toward backends without IFF_VNET_HDR is intentionally left for a
>> follow-up series.
>>
>> Signed-off-by: xiongweimin <xiongweimin@kylinos.cn>
>> Cc: Michael S. Tsirkin <mst@redhat.com>
>> Cc: Jason Wang <jasowang@redhat.com>
>> Cc: virtualization@vger.kernel.org
>> Cc: netdev@vger.kernel.org
>> ---
>>
>> --- a/drivers/vhost/net.c
>> +++ b/drivers/vhost/net.c
>> @@ -73,6 +73,10 @@
>> VHOST_FEATURES,
>> VHOST_NET_F_VIRTIO_NET_HDR,
>> VIRTIO_NET_F_MRG_RXBUF,
>> + VIRTIO_NET_F_GUEST_CSUM,
>> + VIRTIO_NET_F_GUEST_TSO4,
>> + VIRTIO_NET_F_GUEST_TSO6,
>> + VIRTIO_NET_F_GUEST_ECN,
>> VIRTIO_F_ACCESS_PLATFORM,
>> VIRTIO_F_RING_RESET,
>> VIRTIO_F_IN_ORDER,
>> @@ -644,7 +648,7 @@
>> static size_t init_iov_iter(struct vhost_virtqueue *vq, struct iov_iter *iter,
>> size_t hdr_size, int out)
>> {
>> - /* Skip header. TODO: support TSO. */
>> + /* Skip guest virtio_net_hdr; TX TSO handled in a follow-up. */
>> size_t len = iov_length(vq->iov, out);
>>
>> iov_iter_init(iter, ITER_SOURCE, vq->iov, out, len);
>> @@ -1025,6 +1029,35 @@
>> return len;
>> }
>>
>> +/*
>> + * When VHOST_NET_F_VIRTIO_NET_HDR is set, vhost supplies virtio_net_hdr.
>> + * Populate GSO/checksum metadata from the socket skb so guests that
>> + * negotiated GUEST_TSO*/GUEST_CSUM receive correct offload information.
>> + */
>
>this is a wrong type of multiline comment. this file follows net
>convention:
>
>/* AAA
> * BBB
> */
>
>> +static int vhost_net_hdr_from_sock(struct vhost_virtqueue *vq, struct sock *sk,
>> + struct virtio_net_hdr *hdr)
>> +{
>> + struct sk_buff *skb;
>> + unsigned long flags;
>> + int vlan_hlen = 0;
>> + int ret;
>> +
>> + spin_lock_irqsave(&sk->sk_receive_queue.lock, flags);
>> + skb = skb_peek(&sk->sk_receive_queue);
>> + if (!skb) {
>> + spin_unlock_irqrestore(&sk->sk_receive_queue.lock, flags);
>> + memset(hdr, 0, sizeof(*hdr));
>> + hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
>> + return 0;
>> + }
>> + if (skb_vlan_tag_present(skb))
>> + vlan_hlen = VLAN_HLEN;
>> + ret = virtio_net_hdr_from_skb(skb, hdr, vhost_is_little_endian(vq),
>> + true, vlan_hlen);
>> + spin_unlock_irqrestore(&sk->sk_receive_queue.lock, flags);
>> + return ret;
>> +}
>
>
>This means the header will be wrong if something consumes
>the skb after we drop the lock, no?
>
>That's why in the end we put the header filling logic
>in tun, it can avoid races there.
>
>
>> +
>> static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk,
>> bool *busyloop_intr, unsigned int *count)
>> {
>> @@ -1239,10 +1272,18 @@
>> /* We don't need to be notified again. */
>> iov_iter_init(&msg.msg_iter, ITER_DEST, vq->iov, in, vhost_len);
>> fixup = msg.msg_iter;
>> - if (unlikely((vhost_hlen))) {
>> - /* We will supply the header ourselves
>> - * TODO: support TSO.
>> + if (unlikely(vhost_hlen)) {
>> + /*
>> + * Build virtio_net_hdr from the socket skb before
>> + * recvmsg consumes it. Skip for ptr_ring backends
>> + * where the skb is not on sk_receive_queue.
>> */
>> + if (!nvq->rx_ring &&
>> + vhost_net_hdr_from_sock(vq, sock->sk, &hdr)) {
>> + vq_err(vq, "Failed to build vnet_hdr from skb\n");
>> + vhost_discard_vq_desc(vq, headcount, ndesc);
>> + continue;
>> + }
>> iov_iter_advance(&msg.msg_iter, vhost_hlen);
>> }
>> err = sock->ops->recvmsg(sock, &msg,
>> @@ -1270,7 +1311,6 @@
>> */
>> iov_iter_advance(&fixup, sizeof(hdr));
>> }
>> - /* TODO: Should check and handle checksum. */
>>
>> num_buffers = cpu_to_vhost16(vq, headcount);
>> if (likely(set_num_buffers) &&
^ permalink raw reply
* [PATCH] vdpa_sim: Document planned packed-ring support
From: weimin xiong @ 2026-07-13 9:59 UTC (permalink / raw)
To: mst; +Cc: jasowang, virtualization, xiongweimin
From: xiongweimin <xiongweimin@kylinos.cn>
Note that VIRTIO_F_RING_PACKED should be advertised once vringh packed
helpers exist. No functional change.
Signed-off-by: xiongweimin <xiongweimin@kylinos.cn>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Jason Wang <jasowang@redhat.com>
Cc: virtualization@lists.linux.dev
---
--- a/drivers/vdpa/vdpa_sim/vdpa_sim.h
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim.h
@@ -13,6 +13,10 @@
#include <linux/vhost_iotlb.h>
#include <uapi/linux/virtio_config.h>
+/*
+ * Once vringh packed helpers land, also advertise VIRTIO_F_RING_PACKED
+ * here so vdpa_sim can exercise HW-like packed rings.
+ */
#define VDPASIM_FEATURES ((1ULL << VIRTIO_F_ANY_LAYOUT) | \
(1ULL << VIRTIO_F_VERSION_1) | \
(1ULL << VIRTIO_F_ACCESS_PLATFORM))
^ permalink raw reply
* [PATCH] vdpa_sim: Document planned packed-ring support
From: weimin xiong @ 2026-07-13 10:00 UTC (permalink / raw)
To: mst; +Cc: jasowang, virtualization, xiongweimin
From: xiongweimin <xiongweimin@kylinos.cn>
Note that VIRTIO_F_RING_PACKED should be advertised once vringh packed
helpers exist. No functional change.
Signed-off-by: xiongweimin <xiongweimin@kylinos.cn>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Jason Wang <jasowang@redhat.com>
Cc: virtualization@lists.linux.dev
---
--- a/drivers/vdpa/vdpa_sim/vdpa_sim.h
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim.h
@@ -13,6 +13,10 @@
#include <linux/vhost_iotlb.h>
#include <uapi/linux/virtio_config.h>
+/*
+ * Once vringh packed helpers land, also advertise VIRTIO_F_RING_PACKED
+ * here so vdpa_sim can exercise HW-like packed rings.
+ */
#define VDPASIM_FEATURES ((1ULL << VIRTIO_F_ANY_LAYOUT) | \
(1ULL << VIRTIO_F_VERSION_1) | \
(1ULL << VIRTIO_F_ACCESS_PLATFORM))
^ permalink raw reply
* [PATCH RFC net-next v3 0/3] net: sysctl: Const Qualify sysctl ctl_table arrays
From: Joel Granados @ 2026-07-13 11:07 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, David Ahern, Ido Schimmel, Pablo Neira Ayuso,
Florian Westphal, Phil Sutter, Marcelo Ricardo Leitner, Xin Long,
Steffen Klassert, Herbert Xu, D. Wythe, Dust Li, Sidraya Jayagond,
Wenjia Zhang, Mahanta Jambigi, Tony Lu, Wen Gu, Kuniyuki Iwashima,
Stefano Garzarella
Cc: netdev, linux-kernel, netfilter-devel, coreteam, linux-sctp,
linux-rdma, linux-s390, virtualization, Joel Granados
What?
=====
We do two things:
1. Reject netns-unsafe: Replace warning and file permission change with
an error (reject registration) when an "unsafe" net sysctl
registration is detected.
2. Const qualify: Const qualify network templated ctl_table arrays and
unconditional kmemdup'ed ctl_table arrays.
Why?
====
The main motivation for this is to continue with the const qualification
of the ctl_table arrays [1]. The permission change inside
ensure_safe_net_sysctl disallows cons qualifiaction as it basically
modifies the entries before running the sysctl registration.
ent->mode &= ~0222;
On reject netns-unsafe?
=======================
* I believe that there is currently now way that the permission change
gets executed [2]
* I found one case where the warning message was posted to lore
(vsock_sysctl_register) [3], but it made its to mainline as part of
the second case in [2].
* We should error anyway because writing to the global sysctl value
through a child netns is indicative of a bug [4].
On Const qualification?
=======================
We can separate the places where network registers sysctl tables into
three groups:
1. Static global: The unchanged global static arrays are passed along to
sysctl register.
2. Always kmemdup: The global static arrays are always kmemdup'ed before
passing them along to sysctl register.
3. Dynamic global: The global static array is changed in place before
passing it along to sysctl register.
This series handles case 1 and 2. It leaves 3 for a later point as
const qualifying those global ctl_tables is more involved.
RFC
===
Keeping the RFC tag for now in hope of any preliminary feedback. I would
be very thankful if you point me to anything that I have missed in my
analysis that shows that this cannot/shouldn't be done.
Changes in v3:
- Const qualified 2 of the 3 cases within the net directory ctl_table
register sites.
- Link to v2: https://lore.kernel.org/r/20260707-jag-net_const_qualify-v2-1-5a5c52031ead@kernel.org
Changes in v2:
- Rebased on top of net-next
- Updated subject to "RFC net-next"
- Link to v1: https://lore.kernel.org/r/20260629-jag-net_const_qualify-v1-1-ee98b8fc400c@kernel.org
Best
[1]
https://git.kernel.org/pub/scm/linux/kernel/git/sysctl/sysctl.git/commit/?h=constfy-sysctl-6.14-rc1&id=1751f872cc97f992ed5c4c72c55588db1f0021e1
[2]
I have identified 4 contexts relevant to the ensure_safe_net_sysctl call
inside the network sysctl registration.
1. When the (struct net) == &init_net (like in iw_cm_init): In this case
ensure_safe_net_sysctl is not executed and permission modification
never happens.
2. When the ctl_table data (->data) gets "manually" assigned to
something other init_net (like in vsock_sysctl_register): In this
case ensure_safe_net_sysctl *is* executed but the data that is passed
is neither a module address (!is_module_address) nor a kernel core
address (!is_kernel_core_data); so the permission modification never
happens.
3. When the permissions are explicitly changed on a kmemdup'ed ctl_table
array (like in sysctl_core_net_init): in this case
ensure_safe_net_sysctl *is* executed but the permission modification
never happens as the mode is not writable.
4. When ctl have custom proc_handlers (like in nf_lwtunnel_net_init): In
this case ->data is NULL so it is not a module address
(!is_module_address) nor a kernel core address
(!is_kernel_core_data), so permission modification never happens.
It seems like there is no way of executing the permission change in
ensure_safe_net_sysctl. Please correct me if this is inaccurate and help
me find the case that I missed.
[3]
https://lore.kernel.org/all/20260302194926.90378-1-graf@amazon.com/
[4]
The ensure_safe_net_sysctl function was introduced in Commit:
31c4d2f160eb7b17cbead24dc6efed06505a3fee ("net: Ensure net namespace
isolation of sysctls") which states that it is trying to prevent a
leak (indicative of a bug).
---
Signed-off-by: Joel Granados <joel.granados@kernel.org>
---
Joel Granados (3):
net: enforce net sysctl registration
net: Const qualify ctl_tables that kmemdup unconditionally
net: Const qualify network templated ctl_tables Arrays
include/net/net_namespace.h | 4 +--
net/core/sysctl_net_core.c | 38 +++++++++++++++--------
net/ipv4/devinet.c | 2 +-
net/ipv4/sysctl_net_ipv4.c | 54 +++++++++++++++++++--------------
net/ipv4/xfrm4_policy.c | 22 +++++++++++---
net/ipv6/icmp.c | 2 +-
net/ipv6/route.c | 2 +-
net/ipv6/sysctl_net_ipv6.c | 2 +-
net/ipv6/xfrm6_policy.c | 22 +++++++++++---
net/netfilter/nf_conntrack_standalone.c | 2 +-
net/netfilter/nf_hooks_lwtunnel.c | 4 +--
net/sctp/sysctl.c | 2 +-
net/smc/smc_sysctl.c | 26 +++++++++++-----
net/sysctl_net.c | 24 +++++++--------
net/unix/sysctl_net_unix.c | 21 ++++++++++---
net/vmw_vsock/af_vsock.c | 25 ++++++++++-----
net/xfrm/xfrm_sysctl.c | 2 +-
17 files changed, 167 insertions(+), 87 deletions(-)
---
base-commit: 474cff6868129755cf889edf40d7f491729fc588
change-id: 20260629-jag-net_const_qualify-f4e09759dac7
Best regards,
--
Joel Granados <joel.granados@kernel.org>
^ permalink raw reply
* [PATCH RFC net-next v3 3/3] net: Const qualify network templated ctl_tables Arrays
From: Joel Granados @ 2026-07-13 11:07 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, David Ahern, Ido Schimmel, Pablo Neira Ayuso,
Florian Westphal, Phil Sutter, Marcelo Ricardo Leitner, Xin Long,
Steffen Klassert, Herbert Xu, D. Wythe, Dust Li, Sidraya Jayagond,
Wenjia Zhang, Mahanta Jambigi, Tony Lu, Wen Gu, Kuniyuki Iwashima,
Stefano Garzarella
Cc: netdev, linux-kernel, netfilter-devel, coreteam, linux-sctp,
linux-rdma, linux-s390, virtualization, Joel Granados
In-Reply-To: <20260713-jag-net_const_qualify-v3-0-7289fe9eaea6@kernel.org>
Add duplication helpers in the cases where the ctl_table array elements
are modified after duplication. Helpers return a ctl_table as const
pointer allowing the const qualification of the static global ctl_table
array.
Signed-off-by: Joel Granados <joel.granados@kernel.org>
---
net/core/sysctl_net_core.c | 38 +++++++++++++++++----------
net/ipv4/sysctl_net_ipv4.c | 54 +++++++++++++++++++++++----------------
net/ipv4/xfrm4_policy.c | 22 ++++++++++++----
net/ipv6/xfrm6_policy.c | 22 ++++++++++++----
net/netfilter/nf_hooks_lwtunnel.c | 4 +--
net/smc/smc_sysctl.c | 26 ++++++++++++++-----
net/unix/sysctl_net_unix.c | 21 +++++++++++----
net/vmw_vsock/af_vsock.c | 25 +++++++++++++-----
8 files changed, 146 insertions(+), 66 deletions(-)
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index b508618bfc12393ba926ebf5a2dd4ea73ef03ee8..eb35da3556f4aa00cecd4582ab94e339d2518506 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -678,7 +678,7 @@ static struct ctl_table net_core_table[] = {
},
};
-static struct ctl_table netns_core_table[] = {
+static const struct ctl_table netns_core_table[] = {
#if IS_ENABLED(CONFIG_RPS)
{
.procname = "rps_default_mask",
@@ -787,26 +787,38 @@ static int __init fb_tunnels_only_for_init_net_sysctl_setup(char *str)
}
__setup("fb_tunnels=", fb_tunnels_only_for_init_net_sysctl_setup);
-static __net_init int sysctl_core_net_init(struct net *net)
+static const struct ctl_table *netns_core_table_dup(struct net *net)
{
size_t table_size = ARRAY_SIZE(netns_core_table);
struct ctl_table *tbl;
+ int i;
+
+ tbl = kmemdup(netns_core_table, sizeof(netns_core_table), GFP_KERNEL);
+ if (!tbl)
+ return NULL;
+
+ for (i = 0; i < table_size; ++i) {
+ if (tbl[i].data == &sysctl_wmem_max)
+ break;
+
+ tbl[i].data += (char *)net - (char *)&init_net;
+ }
+ for (; i < table_size; ++i)
+ tbl[i].mode &= ~0222;
+
+ return tbl;
+}
+
+static __net_init int sysctl_core_net_init(struct net *net)
+{
+ size_t table_size = ARRAY_SIZE(netns_core_table);
+ const struct ctl_table *tbl;
tbl = netns_core_table;
if (!net_eq(net, &init_net)) {
- int i;
- tbl = kmemdup(tbl, sizeof(netns_core_table), GFP_KERNEL);
+ tbl = netns_core_table_dup(net);
if (tbl == NULL)
goto err_dup;
-
- for (i = 0; i < table_size; ++i) {
- if (tbl[i].data == &sysctl_wmem_max)
- break;
-
- tbl[i].data += (char *)net - (char *)&init_net;
- }
- for (; i < table_size; ++i)
- tbl[i].mode &= ~0222;
}
net->core.sysctl_hdr = register_net_sysctl_sz(net, "net/core", tbl, table_size);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index ca1180dba1dea9ce72028ba49b7f953da343336b..2f0363bca2a88d68276670cfce6fb04398f82bc5 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -624,7 +624,7 @@ static struct ctl_table ipv4_table[] = {
},
};
-static struct ctl_table ipv4_net_table[] = {
+static const struct ctl_table ipv4_net_table[] = {
{
.procname = "tcp_max_tw_buckets",
.data = &init_net.ipv4.tcp_death_row.sysctl_max_tw_buckets,
@@ -1654,35 +1654,45 @@ static struct ctl_table ipv4_net_table[] = {
},
};
-static __net_init int ipv4_sysctl_init_net(struct net *net)
+static const struct ctl_table *ipv4_net_table_dup(struct net *net)
{
size_t table_size = ARRAY_SIZE(ipv4_net_table);
struct ctl_table *table;
+ int i;
+
+ table = kmemdup(ipv4_net_table, sizeof(ipv4_net_table), GFP_KERNEL);
+ if (!table)
+ return NULL;
+
+ for (i = 0; i < table_size; i++) {
+ if (table[i].data) {
+ /* Update the variables to point into
+ * the current struct net
+ */
+ table[i].data += (void *)net - (void *)&init_net;
+ } else {
+ /* Entries without data pointer are global;
+ * Make them read-only in non-init_net ns
+ */
+ table[i].mode &= ~0222;
+ }
+ if (table[i].extra2 >= (void *)&init_net.ipv4 &&
+ table[i].extra2 < (void *)(&init_net.ipv4 + 1))
+ table[i].extra2 += (void *)net - (void *)&init_net;
+ }
+ return table;
+}
+
+static __net_init int ipv4_sysctl_init_net(struct net *net)
+{
+ size_t table_size = ARRAY_SIZE(ipv4_net_table);
+ const struct ctl_table *table;
table = ipv4_net_table;
if (!net_eq(net, &init_net)) {
- int i;
-
- table = kmemdup(table, sizeof(ipv4_net_table), GFP_KERNEL);
+ table = ipv4_net_table_dup(net);
if (!table)
goto err_alloc;
-
- for (i = 0; i < table_size; i++) {
- if (table[i].data) {
- /* Update the variables to point into
- * the current struct net
- */
- table[i].data += (void *)net - (void *)&init_net;
- } else {
- /* Entries without data pointer are global;
- * Make them read-only in non-init_net ns
- */
- table[i].mode &= ~0222;
- }
- if (table[i].extra2 >= (void *)&init_net.ipv4 &&
- table[i].extra2 < (void *)(&init_net.ipv4 + 1))
- table[i].extra2 += (void *)net - (void *)&init_net;
- }
}
net->ipv4.ipv4_hdr = register_net_sysctl_sz(net, "net/ipv4", table,
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 58faf1ddd2b151e4569bb6351029718dac37521b..ab7a01029d490416d36482f7a3189f83d6670f42 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -141,7 +141,7 @@ static const struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
};
#ifdef CONFIG_SYSCTL
-static struct ctl_table xfrm4_policy_table[] = {
+static const struct ctl_table xfrm4_policy_table[] = {
{
.procname = "xfrm4_gc_thresh",
.data = &init_net.xfrm.xfrm4_dst_ops.gc_thresh,
@@ -151,18 +151,30 @@ static struct ctl_table xfrm4_policy_table[] = {
},
};
-static __net_init int xfrm4_net_sysctl_init(struct net *net)
+static const struct ctl_table *xfrm4_policy_table_dup(struct net *net)
{
struct ctl_table *table;
+
+ table = kmemdup(xfrm4_policy_table, sizeof(xfrm4_policy_table),
+ GFP_KERNEL);
+ if (!table)
+ return NULL;
+
+ table[0].data = &net->xfrm.xfrm4_dst_ops.gc_thresh;
+
+ return table;
+}
+
+static __net_init int xfrm4_net_sysctl_init(struct net *net)
+{
+ const struct ctl_table *table;
struct ctl_table_header *hdr;
table = xfrm4_policy_table;
if (!net_eq(net, &init_net)) {
- table = kmemdup(table, sizeof(xfrm4_policy_table), GFP_KERNEL);
+ table = xfrm4_policy_table_dup(net);
if (!table)
goto err_alloc;
-
- table[0].data = &net->xfrm.xfrm4_dst_ops.gc_thresh;
}
hdr = register_net_sysctl_sz(net, "net/ipv4", table,
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 125ea9a5b8a082052380b7fd7ed7123f5247d7cc..1e0385b62cde3f6d23382f92bbad5d7fdd09f1ef 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -186,7 +186,7 @@ static void xfrm6_policy_fini(void)
}
#ifdef CONFIG_SYSCTL
-static struct ctl_table xfrm6_policy_table[] = {
+static const struct ctl_table xfrm6_policy_table[] = {
{
.procname = "xfrm6_gc_thresh",
.data = &init_net.xfrm.xfrm6_dst_ops.gc_thresh,
@@ -196,18 +196,30 @@ static struct ctl_table xfrm6_policy_table[] = {
},
};
-static int __net_init xfrm6_net_sysctl_init(struct net *net)
+static const struct ctl_table *xfrm6_policy_table_dup(struct net *net)
{
struct ctl_table *table;
+
+ table = kmemdup(xfrm6_policy_table, sizeof(xfrm6_policy_table),
+ GFP_KERNEL);
+ if (!table)
+ return NULL;
+
+ table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh;
+
+ return table;
+}
+
+static int __net_init xfrm6_net_sysctl_init(struct net *net)
+{
+ const struct ctl_table *table;
struct ctl_table_header *hdr;
table = xfrm6_policy_table;
if (!net_eq(net, &init_net)) {
- table = kmemdup(table, sizeof(xfrm6_policy_table), GFP_KERNEL);
+ table = xfrm6_policy_table_dup(net);
if (!table)
goto err_alloc;
-
- table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh;
}
hdr = register_net_sysctl_sz(net, "net/ipv6", table,
diff --git a/net/netfilter/nf_hooks_lwtunnel.c b/net/netfilter/nf_hooks_lwtunnel.c
index 2d890dd04ff89041e6aec3741f24cdd7bc47d1fe..4e1eef1ba0f1559ca35f024723af551c6c9e7d35 100644
--- a/net/netfilter/nf_hooks_lwtunnel.c
+++ b/net/netfilter/nf_hooks_lwtunnel.c
@@ -54,7 +54,7 @@ int nf_hooks_lwtunnel_sysctl_handler(const struct ctl_table *table, int write,
}
EXPORT_SYMBOL_GPL(nf_hooks_lwtunnel_sysctl_handler);
-static struct ctl_table nf_lwtunnel_sysctl_table[] = {
+static const struct ctl_table nf_lwtunnel_sysctl_table[] = {
{
.procname = "nf_hooks_lwtunnel",
.data = NULL,
@@ -66,8 +66,8 @@ static struct ctl_table nf_lwtunnel_sysctl_table[] = {
static int __net_init nf_lwtunnel_net_init(struct net *net)
{
+ const struct ctl_table *table;
struct ctl_table_header *hdr;
- struct ctl_table *table;
table = nf_lwtunnel_sysctl_table;
if (!net_eq(net, &init_net)) {
diff --git a/net/smc/smc_sysctl.c b/net/smc/smc_sysctl.c
index b1efed5462435b1a6f2f59584a4cf47f5f6e1981..09dad48337f6164f5765fa793412bdebf47e61ca 100644
--- a/net/smc/smc_sysctl.c
+++ b/net/smc/smc_sysctl.c
@@ -97,7 +97,7 @@ static int proc_smc_hs_ctrl(const struct ctl_table *ctl, int write,
}
#endif /* CONFIG_SMC_HS_CTRL_BPF */
-static struct ctl_table smc_table[] = {
+static const struct ctl_table smc_table[] = {
{
.procname = "autocorking_size",
.data = &init_net.smc.sysctl_autocorking_size,
@@ -195,14 +195,29 @@ static struct ctl_table smc_table[] = {
#endif /* CONFIG_SMC_HS_CTRL_BPF */
};
-int __net_init smc_sysctl_net_init(struct net *net)
+static const struct ctl_table *smc_table_dup(struct net *net)
{
size_t table_size = ARRAY_SIZE(smc_table);
struct ctl_table *table;
+ int i;
+
+ table = kmemdup(smc_table, sizeof(smc_table), GFP_KERNEL);
+ if (!table)
+ return NULL;
+
+ for (i = 0; i < table_size; i++)
+ table[i].data += (void *)net - (void *)&init_net;
+
+ return table;
+}
+
+int __net_init smc_sysctl_net_init(struct net *net)
+{
+ size_t table_size = ARRAY_SIZE(smc_table);
+ const struct ctl_table *table;
table = smc_table;
if (!net_eq(net, &init_net)) {
- int i;
#if IS_ENABLED(CONFIG_SMC_HS_CTRL_BPF)
struct smc_hs_ctrl *ctrl;
@@ -214,12 +229,9 @@ int __net_init smc_sysctl_net_init(struct net *net)
rcu_read_unlock();
#endif /* CONFIG_SMC_HS_CTRL_BPF */
- table = kmemdup(table, sizeof(smc_table), GFP_KERNEL);
+ table = smc_table_dup(net);
if (!table)
goto err_alloc;
-
- for (i = 0; i < table_size; i++)
- table[i].data += (void *)net - (void *)&init_net;
}
net->smc.smc_hdr = register_net_sysctl_sz(net, "net/smc", table,
diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c
index e02ed6e3955c06b60cf4afb02656df8956f075ba..47660d5726bbd7d812762f4feffa9a0a42499d7d 100644
--- a/net/unix/sysctl_net_unix.c
+++ b/net/unix/sysctl_net_unix.c
@@ -13,7 +13,7 @@
#include "af_unix.h"
-static struct ctl_table unix_table[] = {
+static const struct ctl_table unix_table[] = {
{
.procname = "max_dgram_qlen",
.data = &init_net.unx.sysctl_max_dgram_qlen,
@@ -23,18 +23,29 @@ static struct ctl_table unix_table[] = {
},
};
-int __net_init unix_sysctl_register(struct net *net)
+static const struct ctl_table *unix_table_dup(struct net *net)
{
struct ctl_table *table;
+ table = kmemdup(unix_table, sizeof(unix_table), GFP_KERNEL);
+ if (!table)
+ return NULL;
+
+ table[0].data = &net->unx.sysctl_max_dgram_qlen;
+
+ return table;
+}
+
+int __net_init unix_sysctl_register(struct net *net)
+{
+ const struct ctl_table *table;
+
if (net_eq(net, &init_net)) {
table = unix_table;
} else {
- table = kmemdup(unix_table, sizeof(unix_table), GFP_KERNEL);
+ table = unix_table_dup(net);
if (!table)
goto err_alloc;
-
- table[0].data = &net->unx.sysctl_max_dgram_qlen;
}
net->unx.ctl = register_net_sysctl_sz(net, "net/unix", table,
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index 622dbd0467994428f1a590f559b78d8c17f6ba60..caebef73ea58d2b6043ca3fe3b6872f92fbe9fa6 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -2899,7 +2899,7 @@ static int vsock_net_child_mode_string(const struct ctl_table *table, int write,
return 0;
}
-static struct ctl_table vsock_table[] = {
+static const struct ctl_table vsock_table[] = {
{
.procname = "ns_mode",
.data = &init_net.vsock.mode,
@@ -2925,20 +2925,31 @@ static struct ctl_table vsock_table[] = {
},
};
-static int __net_init vsock_sysctl_register(struct net *net)
+static const struct ctl_table *vsock_table_dup(struct net *net)
{
struct ctl_table *table;
+ table = kmemdup(vsock_table, sizeof(vsock_table), GFP_KERNEL);
+ if (!table)
+ return NULL;
+
+ table[0].data = &net->vsock.mode;
+ table[1].data = &net->vsock.child_ns_mode;
+ table[2].data = &net->vsock.g2h_fallback;
+
+ return table;
+}
+
+static int __net_init vsock_sysctl_register(struct net *net)
+{
+ const struct ctl_table *table;
+
if (net_eq(net, &init_net)) {
table = vsock_table;
} else {
- table = kmemdup(vsock_table, sizeof(vsock_table), GFP_KERNEL);
+ table = vsock_table_dup(net);
if (!table)
goto err_alloc;
-
- table[0].data = &net->vsock.mode;
- table[1].data = &net->vsock.child_ns_mode;
- table[2].data = &net->vsock.g2h_fallback;
}
net->vsock.sysctl_hdr = register_net_sysctl_sz(net, "net/vsock", table,
--
2.50.1
^ permalink raw reply related
* [PATCH RFC net-next v3 2/3] net: Const qualify ctl_tables that kmemdup unconditionally
From: Joel Granados @ 2026-07-13 11:07 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, David Ahern, Ido Schimmel, Pablo Neira Ayuso,
Florian Westphal, Phil Sutter, Marcelo Ricardo Leitner, Xin Long,
Steffen Klassert, Herbert Xu, D. Wythe, Dust Li, Sidraya Jayagond,
Wenjia Zhang, Mahanta Jambigi, Tony Lu, Wen Gu, Kuniyuki Iwashima,
Stefano Garzarella
Cc: netdev, linux-kernel, netfilter-devel, coreteam, linux-sctp,
linux-rdma, linux-s390, virtualization, Joel Granados
In-Reply-To: <20260713-jag-net_const_qualify-v3-0-7289fe9eaea6@kernel.org>
Const qualify clt_table arrays in the net directory that always pass a
memory duplicate to sysctl register. The template would then be in
.rodata and the kmemdup'ed array would be outside.
Signed-off-by: Joel Granados <joel.granados@kernel.org>
---
net/ipv4/devinet.c | 2 +-
net/ipv6/icmp.c | 2 +-
net/ipv6/route.c | 2 +-
net/ipv6/sysctl_net_ipv6.c | 2 +-
net/netfilter/nf_conntrack_standalone.c | 2 +-
net/sctp/sysctl.c | 2 +-
net/xfrm/xfrm_sysctl.c | 2 +-
7 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index a35b72662e431661da1672f428cae6bb3110480b..19edc08ae20c4f16d3bcf479dc25022d55cbb5af 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -2798,7 +2798,7 @@ static void devinet_sysctl_unregister(struct in_device *idev)
neigh_sysctl_unregister(idev->arp_parms);
}
-static struct ctl_table ctl_forward_entry[] = {
+static const struct ctl_table ctl_forward_entry[] = {
{
.procname = "ip_forward",
.data = &ipv4_devconf.data[
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index efb23807a0262e8d68aa1afc8d96ee94eab89d50..a95b0351824f3237815e43bf8448110070955884 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -1374,7 +1374,7 @@ EXPORT_SYMBOL(icmpv6_err_convert);
static u32 icmpv6_errors_extension_mask_all =
GENMASK_U8(ICMP_ERR_EXT_COUNT - 1, 0);
-static struct ctl_table ipv6_icmp_table_template[] = {
+static const struct ctl_table ipv6_icmp_table_template[] = {
{
.procname = "ratelimit",
.data = &init_net.ipv6.sysctl.icmpv6_time,
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index a1301334da48c0f911da06ce448a76ecfb0d25cf..96b37c102a634c6715a5fbd1d39ca415302ff859 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -6555,7 +6555,7 @@ static int ipv6_sysctl_rtcache_flush(const struct ctl_table *ctl, int write,
return 0;
}
-static struct ctl_table ipv6_route_table_template[] = {
+static const struct ctl_table ipv6_route_table_template[] = {
{
.procname = "max_size",
.data = &init_net.ipv6.sysctl.ip6_rt_max_size,
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index d2cd33e2698d5c88df4718c9622dba2d574fa309..1a0a36dcdabc1be961d0ab69e5c93b05c53f46a8 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -61,7 +61,7 @@ proc_rt6_multipath_hash_fields(const struct ctl_table *table, int write, void *b
return ret;
}
-static struct ctl_table ipv6_table_template[] = {
+static const struct ctl_table ipv6_table_template[] = {
{
.procname = "bindv6only",
.data = &init_net.ipv6.sysctl.bindv6only,
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index be2953c7d702e92031d4bcf7e707741abed0f49c..f4f2d82192d54ed9831b9677743f1139820e5a2e 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -639,7 +639,7 @@ enum nf_ct_sysctl_index {
NF_SYSCTL_CT_LAST_SYSCTL,
};
-static struct ctl_table nf_ct_sysctl_table[] = {
+static const struct ctl_table nf_ct_sysctl_table[] = {
[NF_SYSCTL_CT_MAX] = {
.procname = "nf_conntrack_max",
.data = &nf_conntrack_max,
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index 15e7db9a3ab2e325f3951ac20c067a973a049618..331f45af9c4990d78a10a5c2c4efbcbca21813dc 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -92,7 +92,7 @@ static struct ctl_table sctp_table[] = {
#define SCTP_PF_RETRANS_IDX 2
#define SCTP_PS_RETRANS_IDX 3
-static struct ctl_table sctp_net_table[] = {
+static const struct ctl_table sctp_net_table[] = {
[SCTP_RTO_MIN_IDX] = {
.procname = "rto_min",
.data = &init_net.sctp.rto_min,
diff --git a/net/xfrm/xfrm_sysctl.c b/net/xfrm/xfrm_sysctl.c
index ca003e8a03760cd8dbb9e9f7cd5a9738eeeb7e71..357152a50faf10e5c33468c034dd1777e0bed079 100644
--- a/net/xfrm/xfrm_sysctl.c
+++ b/net/xfrm/xfrm_sysctl.c
@@ -13,7 +13,7 @@ static void __net_init __xfrm_sysctl_init(struct net *net)
}
#ifdef CONFIG_SYSCTL
-static struct ctl_table xfrm_table[] = {
+static const struct ctl_table xfrm_table[] = {
{
.procname = "xfrm_aevent_etime",
.maxlen = sizeof(u32),
--
2.50.1
^ permalink raw reply related
* [PATCH RFC net-next v3 1/3] net: enforce net sysctl registration
From: Joel Granados @ 2026-07-13 11:07 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, David Ahern, Ido Schimmel, Pablo Neira Ayuso,
Florian Westphal, Phil Sutter, Marcelo Ricardo Leitner, Xin Long,
Steffen Klassert, Herbert Xu, D. Wythe, Dust Li, Sidraya Jayagond,
Wenjia Zhang, Mahanta Jambigi, Tony Lu, Wen Gu, Kuniyuki Iwashima,
Stefano Garzarella
Cc: netdev, linux-kernel, netfilter-devel, coreteam, linux-sctp,
linux-rdma, linux-s390, virtualization, Joel Granados
In-Reply-To: <20260713-jag-net_const_qualify-v3-0-7289fe9eaea6@kernel.org>
Replace the warning and file permission change with an error when an
"unsafe" net sysctl registration is detected.
One of the barriers preventing the const qualification of the ctl_tables
in the net directory is the permission (->mode) change in
ensure_safe_net_sysctl. This prep commit removes that barrier and
ensures that the received ctl_table pointer to the net ctl_table
register function is const.
Signed-off-by: Joel Granados <joel.granados@kernel.org>
---
include/net/net_namespace.h | 4 ++--
net/sysctl_net.c | 24 ++++++++++++------------
2 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 80de5e98a66d6c9273aa7c5b9d489b22cef8559a..dca0ec809483bec604f4ca3d99dfea32834af8fa 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -522,12 +522,12 @@ struct ctl_table;
#ifdef CONFIG_SYSCTL
int net_sysctl_init(void);
struct ctl_table_header *register_net_sysctl_sz(struct net *net, const char *path,
- struct ctl_table *table, size_t table_size);
+ const struct ctl_table *table, size_t table_size);
void unregister_net_sysctl_table(struct ctl_table_header *header);
#else
static inline int net_sysctl_init(void) { return 0; }
static inline struct ctl_table_header *register_net_sysctl_sz(struct net *net,
- const char *path, struct ctl_table *table, size_t table_size)
+ const char *path, const struct ctl_table *table, size_t table_size)
{
return NULL;
}
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index 19e8048241bacb18de853d3b904d0f97fd2fe78a..4714887113d90a191c300c9c49a6317d5609efeb 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -114,16 +114,16 @@ __init int net_sysctl_init(void)
goto out;
}
-/* Verify that sysctls for non-init netns are safe by either:
+/* Return error when sysctls for non-init netns are unsafe by verifying:
* 1) being read-only, or
* 2) having a data pointer which points outside of the global kernel/module
* data segment, and rather into the heap where a per-net object was
* allocated.
*/
-static void ensure_safe_net_sysctl(struct net *net, const char *path,
- struct ctl_table *table, size_t table_size)
+static int ensure_safe_net_sysctl(struct net *net, const char *path,
+ const struct ctl_table *table, size_t table_size)
{
- struct ctl_table *ent;
+ const struct ctl_table *ent;
pr_debug("Registering net sysctl (net %p): %s\n", net, path);
ent = table;
@@ -149,24 +149,24 @@ static void ensure_safe_net_sysctl(struct net *net, const char *path,
else
continue;
- /* If it is writable and points to kernel/module global
- * data, then it's probably a netns leak.
- */
+ /* Warn on netns leak. */
WARN(1, "sysctl %s/%s: data points to %s global data: %ps\n",
- path, ent->procname, where, ent->data);
+ path, ent->procname, where, ent->data);
- /* Make it "safe" by dropping writable perms */
- ent->mode &= ~0222;
+ return -EACCES;
}
+
+ return 0;
}
struct ctl_table_header *register_net_sysctl_sz(struct net *net,
const char *path,
- struct ctl_table *table,
+ const struct ctl_table *table,
size_t table_size)
{
if (!net_eq(net, &init_net))
- ensure_safe_net_sysctl(net, path, table, table_size);
+ if (ensure_safe_net_sysctl(net, path, table, table_size))
+ return NULL;
return __register_sysctl_table(&net->sysctls, path, table, table_size);
}
--
2.50.1
^ permalink raw reply related
* Re: [PATCH v2 2/3] drm/virtio: honor blob_alignment requirements
From: Alyssa Ross @ 2026-07-13 11:19 UTC (permalink / raw)
To: Dmitry Osipenko, Sergio Lopez, Yiwei Zhang, Sergi Blanch Torne,
Valentine Burley
Cc: Chia-I Wu, Jason Wang, Michael S. Tsirkin, Eugenio Pérez,
Xuan Zhuo, linux-kernel, Simona Vetter, Thomas Zimmermann,
David Airlie, Gurchetan Singh, Gerd Hoffmann, virtualization,
dri-devel, Maxime Ripard, Maarten Lankhorst
In-Reply-To: <c8bf0c19-316a-442e-a63e-1b52e7bb67c2@collabora.com>
[-- Attachment #1: Type: text/plain, Size: 1791 bytes --]
Dmitry Osipenko <dmitry.osipenko@collabora.com> writes:
> On 7/1/26 14:10, Alyssa Ross wrote:
>> On Tue, Apr 28, 2026 at 09:44:49PM +0200, Sergio Lopez wrote:
>>> If VIRTIO_GPU_F_BLOB_ALIGNMENT has been negotiated, blob size must be
>>> aligned to blob_alignment. Validate this in verify_blob() so that
>>> invalid requests are rejected early.
>>>
>>> Signed-off-by: Sergio Lopez <slp@redhat.com>
>>
>> FYI: this change breaks crosvm, which is squatting the 5 and 6 values
>> of VIRTIO_GPU_F_* with different meanings. I've reported it as a
>> crosvm bug, so hopefully it can be taken care of there.
>>
>> https://issuetracker.google.com/issues/529852979
>>
>>> ---
>>> drivers/gpu/drm/virtio/virtgpu_ioctl.c | 5 +++++
>>> 1 file changed, 5 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
>>> index c33c057365f8..d0c4edf1eaf4 100644
>>> --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
>>> +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
>>> @@ -489,6 +489,11 @@ static int verify_blob(struct virtio_gpu_device *vgdev,
>>> params->size = rc_blob->size;
>>> params->blob = true;
>>> params->blob_flags = rc_blob->blob_flags;
>>> +
>>> + if (vgdev->has_blob_alignment &&
>>> + !IS_ALIGNED(params->size, vgdev->blob_alignment))
>>> + return -EINVAL;
>>> +
>>> return 0;
>>> }
>>>
>>> --
>>> 2.53.0
>>>
>
> Thanks for the report. Indeed, crosvm will need to fix its experimental
> caps. CI will likely run into this problem first once it will update
> guest to 7.2+ kernel.
I sent
https://chromium-review.googlesource.com/c/crosvm/crosvm/+/8064741 last
week but still waiting to hear anything. Do you have any insight into
whether it's still used / being pursued?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]
^ permalink raw reply
* [PATCH v2] drm/virtio: fix deadlock in display_info_cb by removing hotplug from dequeue worker
From: Ryosuke Yasuoka @ 2026-07-13 13:01 UTC (permalink / raw)
To: David Airlie, Gerd Hoffmann, Dmitry Osipenko, Gurchetan Singh,
Chia-I Wu, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Simona Vetter, Dmitry Baryshkov, Javier Martinez Canillas
Cc: dri-devel, virtualization, linux-kernel, Ryosuke Yasuoka
A probe-time deadlock can occur between the dequeue worker and
drm_client_register(). During probe, drm_client_register() holds
clientlist_mutex and calls the fbdev hotplug callback, which triggers an
atomic commit that ends up sleeping in virtio_gpu_queue_ctrl_sgs()
waiting for virtqueue space. The dequeue worker that would free that
space calls virtio_gpu_cmd_get_display_info_cb(), which invokes
drm_kms_helper_hotplug_event() -> drm_client_dev_hotplug(), attempting
to acquire the same clientlist_mutex. Since wake_up() is only called
after the resp_cb loop, the probe thread is never woken and both threads
deadlock.
Fix this by removing the hotplug notification from
virtio_gpu_cmd_get_display_info_cb(). The display data (outputs[i].info)
is still updated synchronously in the callback.
For the init path, drm_client_register() already fires an initial
hotplug when the client is registered, which picks up the connector
state updated by display_info_cb.
For the runtime config_changed path, add a wait_event_timeout() in
config_changed_work_func() so that display_info_cb updates the connector
data before the hotplug notification is sent. Also replace
drm_helper_hpd_irq_event() with drm_kms_helper_hotplug_event() since
virtio-gpu never calls drm_kms_helper_poll_init() and thus
drm_helper_hpd_irq_event() always returns false without doing anything.
Fixes: 27655b9bb9f0 ("drm/client: Send hotplug event after registering a client")
Closes: https://syzkaller.appspot.com/bug?id=d6dd6f86d3aaf7eebe7406e45c1c6e549453f224
Closes: https://syzkaller.appspot.com/bug?id=908bd910da5dd79b88de4cf7baf376cc873a922e
Suggested-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Signed-off-by: Ryosuke Yasuoka <ryasuoka@redhat.com>
---
I checked whether drm_helper_hpd_irq_event() is needed in
virtio_gpu_init(), as Dmitry suggested. AFAIS, it is not needed because:
1. drm_helper_hpd_irq_event() is always a no-op in virtio-gpu.
It returns false immediately probe_helper.c:1088 because
dev->mode_config.poll_enabled is false — virtio-gpu never calls
drm_kms_helper_poll_init(). Even if it passed that gate, no
virtio-gpu connectors set DRM_CONNECTOR_POLL_HPD.
1082 bool drm_helper_hpd_irq_event(struct drm_device *dev)
1083 {
...
1088 if (!dev->mode_config.poll_enabled)
1089 return false;
2. virtio_gpu_init() runs before drm_dev_register() and
drm_client_setup(), so no DRM clients are registered yet.
drm_kms_helper_hotplug_event() would iterate an empty client list.
The initial hotplug is handled by drm_client_register(), which fires
a hotplug callback to the newly registered client. By that time,
display_info_cb has already updated the connector data.
For the same reason, drm_helper_hpd_irq_event() in
config_changed_work_func() was also a no-op. The actual runtime hotplug
notification was always delivered by display_info_cb's call to
drm_kms_helper_hotplug_event(). This patch replaces it with a direct
drm_kms_helper_hotplug_event() call after waiting for the display info
response.
---
Changes in v2:
- Dropped the work_struct approach from v1.
- Instead, removed the hotplug calls from display_info_cb entirely, as
suggested by Dmitry.
- Added wait_event_timeout() in config_changed_work_func() so that the
display info response is received before sending the hotplug
notification.
- Replaced drm_helper_hpd_irq_event() with drm_kms_helper_hotplug_event()
in config_changed_work_func() since drm_helper_hpd_irq_event() is
always a no-op in virtio-gpu (poll_enabled is never set).
- No changes to virtio_gpu_init() — drm_client_register() already
handles the initial hotplug and hotplug event does nothing before DRM
device/client has been registered.
- Link to v1: https://lore.kernel.org/r/20260630-virtiogpu_syzbot-v1-1-0aa06630750e@redhat.com
---
drivers/gpu/drm/virtio/virtgpu_kms.c | 5 ++++-
drivers/gpu/drm/virtio/virtgpu_vq.c | 3 ---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c
index cfde9f573df6..b4329f28e976 100644
--- a/drivers/gpu/drm/virtio/virtgpu_kms.c
+++ b/drivers/gpu/drm/virtio/virtgpu_kms.c
@@ -49,7 +49,10 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work)
virtio_gpu_cmd_get_edids(vgdev);
virtio_gpu_cmd_get_display_info(vgdev);
virtio_gpu_notify(vgdev);
- drm_helper_hpd_irq_event(vgdev->ddev);
+ wait_event_timeout(vgdev->resp_wq,
+ !vgdev->display_info_pending,
+ 5 * HZ);
+ drm_kms_helper_hotplug_event(vgdev->ddev);
}
events_clear |= VIRTIO_GPU_EVENT_DISPLAY;
}
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
index c8b9475a7472..e5e1af8b8e8a 100644
--- a/drivers/gpu/drm/virtio/virtgpu_vq.c
+++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
@@ -840,9 +840,6 @@ static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev,
vgdev->display_info_pending = false;
spin_unlock(&vgdev->display_info_lock);
wake_up(&vgdev->resp_wq);
-
- if (!drm_helper_hpd_irq_event(vgdev->ddev))
- drm_kms_helper_hotplug_event(vgdev->ddev);
}
static void virtio_gpu_cmd_get_capset_info_cb(struct virtio_gpu_device *vgdev,
---
base-commit: a13c140cc289c0b7b3770bce5b3ad42ab35074aa
change-id: 20260619-virtiogpu_syzbot-bdab508ffcd5
Best regards,
--
Ryosuke Yasuoka <ryasuoka@redhat.com>
^ permalink raw reply related
* [PATCH] virtio_net: fix infinite loop in virtnet_poll_cleantx when device is broken
From: Jinqian Yang @ 2026-07-13 13:20 UTC (permalink / raw)
To: mst, jasowang, xuanzhuo, eperezma, andrew+netdev, davem, edumazet,
kuba, pabeni
Cc: netdev, virtualization, linux-kernel, liuyonglong, wangzhou1,
linuxarm, Jinqian Yang
virtnet_poll_cleantx() contains a do-while loop that cleans up
transmitted TX buffers and calls virtqueue_enable_cb_delayed() to check
whether more buffers need processing. When the virtio backend stops
responding during guest reboot, used->idx is never updated, so
virtqueue_enable_cb_delayed() always returns false and the loop never
terminates. Then it will block reboot process, and the guest will hang.
The problem occurs during guest reboot under network traffic:
1. kernel_restart() -> device_shutdown() traverses the device list
2. virtio_dev_shutdown() calls virtio_break_device() which sets
vq->broken = true
3. virtio_dev_shutdown() then calls virtio_synchronize_cbs() to wait
for in-flight callbacks to complete
4. A virtio interrupt fires, softirq is deferred to ksoftirqd which
calls net_rx_action() -> virtnet_poll() -> virtnet_poll_cleantx()
5. virtnet_poll_cleantx() enters the do-while loop and never exits
because the QEMU backend has stopped updating used->idx, despite
vq->broken having been set to true in step 2.
Since the loop runs inside ksoftirqd (a SCHED_OTHER kthread), it is
visible to the scheduler and does not trigger a hard lockup. However,
the kthread never leaves the loop, so RCU detects it as a CPU stall
and reports it periodically. Meanwhile, the reboot process remains
blocked in device_shutdown() because virtio_dev_shutdown() cannot
complete its synchronization step, and the guest hangs permanently.
This can be reproduced on a guest with a virtio-net device: run iperf3
traffic in the guest, then trigger reboot. The reboot occasionally hangs
permanently with RCU stall on ksoftirqd.
Observed on ARM64 KVM guest:
CPU#1 RCU stall (ksoftirqd/1), repeated periodically:
virtqueue_enable_cb_delayed_split <- virtnet_poll <- __napi_poll <-
net_rx_action <- handle_softirqs <- run_ksoftirqd <-
smpboot_thread_fn <- kthread
Fix by adding a virtqueue_is_broken() check to the loop condition, so
that the loop exits immediately when the device is broken, allowing
the device shutdown to proceed.
Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com>
---
drivers/net/virtio_net.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 7d2eeb9b1226..c8d2d420c31d 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -2970,7 +2970,8 @@ static void virtnet_poll_cleantx(struct receive_queue *rq, int budget)
do {
virtqueue_disable_cb(sq->vq);
free_old_xmit(sq, txq, !!budget);
- } while (unlikely(!virtqueue_enable_cb_delayed(sq->vq)));
+ } while (!virtqueue_is_broken(sq->vq) &&
+ unlikely(!virtqueue_enable_cb_delayed(sq->vq)));
if (sq->vq->num_free >= MAX_SKB_FRAGS + 2)
virtnet_tx_wake_queue(vi, sq);
--
2.33.0
^ permalink raw reply related
* Re: [PATCH v2 2/3] drm/virtio: honor blob_alignment requirements
From: Dmitry Osipenko @ 2026-07-13 14:34 UTC (permalink / raw)
To: Alyssa Ross, Sergio Lopez, Yiwei Zhang, Sergi Blanch Torne,
Valentine Burley
Cc: Chia-I Wu, Jason Wang, Michael S. Tsirkin, Eugenio Pérez,
Xuan Zhuo, linux-kernel, Simona Vetter, Thomas Zimmermann,
David Airlie, Gurchetan Singh, Gerd Hoffmann, virtualization,
dri-devel, Maxime Ripard, Maarten Lankhorst
In-Reply-To: <87v7ajyw5j.fsf@alyssa.is>
On 7/13/26 14:19, Alyssa Ross wrote:
> Dmitry Osipenko <dmitry.osipenko@collabora.com> writes:
>
>> On 7/1/26 14:10, Alyssa Ross wrote:
>>> On Tue, Apr 28, 2026 at 09:44:49PM +0200, Sergio Lopez wrote:
>>>> If VIRTIO_GPU_F_BLOB_ALIGNMENT has been negotiated, blob size must be
>>>> aligned to blob_alignment. Validate this in verify_blob() so that
>>>> invalid requests are rejected early.
>>>>
>>>> Signed-off-by: Sergio Lopez <slp@redhat.com>
>>>
>>> FYI: this change breaks crosvm, which is squatting the 5 and 6 values
>>> of VIRTIO_GPU_F_* with different meanings. I've reported it as a
>>> crosvm bug, so hopefully it can be taken care of there.
>>>
>>> https://issuetracker.google.com/issues/529852979
>>>
>>>> ---
>>>> drivers/gpu/drm/virtio/virtgpu_ioctl.c | 5 +++++
>>>> 1 file changed, 5 insertions(+)
>>>>
>>>> diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
>>>> index c33c057365f8..d0c4edf1eaf4 100644
>>>> --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
>>>> +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
>>>> @@ -489,6 +489,11 @@ static int verify_blob(struct virtio_gpu_device *vgdev,
>>>> params->size = rc_blob->size;
>>>> params->blob = true;
>>>> params->blob_flags = rc_blob->blob_flags;
>>>> +
>>>> + if (vgdev->has_blob_alignment &&
>>>> + !IS_ALIGNED(params->size, vgdev->blob_alignment))
>>>> + return -EINVAL;
>>>> +
>>>> return 0;
>>>> }
>>>>
>>>> --
>>>> 2.53.0
>>>>
>>
>> Thanks for the report. Indeed, crosvm will need to fix its experimental
>> caps. CI will likely run into this problem first once it will update
>> guest to 7.2+ kernel.
>
> I sent
> https://chromium-review.googlesource.com/c/crosvm/crosvm/+/8064741 last
> week but still waiting to hear anything. Do you have any insight into
> whether it's still used / being pursued?
The GUEST_HANDLE should be used by Android [1]. The FENCE_PASSING
shouldn't be used in production, though don't know for sure.
Crosvm should bump its experimental defines by +10 to prevent clash with
upstream in future.
[1]
https://github.com/google/gfxstream/blob/main/host/vulkan/vk_decoder_global_state.cpp#L107
--
Best regards,
Dmitry
^ permalink raw reply
* Re: [PATCH] drm/virtio: Don't detach GEM from a non-created context
From: Dmitry Osipenko @ 2026-07-13 16:18 UTC (permalink / raw)
To: Jason Macnak, David Airlie, Gerd Hoffmann, Gurchetan Singh,
Yiwei Zhang
Cc: dri-devel, virtualization, linux-kernel, stable
In-Reply-To: <20260625170828.3335431-1-natsu@google.com>
On 6/25/26 20:08, Jason Macnak wrote:
> Applies the same treatment as commit 7cf6dd467e87 ("drm/virtio:
> Don't attach GEM to a non-created context in gem_object_open()")
> to virtio_gpu_gem_object_close() to avoid trying to detach
> a resource that was never attached due to a context
> never being created when context_init is supported.
>
> Fixes: 086b9f27f0ab ("drm/virtio: Don't create a context with default param if context_init is supported")
> Cc: <stable@vger.kernel.org> # v6.14+
> Signed-off-by: Jason Macnak <natsu@google.com>
> ---
> drivers/gpu/drm/virtio/virtgpu_gem.c | 14 ++++++++------
> 1 file changed, 8 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c
> index 435d37d36034..66c3f6f74e9c 100644
> --- a/drivers/gpu/drm/virtio/virtgpu_gem.c
> +++ b/drivers/gpu/drm/virtio/virtgpu_gem.c
> @@ -139,13 +139,15 @@ void virtio_gpu_gem_object_close(struct drm_gem_object *obj,
> if (!vgdev->has_virgl_3d)
> return;
>
> - objs = virtio_gpu_array_alloc(1);
> - if (!objs)
> - return;
> - virtio_gpu_array_add_obj(objs, obj);
> + if (vfpriv->context_created) {
> + objs = virtio_gpu_array_alloc(1);
> + if (!objs)
> + return;
> + virtio_gpu_array_add_obj(objs, obj);
>
> - virtio_gpu_cmd_context_detach_resource(vgdev, vfpriv->ctx_id,
> - objs);
> + virtio_gpu_cmd_context_detach_resource(vgdev, vfpriv->ctx_id,
> + objs);
> + }
> virtio_gpu_notify(vgdev);
> }
>
Applied to misc-fixes, thanks!
--
Best regards,
Dmitry
^ permalink raw reply
* Re: [PATCH v2] drm/virtio: fix deadlock in display_info_cb by removing hotplug from dequeue worker
From: Dmitry Osipenko @ 2026-07-13 16:31 UTC (permalink / raw)
To: Ryosuke Yasuoka, David Airlie, Gerd Hoffmann, Gurchetan Singh,
Chia-I Wu, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Simona Vetter, Dmitry Baryshkov, Javier Martinez Canillas
Cc: dri-devel, virtualization, linux-kernel
In-Reply-To: <20260713-virtiogpu_syzbot-v2-1-2958fa37d46d@redhat.com>
On 7/13/26 16:01, Ryosuke Yasuoka wrote:
> A probe-time deadlock can occur between the dequeue worker and
> drm_client_register(). During probe, drm_client_register() holds
> clientlist_mutex and calls the fbdev hotplug callback, which triggers an
> atomic commit that ends up sleeping in virtio_gpu_queue_ctrl_sgs()
> waiting for virtqueue space. The dequeue worker that would free that
> space calls virtio_gpu_cmd_get_display_info_cb(), which invokes
> drm_kms_helper_hotplug_event() -> drm_client_dev_hotplug(), attempting
> to acquire the same clientlist_mutex. Since wake_up() is only called
> after the resp_cb loop, the probe thread is never woken and both threads
> deadlock.
>
> Fix this by removing the hotplug notification from
> virtio_gpu_cmd_get_display_info_cb(). The display data (outputs[i].info)
> is still updated synchronously in the callback.
>
> For the init path, drm_client_register() already fires an initial
> hotplug when the client is registered, which picks up the connector
> state updated by display_info_cb.
>
> For the runtime config_changed path, add a wait_event_timeout() in
> config_changed_work_func() so that display_info_cb updates the connector
> data before the hotplug notification is sent. Also replace
> drm_helper_hpd_irq_event() with drm_kms_helper_hotplug_event() since
> virtio-gpu never calls drm_kms_helper_poll_init() and thus
> drm_helper_hpd_irq_event() always returns false without doing anything.
>
> Fixes: 27655b9bb9f0 ("drm/client: Send hotplug event after registering a client")
> Closes: https://syzkaller.appspot.com/bug?id=d6dd6f86d3aaf7eebe7406e45c1c6e549453f224
> Closes: https://syzkaller.appspot.com/bug?id=908bd910da5dd79b88de4cf7baf376cc873a922e
> Suggested-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> Signed-off-by: Ryosuke Yasuoka <ryasuoka@redhat.com>
> ---
> I checked whether drm_helper_hpd_irq_event() is needed in
> virtio_gpu_init(), as Dmitry suggested. AFAIS, it is not needed because:
>
> 1. drm_helper_hpd_irq_event() is always a no-op in virtio-gpu.
> It returns false immediately probe_helper.c:1088 because
> dev->mode_config.poll_enabled is false — virtio-gpu never calls
> drm_kms_helper_poll_init(). Even if it passed that gate, no
> virtio-gpu connectors set DRM_CONNECTOR_POLL_HPD.
>
> 1082 bool drm_helper_hpd_irq_event(struct drm_device *dev)
> 1083 {
> ...
> 1088 if (!dev->mode_config.poll_enabled)
> 1089 return false;
>
> 2. virtio_gpu_init() runs before drm_dev_register() and
> drm_client_setup(), so no DRM clients are registered yet.
> drm_kms_helper_hotplug_event() would iterate an empty client list.
> The initial hotplug is handled by drm_client_register(), which fires
> a hotplug callback to the newly registered client. By that time,
> display_info_cb has already updated the connector data.
>
> For the same reason, drm_helper_hpd_irq_event() in
> config_changed_work_func() was also a no-op. The actual runtime hotplug
> notification was always delivered by display_info_cb's call to
> drm_kms_helper_hotplug_event(). This patch replaces it with a direct
> drm_kms_helper_hotplug_event() call after waiting for the display info
> response.
> ---
> Changes in v2:
> - Dropped the work_struct approach from v1.
> - Instead, removed the hotplug calls from display_info_cb entirely, as
> suggested by Dmitry.
> - Added wait_event_timeout() in config_changed_work_func() so that the
> display info response is received before sending the hotplug
> notification.
> - Replaced drm_helper_hpd_irq_event() with drm_kms_helper_hotplug_event()
> in config_changed_work_func() since drm_helper_hpd_irq_event() is
> always a no-op in virtio-gpu (poll_enabled is never set).
> - No changes to virtio_gpu_init() — drm_client_register() already
> handles the initial hotplug and hotplug event does nothing before DRM
> device/client has been registered.
> - Link to v1: https://lore.kernel.org/r/20260630-virtiogpu_syzbot-v1-1-0aa06630750e@redhat.com
> ---
> drivers/gpu/drm/virtio/virtgpu_kms.c | 5 ++++-
> drivers/gpu/drm/virtio/virtgpu_vq.c | 3 ---
> 2 files changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c
> index cfde9f573df6..b4329f28e976 100644
> --- a/drivers/gpu/drm/virtio/virtgpu_kms.c
> +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c
> @@ -49,7 +49,10 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work)
> virtio_gpu_cmd_get_edids(vgdev);
> virtio_gpu_cmd_get_display_info(vgdev);
> virtio_gpu_notify(vgdev);
> - drm_helper_hpd_irq_event(vgdev->ddev);
> + wait_event_timeout(vgdev->resp_wq,
> + !vgdev->display_info_pending,
> + 5 * HZ);
> + drm_kms_helper_hotplug_event(vgdev->ddev);
> }
> events_clear |= VIRTIO_GPU_EVENT_DISPLAY;
> }
> diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
> index c8b9475a7472..e5e1af8b8e8a 100644
> --- a/drivers/gpu/drm/virtio/virtgpu_vq.c
> +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
> @@ -840,9 +840,6 @@ static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev,
> vgdev->display_info_pending = false;
> spin_unlock(&vgdev->display_info_lock);
> wake_up(&vgdev->resp_wq);
> -
> - if (!drm_helper_hpd_irq_event(vgdev->ddev))
> - drm_kms_helper_hotplug_event(vgdev->ddev);
> }
>
> static void virtio_gpu_cmd_get_capset_info_cb(struct virtio_gpu_device *vgdev,
>
> ---
> base-commit: a13c140cc289c0b7b3770bce5b3ad42ab35074aa
> change-id: 20260619-virtiogpu_syzbot-bdab508ffcd5
>
> Best regards,
Appled to misc-fixes, thanks!
--
Best regards,
Dmitry
^ permalink raw reply
* Re: [RFC] virtio_balloon: fix Use-After-Free in page reporting during PM freeze
From: David Rientjes @ 2026-07-13 19:41 UTC (permalink / raw)
To: Link Lin
Cc: Andrew Morton, Vlastimil Babka, Michael S . Tsirkin,
David Hildenbrand, virtualization, linux-mm, linux-kernel, prasin,
duenwen, jasowang, xuanzhuo, Ammar Faizi, jiaqiyan, ahwilkins,
Greg Thelen, Alexander Duyck, stable
In-Reply-To: <CALUx4KQ=bYTpDoDAZ+iVb7Ehaa0LmyPDsEWk3xFFmTVYKrpAUA@mail.gmail.com>
On Thu, 9 Jul 2026, Link Lin wrote:
> > > Fix this by:
> > > 1. Unregistering page reporting in virtballoon_freeze() prior to calling
> > > remove_common(). This clears the RCU pr_dev_info pointer and flushes/
> > > cancels prdev->work on system_wq via cancel_delayed_work_sync().
> > > 2. Re-registering page reporting in virtballoon_restore() after the
> > > virtqueues are re-initialized and virtio_device_ready() has been called.
> > > 3. Unwinding virtqueue initialization via remove_common() in
> > > virtballoon_restore() if page_reporting_register() fails.
> >
> > AI review thinks the patch didn't do the above:
> > https://sashiko.dev/#/patchset/20260709224330.946683-1-linkl@google.com
>
> The AI reviewer might not have parsed the entirety of the fix I proposed.
> The patch submitted definitely includes the changes to virtballoon_restore()
> for steps 2 and 3 (re-registering page reporting and unwinding init_vqs
> on failure). It seems the AI failed to parse the diff correctly. See:
>
> + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_REPORTING)) {
> + ret = page_reporting_register(&vb->pr_dev_info);
> + if (ret)
> + goto out_remove_vqs;
> + }
> +
> if (towards_target(vb))
> virtballoon_changed(vdev);
> update_balloon_size(vb);
> return 0;
> +
> +out_remove_vqs:
> + remove_common(vb);
> + return ret;
> }
>
> > It also might have found a couple of pre-existing bugs in there.
>
> Indeed. Regarding the first pre-existing bug found by the AI (leaving the
> OOM notifier registered during suspend, leading to a UAF if memory pressure
> spikes during S4 hibernation):
>
> I actually addressed this in the commit message:
>
> "(Note: The OOM Notifier and Shrinker/Free Page Hinting features suffer
> from an identical lifecycle flaw and are also vulnerable to UAFs during
> S4 hibernation when memory pressure spikes. This patch focuses on Free
> Page Reporting, which runs periodically, to ensure clean backports to
> stable kernels)."
>
> Regarding the second pre-existing bug the AI flagged (leaving uncancelled
> works on system_freezable_wq if virtballoon_restore fails on the cold path):
> the AI is correct that this asynchronous work cancellation failure exists.
>
> Since these are separate, pre-existing lifecycle bugs, would you prefer I
> roll fixes for the OOM notifier, shrinker/free page hinting, and work
> cancellations into a v2 of this patch, or submit them as a separate patch
> series to keep the stable backports clean?
>
I think it would be best to have separate patches for each fix; Andrew,
please correct me if you'd prefer one patch to address everything.
^ permalink raw reply
* Re: [RFC] virtio_balloon: fix Use-After-Free in page reporting during PM freeze
From: Michael S. Tsirkin @ 2026-07-13 19:43 UTC (permalink / raw)
To: David Rientjes
Cc: Link Lin, Andrew Morton, Vlastimil Babka, David Hildenbrand,
virtualization, linux-mm, linux-kernel, prasin, duenwen, jasowang,
xuanzhuo, Ammar Faizi, jiaqiyan, ahwilkins, Greg Thelen,
Alexander Duyck, stable
In-Reply-To: <59e3dae7-a203-2e1d-3b65-875b7e0e122b@google.com>
On Mon, Jul 13, 2026 at 12:41:07PM -0700, David Rientjes wrote:
> On Thu, 9 Jul 2026, Link Lin wrote:
>
> > > > Fix this by:
> > > > 1. Unregistering page reporting in virtballoon_freeze() prior to calling
> > > > remove_common(). This clears the RCU pr_dev_info pointer and flushes/
> > > > cancels prdev->work on system_wq via cancel_delayed_work_sync().
> > > > 2. Re-registering page reporting in virtballoon_restore() after the
> > > > virtqueues are re-initialized and virtio_device_ready() has been called.
> > > > 3. Unwinding virtqueue initialization via remove_common() in
> > > > virtballoon_restore() if page_reporting_register() fails.
> > >
> > > AI review thinks the patch didn't do the above:
> > > https://sashiko.dev/#/patchset/20260709224330.946683-1-linkl@google.com
> >
> > The AI reviewer might not have parsed the entirety of the fix I proposed.
> > The patch submitted definitely includes the changes to virtballoon_restore()
> > for steps 2 and 3 (re-registering page reporting and unwinding init_vqs
> > on failure). It seems the AI failed to parse the diff correctly. See:
> >
> > + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_REPORTING)) {
> > + ret = page_reporting_register(&vb->pr_dev_info);
> > + if (ret)
> > + goto out_remove_vqs;
> > + }
> > +
> > if (towards_target(vb))
> > virtballoon_changed(vdev);
> > update_balloon_size(vb);
> > return 0;
> > +
> > +out_remove_vqs:
> > + remove_common(vb);
> > + return ret;
> > }
> >
> > > It also might have found a couple of pre-existing bugs in there.
> >
> > Indeed. Regarding the first pre-existing bug found by the AI (leaving the
> > OOM notifier registered during suspend, leading to a UAF if memory pressure
> > spikes during S4 hibernation):
> >
> > I actually addressed this in the commit message:
> >
> > "(Note: The OOM Notifier and Shrinker/Free Page Hinting features suffer
> > from an identical lifecycle flaw and are also vulnerable to UAFs during
> > S4 hibernation when memory pressure spikes. This patch focuses on Free
> > Page Reporting, which runs periodically, to ensure clean backports to
> > stable kernels)."
> >
> > Regarding the second pre-existing bug the AI flagged (leaving uncancelled
> > works on system_freezable_wq if virtballoon_restore fails on the cold path):
> > the AI is correct that this asynchronous work cancellation failure exists.
> >
> > Since these are separate, pre-existing lifecycle bugs, would you prefer I
> > roll fixes for the OOM notifier, shrinker/free page hinting, and work
> > cancellations into a v2 of this patch, or submit them as a separate patch
> > series to keep the stable backports clean?
> >
>
> I think it would be best to have separate patches for each fix; Andrew,
> please correct me if you'd prefer one patch to address everything.
It does not matter much but yes separate ones are a bit better if
each can be applied independently.
^ permalink raw reply
* Re: [PATCH v2 0/4] virtio_balloon: quiesce balloon work on device shutdown
From: Denis V. Lunev @ 2026-07-13 20:32 UTC (permalink / raw)
To: Michael S. Tsirkin, David Hildenbrand (Arm)
Cc: Denis V. Lunev, virtualization, linux-kernel
In-Reply-To: <20260702183236-mutt-send-email-mst@kernel.org>
On 7/3/26 00:33, Michael S. Tsirkin wrote:
> On Thu, Jul 02, 2026 at 09:30:26PM +0200, David Hildenbrand (Arm) wrote:
>> On 7/2/26 19:50, Denis V. Lunev wrote:
>>> On 6/24/26 16:08, Denis V. Lunev wrote:
>>>> This email originated from an IP that might not be authorized by the domain it was sent from.
>>>> Do not click links or open attachments unless it is an email you expected to receive.
>>>> Since commit 8bd2fa086a04 ("virtio: break and reset virtio devices on
>>>> device_shutdown()") the virtio bus breaks and resets every virtio device
>>>> during device_shutdown(), i.e. on reboot and kexec. virtio_balloon has no
>>>> .shutdown of its own, so that generic path runs while the balloon's
>>>> asynchronous work is still armed: the free page reporting worker, the
>>>> inflate/deflate and stats workers, the OOM notifier and the free page
>>>> shrinker.
>>>>
>>>> Once the device has been broken, virtqueue_add_inbuf() in
>>>> virtballoon_free_page_report() returns -EIO and trips its WARN_ON_ONCE().
>>>> On a kernel booted with panic_on_warn that turns an ordinary reboot into a
>>>> fatal panic in the middle of device_shutdown(), so the machine never
>>>> reaches the new kernel. The inflate/deflate and OOM paths do not warn but
>>>> are no better off: they call wait_event(vb->acked, ...) and would block
>>>> forever on a queue that can no longer complete.
>>>>
>>>> This was hit in the field as an intermittent failure of a virtualization
>>>> cluster upgrade: guest storage nodes were rebooted via kexec into the new
>>>> kernel, and the ones whose free page reporting happened to run during
>>>> device_shutdown() panicked (the guests run with panic_on_warn) and never
>>>> came back, stalling the rolling upgrade. The crash dump showed the WARN at
>>>> virtio_balloon.c:216 in a page_reporting kworker, with all the balloon
>>>> virtqueues already broken.
>>>>
>>>> Validated by churning balloon inflate/deflate from the host while
>>>> kexec-rebooting the guest in a loop under panic_on_warn: the unpatched
>>>> kernel reproduces the WARN within a couple of cycles, while the patched
>>>> kernel survives many consecutive kexec cycles cleanly (12/12 in the final
>>>> run, 0 WARNs). checkpatch is clean across the series.
>>>>
>>>> Changes in v2:
>>>> - Add a virtio_device_shutdown() core helper and call it from the balloon
>>>> .shutdown handler instead of open-coding break + synchronize_cbs + reset
>>>> (David Hildenbrand).
>>>> - New patch: make tell_host() warn and bail instead of hanging if a buffer
>>>> add ever fails (David Hildenbrand); kept as a separate patch
>>>> (Michael S. Tsirkin).
>>>>
>>>> v1: https://lore.kernel.org/all/20260622133715.3707707-1-den@openvz.org
>>>>
>>>> Denis V. Lunev (4):
>>>> virtio: add virtio_device_shutdown() helper
>>>> virtio_balloon: factor out virtballoon_quiesce()
>>>> virtio_balloon: quiesce balloon work before device shutdown
>>>> virtio_balloon: warn on failed buffer add in tell_host()
>>>>
>>>> drivers/virtio/virtio.c | 41 ++++++++++++++++++++++-----------
>>>> drivers/virtio/virtio_balloon.c | 40 ++++++++++++++++++++++++--------
>>>> include/linux/virtio.h | 1 +
>>>> 3 files changed, 59 insertions(+), 23 deletions(-)
>>>>
>>> Hi, David!
>> Hi! :)
>>
>>> Is this good to go in? I have not seen the confirmation that the
>>> series is taken into your tree.
>> I don't have a tree (yet), and once I have one it will likely be more mm focused :)
>>
>> @MST, I think this is good to go!
>>
>> --
>> Cheers,
>>
>> David
> Indeed, it's just a bugfix and I'm trying to get features into qemu
> now before their freeze. I'll work on linux end of next week.
>
Hi, Michael!
Have you had a chance to take series into your tree, i.e.
should I continue to track this submission?
Thank you in advance,
Den
^ permalink raw reply
* Re: [PATCH v2 0/4] virtio_balloon: quiesce balloon work on device shutdown
From: Michael S. Tsirkin @ 2026-07-13 20:37 UTC (permalink / raw)
To: Denis V. Lunev
Cc: David Hildenbrand (Arm), Denis V. Lunev, virtualization,
linux-kernel
In-Reply-To: <6697d41e-a2fd-4207-982d-999cafd3cd56@virtuozzo.com>
On Mon, Jul 13, 2026 at 10:32:29PM +0200, Denis V. Lunev wrote:
> On 7/3/26 00:33, Michael S. Tsirkin wrote:
> > On Thu, Jul 02, 2026 at 09:30:26PM +0200, David Hildenbrand (Arm) wrote:
> >> On 7/2/26 19:50, Denis V. Lunev wrote:
> >>> On 6/24/26 16:08, Denis V. Lunev wrote:
> >>>> This email originated from an IP that might not be authorized by the domain it was sent from.
> >>>> Do not click links or open attachments unless it is an email you expected to receive.
> >>>> Since commit 8bd2fa086a04 ("virtio: break and reset virtio devices on
> >>>> device_shutdown()") the virtio bus breaks and resets every virtio device
> >>>> during device_shutdown(), i.e. on reboot and kexec. virtio_balloon has no
> >>>> .shutdown of its own, so that generic path runs while the balloon's
> >>>> asynchronous work is still armed: the free page reporting worker, the
> >>>> inflate/deflate and stats workers, the OOM notifier and the free page
> >>>> shrinker.
> >>>>
> >>>> Once the device has been broken, virtqueue_add_inbuf() in
> >>>> virtballoon_free_page_report() returns -EIO and trips its WARN_ON_ONCE().
> >>>> On a kernel booted with panic_on_warn that turns an ordinary reboot into a
> >>>> fatal panic in the middle of device_shutdown(), so the machine never
> >>>> reaches the new kernel. The inflate/deflate and OOM paths do not warn but
> >>>> are no better off: they call wait_event(vb->acked, ...) and would block
> >>>> forever on a queue that can no longer complete.
> >>>>
> >>>> This was hit in the field as an intermittent failure of a virtualization
> >>>> cluster upgrade: guest storage nodes were rebooted via kexec into the new
> >>>> kernel, and the ones whose free page reporting happened to run during
> >>>> device_shutdown() panicked (the guests run with panic_on_warn) and never
> >>>> came back, stalling the rolling upgrade. The crash dump showed the WARN at
> >>>> virtio_balloon.c:216 in a page_reporting kworker, with all the balloon
> >>>> virtqueues already broken.
> >>>>
> >>>> Validated by churning balloon inflate/deflate from the host while
> >>>> kexec-rebooting the guest in a loop under panic_on_warn: the unpatched
> >>>> kernel reproduces the WARN within a couple of cycles, while the patched
> >>>> kernel survives many consecutive kexec cycles cleanly (12/12 in the final
> >>>> run, 0 WARNs). checkpatch is clean across the series.
> >>>>
> >>>> Changes in v2:
> >>>> - Add a virtio_device_shutdown() core helper and call it from the balloon
> >>>> .shutdown handler instead of open-coding break + synchronize_cbs + reset
> >>>> (David Hildenbrand).
> >>>> - New patch: make tell_host() warn and bail instead of hanging if a buffer
> >>>> add ever fails (David Hildenbrand); kept as a separate patch
> >>>> (Michael S. Tsirkin).
> >>>>
> >>>> v1: https://lore.kernel.org/all/20260622133715.3707707-1-den@openvz.org
> >>>>
> >>>> Denis V. Lunev (4):
> >>>> virtio: add virtio_device_shutdown() helper
> >>>> virtio_balloon: factor out virtballoon_quiesce()
> >>>> virtio_balloon: quiesce balloon work before device shutdown
> >>>> virtio_balloon: warn on failed buffer add in tell_host()
> >>>>
> >>>> drivers/virtio/virtio.c | 41 ++++++++++++++++++++++-----------
> >>>> drivers/virtio/virtio_balloon.c | 40 ++++++++++++++++++++++++--------
> >>>> include/linux/virtio.h | 1 +
> >>>> 3 files changed, 59 insertions(+), 23 deletions(-)
> >>>>
> >>> Hi, David!
> >> Hi! :)
> >>
> >>> Is this good to go in? I have not seen the confirmation that the
> >>> series is taken into your tree.
> >> I don't have a tree (yet), and once I have one it will likely be more mm focused :)
> >>
> >> @MST, I think this is good to go!
> >>
> >> --
> >> Cheers,
> >>
> >> David
> > Indeed, it's just a bugfix and I'm trying to get features into qemu
> > now before their freeze. I'll work on linux end of next week.
> >
> Hi, Michael!
>
> Have you had a chance to take series into your tree, i.e.
> should I continue to track this submission?
>
> Thank you in advance,
> Den
Hi!
It's on my queue and will be in the next Linux release, don't worry.
--
MST
^ permalink raw reply
* Re: [PATCH v2 00/13] mm: convert more vm_flags_t users to vma_flags_t
From: Andrew Morton @ 2026-07-14 2:25 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: David Hildenbrand, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Thomas Bogendoerfer, Benjamin LaHaise, Alexander Viro,
Christian Brauner, Jan Kara, Hugh Dickins, Baolin Wang, Jann Horn,
Pedro Falcato, Muchun Song, Oscar Salvador, Zi Yan, Nico Pache,
Ryan Roberts, Dev Jain, Barry Song, Lance Yang, Usama Arif,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Lucas Stach,
Russell King, Christian Gmeiner, Inki Dae, Seung-Woo Kim,
Kyungmin Park, Krzysztof Kozlowski, Peter Griffin, Alim Akhtar,
Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin,
Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, Lyude Paul, Danilo Krummrich,
Tomi Valkeinen, Sandy Huang, Heiko Stübner, Andy Yan,
Thierry Reding, Mikko Perttunen, Jonathan Hunter, Gerd Hoffmann,
Dmitry Osipenko, Gurchetan Singh, Chia-I Wu, Zack Rusin,
Broadcom internal kernel review list, Matthew Brost,
Thomas Hellström, Oleksandr Andrushchenko, Helge Deller,
Kees Cook, Jaroslav Kysela, Takashi Iwai, Boris Brezillon,
Steven Price, Liviu Dudau, linux-mm, linux-kernel, linux-mips,
linux-aio, linux-fsdevel, linuxppc-dev, dri-devel, etnaviv,
linux-arm-kernel, linux-samsung-soc, intel-gfx, linux-arm-msm,
freedreno, nouveau, linux-rockchip, linux-tegra, virtualization,
intel-xe, xen-devel, linux-fbdev, linux-sound, Jani Nikula
In-Reply-To: <20260711-b4-vma-flags-mm-v2-0-0fa2357d5431@kernel.org>
On Sat, 11 Jul 2026 19:44:57 +0100 Lorenzo Stoakes <ljs@kernel.org> wrote:
> This series makes further progress in converting usage of the deprecated
> vm_flags_t type to its replacement, vma_flags_t.
>
> It focuses on mm, though updates some users of mm APIs also.
>
> It updates:
>
> * The core do_mmap() code path for VMA mapping.
> * Unmapped area logic.
> * The usage of mm->def_vma_flags.
> * VMA page protection bit logic.
> * General usage of VMA flags in core mm code, mlock, mprotect, mremap.
Added to mm-new, thanks.
And oh my, what a lot of pre-existing issues:
https://sashiko.dev/#/patchset/20260711-b4-vma-flags-mm-v2-0-0fa2357d5431@kernel.org
^ permalink raw reply
* [PATCH] virtio_net: fix spelling of aggressively in comments
From: weimin xiong @ 2026-07-14 2:40 UTC (permalink / raw)
To: netdev; +Cc: mst, jasowangio, xuanzhuo, eperezma, virtualization, xiongweimin
From: xiongweimin <xiongweimin@kylinos.cn>
Two receive-path comments misspell "aggressively" as "agressively".
Signed-off-by: xiongweimin <xiongweimin@kylinos.cn>
---
drivers/net/virtio_net.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 3e2a5876c..f3c7b28ce 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -3190,7 +3190,7 @@ static int virtnet_open(struct net_device *dev)
for (i = 0; i < vi->max_queue_pairs; i++) {
if (i < vi->curr_queue_pairs)
- /* Pre-fill rq agressively, to make sure we are ready to
+ /* Pre-fill rq aggressively, to make sure we are ready to
* get packets immediately.
*/
try_fill_recv(vi, &vi->rq[i], GFP_KERNEL);
@@ -3419,7 +3419,7 @@ static void virtnet_rx_resume(struct virtnet_info *vi,
bool refill)
{
if (netif_running(vi->dev)) {
- /* Pre-fill rq agressively, to make sure we are ready to get
+ /* Pre-fill rq aggressively, to make sure we are ready to get
* packets immediately.
*/
if (refill)
--
2.43.0
No virus found
Checked by Hillstone Network AntiVirus
^ permalink raw reply related
* [PATCH] virtio: rtc: time out alarm requests
From: GuoHan Zhao @ 2026-07-14 2:43 UTC (permalink / raw)
To: Peter Hilber, Michael S. Tsirkin, virtualization
Cc: Jason Wang, Xuan Zhuo, Eugenio Pérez, Alexandre Belloni,
linux-kernel
RTC class operations run with rtc_device.ops_lock held. The virtio RTC
alarm requests currently wait without a timeout for the device to return
their requestq buffers.
On surprise removal, virtio-pci marks the virtqueues broken before
unregistering the virtio device. If an alarm request is waiting when the
device stops responding, viortc_remove() blocks in viortc_class_stop()
while trying to acquire ops_lock. The request cannot complete and device
removal hangs until the waiting task is signalled.
Use the same 60-second timeout as clock read requests for alarm reads,
alarm programming, and alarm interrupt enable requests. The existing
message reference counting keeps a timed-out request alive until a late
response or device teardown.
Fixes: 9d4f22fd563e ("virtio_rtc: Add RTC class driver")
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: GuoHan Zhao <zhaoguohan@kylinos.cn>
---
drivers/virtio/virtio_rtc_driver.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/virtio/virtio_rtc_driver.c b/drivers/virtio/virtio_rtc_driver.c
index 4419735b0f0d..74616ba5be11 100644
--- a/drivers/virtio/virtio_rtc_driver.c
+++ b/drivers/virtio/virtio_rtc_driver.c
@@ -574,8 +574,8 @@ static int viortc_msg_xfer(struct viortc_vq *vq, struct viortc_msg *msg,
* read requests
*/
-/** timeout for clock readings, where timeouts are considered non-fatal */
-#define VIORTC_MSG_READ_TIMEOUT secs_to_jiffies(60)
+/** timeout for runtime requests, where timeouts are considered non-fatal */
+#define VIORTC_MSG_TIMEOUT secs_to_jiffies(60)
/**
* viortc_read() - VIRTIO_RTC_REQ_READ wrapper
@@ -600,7 +600,7 @@ int viortc_read(struct viortc_dev *viortc, u16 vio_clk_id, u64 *reading)
VIORTC_MSG_WRITE(hdl, clock_id, &vio_clk_id);
ret = viortc_msg_xfer(&viortc->vqs[VIORTC_REQUESTQ], VIORTC_MSG(hdl),
- VIORTC_MSG_READ_TIMEOUT);
+ VIORTC_MSG_TIMEOUT);
if (ret) {
dev_dbg(&viortc->vdev->dev, "%s: xfer returned %d\n", __func__,
ret);
@@ -642,7 +642,7 @@ int viortc_read_cross(struct viortc_dev *viortc, u16 vio_clk_id, u8 hw_counter,
VIORTC_MSG_WRITE(hdl, hw_counter, &hw_counter);
ret = viortc_msg_xfer(&viortc->vqs[VIORTC_REQUESTQ], VIORTC_MSG(hdl),
- VIORTC_MSG_READ_TIMEOUT);
+ VIORTC_MSG_TIMEOUT);
if (ret) {
dev_dbg(&viortc->vdev->dev, "%s: xfer returned %d\n", __func__,
ret);
@@ -809,7 +809,7 @@ int viortc_read_alarm(struct viortc_dev *viortc, u16 vio_clk_id,
VIORTC_MSG_WRITE(hdl, clock_id, &vio_clk_id);
ret = viortc_msg_xfer(&viortc->vqs[VIORTC_REQUESTQ], VIORTC_MSG(hdl),
- 0);
+ VIORTC_MSG_TIMEOUT);
if (ret) {
dev_dbg(&viortc->vdev->dev, "%s: xfer returned %d\n", __func__,
ret);
@@ -858,7 +858,7 @@ int viortc_set_alarm(struct viortc_dev *viortc, u16 vio_clk_id, u64 alarm_time,
VIORTC_MSG_WRITE(hdl, flags, &flags);
ret = viortc_msg_xfer(&viortc->vqs[VIORTC_REQUESTQ], VIORTC_MSG(hdl),
- 0);
+ VIORTC_MSG_TIMEOUT);
if (ret) {
dev_dbg(&viortc->vdev->dev, "%s: xfer returned %d\n", __func__,
ret);
@@ -900,7 +900,7 @@ int viortc_set_alarm_enabled(struct viortc_dev *viortc, u16 vio_clk_id,
VIORTC_MSG_WRITE(hdl, flags, &flags);
ret = viortc_msg_xfer(&viortc->vqs[VIORTC_REQUESTQ], VIORTC_MSG(hdl),
- 0);
+ VIORTC_MSG_TIMEOUT);
if (ret) {
dev_dbg(&viortc->vdev->dev, "%s: xfer returned %d\n", __func__,
ret);
base-commit: 3b029c035b34bbc693405ddf759f0e9b920c27f1
--
2.43.0
^ permalink raw reply related
* [PATCH] vhost: fix inaccurate kdoc in iotlb helpers
From: weimin xiong @ 2026-07-14 2:44 UTC (permalink / raw)
To: virtualization; +Cc: mst, jasowangio, eperezma, kvm, xiongweimin
From: xiongweimin <xiongweimin@kylinos.cn>
Correct missing "if" in the add_range_ctx return description, and
align vhost_iotlb_alloc documentation with its NULL return on
allocation failure.
Signed-off-by: xiongweimin <xiongweimin@kylinos.cn>
---
drivers/vhost/iotlb.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/vhost/iotlb.c b/drivers/vhost/iotlb.c
index e1414c774..10d1c4073 100644
--- a/drivers/vhost/iotlb.c
+++ b/drivers/vhost/iotlb.c
@@ -44,7 +44,7 @@ EXPORT_SYMBOL_GPL(vhost_iotlb_map_free);
* @perm: access permission of this range
* @opaque: the opaque pointer for the new mapping
*
- * Returns an error last is smaller than start or memory allocation
+ * Returns an error if last is smaller than start or memory allocation
* fails
*/
int vhost_iotlb_add_range_ctx(struct vhost_iotlb *iotlb,
@@ -143,11 +143,11 @@ void vhost_iotlb_init(struct vhost_iotlb *iotlb, unsigned int limit,
EXPORT_SYMBOL_GPL(vhost_iotlb_init);
/**
- * vhost_iotlb_alloc - add a new vhost IOTLB
+ * vhost_iotlb_alloc - allocate a new vhost IOTLB
* @limit: maximum number of IOTLB entries
* @flags: VHOST_IOTLB_FLAG_XXX
*
- * Returns an error is memory allocation fails
+ * Returns NULL if memory allocation fails
*/
struct vhost_iotlb *vhost_iotlb_alloc(unsigned int limit, unsigned int flags)
{
--
2.43.0
No virus found
Checked by Hillstone Network AntiVirus
^ permalink raw reply related
* [PATCH] virtio: fix article before virtio in dma-buf comment
From: weimin xiong @ 2026-07-14 2:45 UTC (permalink / raw)
To: virtualization; +Cc: mst, jasowangio, xuanzhuo, eperezma, xiongweimin
From: xiongweimin <xiongweimin@kylinos.cn>
Use "a virtio" rather than "an virtio".
Signed-off-by: xiongweimin <xiongweimin@kylinos.cn>
---
drivers/virtio/virtio_dma_buf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/virtio/virtio_dma_buf.c b/drivers/virtio/virtio_dma_buf.c
index 95c10632f..901282d82 100644
--- a/drivers/virtio/virtio_dma_buf.c
+++ b/drivers/virtio/virtio_dma_buf.c
@@ -14,7 +14,7 @@
* struct embedded in a virtio_dma_buf_ops.
*
* This wraps dma_buf_export() to allow virtio drivers to create a dma-buf
- * for an virtio exported object that can be queried by other virtio drivers
+ * for a virtio exported object that can be queried by other virtio drivers
* for the object's UUID.
*/
struct dma_buf *virtio_dma_buf_export
--
2.43.0
No virus found
Checked by Hillstone Network AntiVirus
^ permalink raw reply related
* [PATCH] vdpa/solidrun: fix typos in snet_ctrl comments
From: weimin xiong @ 2026-07-14 2:45 UTC (permalink / raw)
To: virtualization
Cc: alvaro.karsz, mst, jasowangio, xuanzhuo, eperezma, xiongweimin
From: xiongweimin <xiongweimin@kylinos.cn>
Correct "readind" and "the an error" in the DPU control path comments.
Signed-off-by: xiongweimin <xiongweimin@kylinos.cn>
---
drivers/vdpa/solidrun/snet_ctrl.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/vdpa/solidrun/snet_ctrl.c b/drivers/vdpa/solidrun/snet_ctrl.c
index 3cef2571d..e284c3a06 100644
--- a/drivers/vdpa/solidrun/snet_ctrl.c
+++ b/drivers/vdpa/solidrun/snet_ctrl.c
@@ -124,10 +124,10 @@ static int snet_wait_for_dpu_completion(struct snet_ctrl_regs __iomem *ctrl_regs
* reading the in_process and error bits in the control register.
* (2) Write the request opcode and the VQ idx in the opcode register
* and write the buffer size in the control register.
- * (3) Start readind chunks of data, chunk_ready bit indicates that a
+ * (3) Start reading chunks of data, chunk_ready bit indicates that a
* data chunk is available, we signal that we read the data by clearing the bit.
* (4) Detect that the transfer is completed when the in_process bit
- * in the control register is cleared or when the an error appears.
+ * in the control register is cleared or when an error appears.
*/
static int snet_ctrl_read_from_dpu(struct snet *snet, u16 opcode, u16 vq_idx, void *buffer,
u32 buf_size)
--
2.43.0
No virus found
Checked by Hillstone Network AntiVirus
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox