* Re: [PATCH net-next 2/3] vsock: convert to getsockopt_iter
From: David Laight @ 2026-05-01 21:21 UTC (permalink / raw)
To: Bobby Eshleman
Cc: Breno Leitao, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Stefano Garzarella, Shuah Khan,
sdf.kernel, netdev, linux-kernel, virtualization, linux-kselftest,
kernel-team
In-Reply-To: <afTjvM1P4gjPSvW8@devvm29614.prn0.facebook.com>
On Fri, 1 May 2026 10:32:44 -0700
Bobby Eshleman <bobbyeshleman@gmail.com> wrote:
> On Fri, May 01, 2026 at 08:52:52AM -0700, Breno Leitao wrote:
> > Convert AF_VSOCK's getsockopt implementation to use the new
> > getsockopt_iter callback with sockopt_t. The single
> > vsock_connectible_getsockopt() callback is shared by both
> > vsock_stream_ops and vsock_seqpacket_ops, so both proto_ops are
> > updated to use .getsockopt_iter.
> >
> > Key changes:
> > - Replace (char __user *optval, int __user *optlen) with sockopt_t *opt
> > - Use opt->optlen for buffer length (input) and returned size (output)
> > - Use copy_to_iter() instead of put_user()/copy_to_user()
> >
> > Signed-off-by: Breno Leitao <leitao@debian.org>
> > ---
> > net/vmw_vsock/af_vsock.c | 16 +++++++---------
> > 1 file changed, 7 insertions(+), 9 deletions(-)
> >
> > diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
> > index 44037b066a5ff..d4a97eeb596e6 100644
> > --- a/net/vmw_vsock/af_vsock.c
> > +++ b/net/vmw_vsock/af_vsock.c
> > @@ -155,6 +155,7 @@
> > #include <linux/random.h>
> > #include <linux/skbuff.h>
> > #include <linux/smp.h>
> > +#include <linux/uio.h>
> > #include <linux/socket.h>
> > #include <linux/stddef.h>
> > #include <linux/sysctl.h>
> > @@ -2091,8 +2092,7 @@ static int vsock_connectible_setsockopt(struct socket *sock,
> >
> > static int vsock_connectible_getsockopt(struct socket *sock,
> > int level, int optname,
> > - char __user *optval,
> > - int __user *optlen)
> > + sockopt_t *opt)
> > {
> > struct sock *sk = sock->sk;
> > struct vsock_sock *vsk = vsock_sk(sk);
> > @@ -2110,8 +2110,7 @@ static int vsock_connectible_getsockopt(struct socket *sock,
> > if (level != AF_VSOCK)
> > return -ENOPROTOOPT;
> >
> > - if (get_user(len, optlen))
> > - return -EFAULT;
> > + len = opt->optlen;
> >
> > memset(&v, 0, sizeof(v));
> >
> > @@ -2142,11 +2141,10 @@ static int vsock_connectible_getsockopt(struct socket *sock,
> > return -EINVAL;
> > if (len > lv)
> > len = lv;
> > - if (copy_to_user(optval, &v, len))
> > + if (copy_to_iter(&v, len, &opt->iter_out) != len)
I'd wrap that as copy_to_sockopt(&v, len, opt).
or to make the edits easier: copy_to_sockopt(opt, &v, len).
Then if someone decides to change the implementation none of the call
sites need changing.
-- David
> > return -EFAULT;
> >
> > - if (put_user(len, optlen))
> > - return -EFAULT;
> > + opt->optlen = len;
> >
> > return 0;
> > }
> > @@ -2631,7 +2629,7 @@ static const struct proto_ops vsock_stream_ops = {
> > .listen = vsock_listen,
> > .shutdown = vsock_shutdown,
> > .setsockopt = vsock_connectible_setsockopt,
> > - .getsockopt = vsock_connectible_getsockopt,
> > + .getsockopt_iter = vsock_connectible_getsockopt,
> > .sendmsg = vsock_connectible_sendmsg,
> > .recvmsg = vsock_connectible_recvmsg,
> > .mmap = sock_no_mmap,
> > @@ -2653,7 +2651,7 @@ static const struct proto_ops vsock_seqpacket_ops = {
> > .listen = vsock_listen,
> > .shutdown = vsock_shutdown,
> > .setsockopt = vsock_connectible_setsockopt,
> > - .getsockopt = vsock_connectible_getsockopt,
> > + .getsockopt_iter = vsock_connectible_getsockopt,
> > .sendmsg = vsock_connectible_sendmsg,
> > .recvmsg = vsock_connectible_recvmsg,
> > .mmap = sock_no_mmap,
> >
> > --
> > 2.52.0
> >
>
> Reviewed-by: Bobby Eshleman <bobbyeshleman@meta.com>
>
^ permalink raw reply
* Re: [PATCH] kcov: refactor common handle ID into kcov_common_handle_id
From: Jakub Kicinski @ 2026-05-01 23:52 UTC (permalink / raw)
To: Jann Horn
Cc: Dmitry Vyukov, Andrey Konovalov, kasan-dev, Andrew Morton,
Alexander Potapenko, Valentina Manea, Shuah Khan, Shuah Khan,
Hongren Zheng, linux-usb, Michael S. Tsirkin, Jason Wang,
Eugenio Pérez, kvm, virtualization, netdev, linux-kernel
In-Reply-To: <20260430-kcov-refactor-common-handle-v1-1-23a0c7a0ba38@google.com>
On Thu, 30 Apr 2026 16:15:33 +0200 Jann Horn wrote:
> Store common handle IDs in "struct kcov_common_handle_id", which consumes
> no space in non-KCOV builds.
> This cleanup removes #ifdef boilerplate code from subsystems that
> integrate with KCOV (in particular in usbip_common.h and skbuff.h, see the
> diffstat).
> This should also make it easier to add KCOV remote coverage to more
> subsystems in the future.
>
> Signed-off-by: Jann Horn <jannh@google.com>
Acked-by: Jakub Kicinski <kuba@kernel.org>
^ permalink raw reply
* Re: [PATCH v12 10/13] blk-mq: use hk cpus only when isolcpus=io_queue is enabled
From: Aaron Tomlin @ 2026-05-02 21:25 UTC (permalink / raw)
To: axboe, kbusch, hch, sagi, mst
Cc: aacraid, James.Bottomley, martin.petersen, liyihang9,
kashyap.desai, sumit.saxena, shivasharan.srikanteshwara,
chandrakanth.patil, sathya.prakash, sreekanth.reddy,
suganath-prabu.subramani, ranjan.kumar, jinpu.wang, tglx, mingo,
peterz, juri.lelli, vincent.guittot, akpm, maz, ruanjinjie,
bigeasy, yphbchou0911, wagi, frederic, longman, chenridong, hare,
kch, ming.lei, tom.leiming, steve, sean, chjohnst, neelx, mproche,
nick.lange, marco.crivellari, linux-block, linux-kernel,
virtualization, linux-nvme, linux-scsi, megaraidlinux.pdl,
mpi3mr-linuxdrv.pdl, MPT-FusionLinux.pdl
In-Reply-To: <20260422185215.100929-11-atomlin@atomlin.com>
[-- Attachment #1: Type: text/plain, Size: 3734 bytes --]
On Wed, Apr 22, 2026 at 02:52:12PM -0400, Aaron Tomlin wrote:
> From: Daniel Wagner <wagi@kernel.org>
> +static void blk_mq_map_fallback(struct blk_mq_queue_map *qmap)
> +{
> + unsigned int cpu;
> +
> + /*
> + * Map all CPUs to the first hctx to ensure at least one online
> + * CPU is serving it.
> + */
> + for_each_possible_cpu(cpu)
> + qmap->mq_map[cpu] = 0;
> +}
I suspect we should use 'qmap->mq_map[cpu] = qmap->queue_offset' to respect
the specified map's boundaries. For instance, secondary maps may not start
at zero.
> void blk_mq_map_queues(struct blk_mq_queue_map *qmap)
> {
> - const struct cpumask *masks;
> + struct cpumask *masks __free(kfree) = NULL;
> + const struct cpumask *constraint;
> unsigned int queue, cpu, nr_masks;
> + cpumask_var_t active_hctx;
[ ... ]
> + /* Map CPUs to the hardware contexts (hctx) */
> + masks = group_mask_cpus_evenly(qmap->nr_queues, constraint, &nr_masks);
> + if (!masks)
> + goto free_fallback;
According to Documentation/dev-tools/checkpatch.rst, pointers with the
'__free' attribute should be declared at the place of use and
initialisation. However, I suspect we should not use traditional goto error
unwinding with scope-based cleanups in the same function. I propose we drop
the use of __free and free 'masks' during the success code path.
> for (queue = 0; queue < qmap->nr_queues; queue++) {
> - for_each_cpu(cpu, &masks[queue % nr_masks])
> + unsigned int idx = (qmap->queue_offset + queue) % nr_masks;
> +
> + for_each_cpu(cpu, &masks[idx]) {
> qmap->mq_map[cpu] = qmap->queue_offset + queue;
> +
> + if (cpu_online(cpu))
> + cpumask_set_cpu(queue, active_hctx);
> + }
> }
[ ... ]
> +
> + /* Map any unassigned CPU evenly to the hardware contexts (hctx) */
> + queue = cpumask_first(active_hctx);
> + for_each_cpu_andnot(cpu, cpu_possible_mask, constraint) {
> + qmap->mq_map[cpu] = qmap->queue_offset + queue;
> + queue = cpumask_next_wrap(queue, active_hctx);
> + }
> +
> + if (!blk_mq_validate(qmap, active_hctx))
> + goto free_fallback;
> +
There is a potential out-of-bounds write vulnerability here.
The variable active_hctx (of type cpumask_var_t), after the call
zalloc_cpumask_var(), the Linux kernel would have allocated exactly enough
bits to represent the number of CPUs the system is configured to support
(nr_cpumask_bits). For example, nr_cpumask_bits could be set to 16.
Now, in the above loop, we are using active_hctx to track hardware queues
(qmap->nr_queues), passing queue as the index into cpumask_set_cpu().
A modern, high-end NVMe drive can expose 128 hardware queues.
If we plug that drive into a machine with only 16 CPUs:
1. zalloc_cpumask_var() allocates 16 bits (perhaps rounded up to a
standard word/slab size).
2. The loop iterates up to queue = 127.
3. cpumask_set_cpu(127, active_hctx) blindly writes to the 127th bit,
drastically overshooting the allocated memory and corrupting
adjacent slab memory in the kernel heap.
Because active_hctx is tracking hardware queues and not CPUs, we must not
use the cpumask API. Instead, switch it to the kernel's standard bitmap
API so the exact bit-length based on qmap->nr_queues can be dynamically
allocated.
Additionally, if all CPUs in the generated masks happen to be offline, the
bitmap will be empty. In that scenario, the bit-finding function will
return the size of the array, causing the unassigned CPU loop to map those
CPUs out-of-bounds. Checking if the bitmap is empty before that loop would
prevent this.
I will address the above in the next series iteration.
Kind regards,
--
Aaron Tomlin
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH] drm/bochs: Drop manual put on probe error path
From: Thomas Zimmermann @ 2026-05-04 8:36 UTC (permalink / raw)
To: Myeonghun Pak
Cc: Gerd Hoffmann, Maarten Lankhorst, Maxime Ripard, David Airlie,
Simona Vetter, virtualization, dri-devel, linux-kernel
In-Reply-To: <CAGEsz8F54LaiJYGD6i-nW7hDiLTu6FOi4Z8fzb8b4=+9-OEH+Q@mail.gmail.com>
Hi
Am 30.04.26 um 15:52 schrieb Myeonghun Pak:
> Thanks for the explanation.
>
> I see your point now. My patch treated uart_add_one_port() failure as
> a fatal
> probe failure, but the current code is intentionally trying to keep
> the driver
> alive so that other MAX3100 ports can still be available even if one
> port cannot
> be instantiated.
>
> Please drop this patch. I will not pursue this direction.
Why? The was patch was good AFAICT. It's just missing a Fixes tag.
Best regards
Thomas
>
> Thanks,
> Myeonghun
>
> 2026년 4월 24일 (금) 오후 11:59, Thomas Zimmermann
> <tzimmermann@suse.de>님이 작성:
>
> Hi
>
> Am 24.04.26 um 15:40 schrieb Myeonghun Pak:
> > Hi Thomas,
> >
> > Thank you for your reply. I will ensure that the requested
> |Fixes| tag
> > and |stable| CC are included in the next patch I send.
> >
> > Regarding your request for information about AI usage and how the
> > issue was identified:
> >
> > * This issue was identified during our ongoing static-analysis
> > research while reviewing kernel code.
> > 1
> >
> <https://mail.google.com/mail/u/0/#all/%23thread-f:1863355320119932959>
> > * Specifically, it was found by an experimental static
> analysis tool
> > that we are currently developing. The tool is not public
> yet, so I
> > prefer not to disclose further project details at this stage.
> >
> > * AI was used only for cross-review, not as the primary means of
> > finding or fixing the bug.
> > * I manually reviewed the code and verified the issue before
> sending
> > the patch.
> >
> > I will incorporate your requests and this additional context,
> and then
> > resend the modified patch.
>
> Thanks a lot.
>
> Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
>
> Best regards
> Thomas
>
> >
> > Thank you.
> >
> > Myeonghun Pak
> >
> >
> > 2026년 4월 24일 (금) 오후 10:25, Thomas Zimmermann
> > <tzimmermann@suse.de>님이 작성:
> >
> > Hi,
> >
> > please add fixes tags to all these patches you're sending. You
> > also need
> > to CC stable so that they can be backported easily. Also
> list the AI
> > you're using to find and create these patches.
> >
> > Best regards
> > Thomas
> >
> > Am 24.04.26 um 14:34 schrieb Myeonghun Pak:
> > > bochs_pci_probe() allocates the DRM device with
> > devm_drm_dev_alloc(),
> > > which registers a devres action to drop the initial DRM device
> > reference
> > > on driver detach or probe failure.
> > >
> > > The error path currently calls drm_dev_put() manually. If
> probe then
> > > returns an error, devres will run the registered release
> action
> > and put
> > > the same device again, after the first put may already have
> > released it.
> > >
> > > Return the probe error directly and let devres own the
> final put.
> > >
> > > Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
> > > ---
> > > drivers/gpu/drm/tiny/bochs.c | 10 +++-------
> > > 1 file changed, 3 insertions(+), 7 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/tiny/bochs.c
> > b/drivers/gpu/drm/tiny/bochs.c
> > > index 222e4ae1ab..5d8dc5efec 100644
> > > --- a/drivers/gpu/drm/tiny/bochs.c
> > > +++ b/drivers/gpu/drm/tiny/bochs.c
> > > @@ -761,25 +761,21 @@ static int bochs_pci_probe(struct
> pci_dev
> > *pdev, const struct pci_device_id *ent
> > >
> > > ret = pcim_enable_device(pdev);
> > > if (ret)
> > > - goto err_free_dev;
> > > + return ret;
> > >
> > > pci_set_drvdata(pdev, dev);
> > >
> > > ret = bochs_load(bochs);
> > > if (ret)
> > > - goto err_free_dev;
> > > + return ret;
> > >
> > > ret = drm_dev_register(dev, 0);
> > > if (ret)
> > > - goto err_free_dev;
> > > + return ret;
> > >
> > > drm_client_setup(dev, NULL);
> > >
> > > return ret;
> > > -
> > > -err_free_dev:
> > > - drm_dev_put(dev);
> > > - return ret;
> > > }
> > >
> > > static void bochs_pci_remove(struct pci_dev *pdev)
> >
> > --
> > --
> > Thomas Zimmermann
> > Graphics Driver Developer
> > SUSE Software Solutions Germany GmbH
> > Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
> <http://www.suse.com>
> > <http://www.suse.com>
> > GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB
> 36809, AG
> > Nürnberg)
> >
> >
>
> --
> --
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
> <http://www.suse.com>
> GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG
> Nürnberg)
>
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG Nürnberg)
^ permalink raw reply
* Re: [PATCH net-next 1/3] netlink: convert to getsockopt_iter
From: Stanislav Fomichev @ 2026-05-04 14:54 UTC (permalink / raw)
To: Breno Leitao
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Stefano Garzarella, Shuah Khan, netdev,
linux-kernel, virtualization, linux-kselftest, kernel-team
In-Reply-To: <20260501-getsock_one-v1-1-810ce23ea70e@debian.org>
On 05/01, Breno Leitao wrote:
> Convert AF_NETLINK's getsockopt implementation to use the new
> getsockopt_iter callback with sockopt_t.
>
> Key changes:
> - Replace (char __user *optval, int __user *optlen) with sockopt_t *opt
> - Use opt->optlen for buffer length (input) and returned size (output)
> - Use copy_to_iter() instead of put_user()/copy_to_user()
> - For NETLINK_LIST_MEMBERSHIPS: walk the groups bitmap and emit each
> u32 sequentially via copy_to_iter(), then set opt->optlen to the
> total size required (ALIGN(BITS_TO_BYTES(ngroups), sizeof(u32))).
> The wrapper writes opt->optlen back to userspace even on partial
> failure, preserving the existing API that lets userspace discover
> the needed allocation size.
>
> Signed-off-by: Breno Leitao <leitao@debian.org>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
^ permalink raw reply
* Re: [PATCH net-next 2/3] vsock: convert to getsockopt_iter
From: Stanislav Fomichev @ 2026-05-04 14:54 UTC (permalink / raw)
To: Breno Leitao
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Stefano Garzarella, Shuah Khan, netdev,
linux-kernel, virtualization, linux-kselftest, kernel-team
In-Reply-To: <20260501-getsock_one-v1-2-810ce23ea70e@debian.org>
On 05/01, Breno Leitao wrote:
> Convert AF_VSOCK's getsockopt implementation to use the new
> getsockopt_iter callback with sockopt_t. The single
> vsock_connectible_getsockopt() callback is shared by both
> vsock_stream_ops and vsock_seqpacket_ops, so both proto_ops are
> updated to use .getsockopt_iter.
>
> Key changes:
> - Replace (char __user *optval, int __user *optlen) with sockopt_t *opt
> - Use opt->optlen for buffer length (input) and returned size (output)
> - Use copy_to_iter() instead of put_user()/copy_to_user()
>
> Signed-off-by: Breno Leitao <leitao@debian.org>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
^ permalink raw reply
* Re: [PATCH net-next 3/3] net: selftests: add getsockopt_iter regression tests
From: Stanislav Fomichev @ 2026-05-04 14:57 UTC (permalink / raw)
To: Breno Leitao
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Stefano Garzarella, Shuah Khan, netdev,
linux-kernel, virtualization, linux-kselftest, kernel-team
In-Reply-To: <20260501-getsock_one-v1-3-810ce23ea70e@debian.org>
On 05/01, Breno Leitao wrote:
> Add a single kselftest covering the proto_ops getsockopt_iter
> conversions for AF_NETLINK and AF_VSOCK, using one fixture per protocol:
>
> netlink:
>
> NETLINK_PKTINFO covers the flag-style int path (exact size, oversize
> clamp, undersize -EINVAL); NETLINK_LIST_MEMBERSHIPS covers the
> size-discovery path that always reports the required buffer length back
> via optlen, even when the user buffer is too small to receive any group
> bits.
>
> vsock:
> SO_VM_SOCKETS_BUFFER_SIZE covers the u64 path (exact size, oversize
> clamp, undersize -EINVAL).
>
> Each fixture also exercises an unknown optname and a bogus level so
> the returned-length / errno semantics preserved by the sockopt_t
> conversion are pinned down.
>
> Signed-off-by: Breno Leitao <leitao@debian.org>
A few nits if you happen to respin (or for similar tests in the future):
- add ASSERT_EQ(optlen, xxx), won't hurt
- christmas tree (although not sure how much we care, you'll have to move
optlen = sizeof() assignment)
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
^ permalink raw reply
* [PATCH] drm: Consistently define pci_device_ids using named initializers
From: Uwe Kleine-König (The Capable Hub) @ 2026-05-04 15:05 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Gerd Hoffmann
Cc: Markus Schneider-Pargmann, Patrik Jakobsson, Jianmin Lv,
Qianhai Wu, Huacai Chen, Mingcong Bai, Xi Ruoyao, Icenowy Zheng,
Dave Airlie, Jocelyn Falempe, dri-devel, linux-kernel,
virtualization, spice-devel
The .driver_data member of the various struct pci_device_id arrays were
initialized by list expressions. This isn't easily readable if you're
not into PCI. Using the PCI_DEVICE macro and named initializers is more
explicit and thus easier to parse. Also skip explicit assignments of 0
(which the compiler then takes care of).
This change doesn't introduce changes to the compiled pci_device_id
arrays. Tested on x86 and arm64.
Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
---
Hello,
The secret plan is to make struct pci_device_id::driver_data an
anonymous union (similar to
https://lore.kernel.org/all/cover.1776579304.git.u.kleine-koenig@baylibre.com/)
and that requires named initializers. But IMHO it's also a nice cleanup
on its own.
The anonymous union will allow changes like the following:
- { PCI_DEVICE(0x8086, 0x8108), .driver_data = (long) &psb_chip_ops },
+ { PCI_DEVICE(0x8086, 0x8108), .driver_data_ptr = &psb_chip_ops },
(together with the respective change in the code when the value is
used). This gets rid of a bunch of casts and thus slightly improves
type safety.
Best regards
Uwe
drivers/gpu/drm/gma500/psb_drv.c | 56 +++++++++++++--------------
drivers/gpu/drm/loongson/lsdc_drv.c | 4 +-
drivers/gpu/drm/mgag200/mgag200_drv.c | 24 ++++++------
drivers/gpu/drm/qxl/qxl_drv.c | 15 ++++---
4 files changed, 52 insertions(+), 47 deletions(-)
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index 005ab7f5355f..039da26ef24d 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -56,36 +56,36 @@ static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
*/
static const struct pci_device_id pciidlist[] = {
/* Poulsbo */
- { 0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops },
- { 0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops },
+ { PCI_DEVICE(0x8086, 0x8108), .driver_data = (long) &psb_chip_ops },
+ { PCI_DEVICE(0x8086, 0x8109), .driver_data = (long) &psb_chip_ops },
/* Oak Trail */
- { 0x8086, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
- { 0x8086, 0x4101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
- { 0x8086, 0x4102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
- { 0x8086, 0x4103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
- { 0x8086, 0x4104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
- { 0x8086, 0x4105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
- { 0x8086, 0x4106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
- { 0x8086, 0x4107, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
- { 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
+ { PCI_DEVICE(0x8086, 0x4100), .driver_data = (long) &oaktrail_chip_ops },
+ { PCI_DEVICE(0x8086, 0x4101), .driver_data = (long) &oaktrail_chip_ops },
+ { PCI_DEVICE(0x8086, 0x4102), .driver_data = (long) &oaktrail_chip_ops },
+ { PCI_DEVICE(0x8086, 0x4103), .driver_data = (long) &oaktrail_chip_ops },
+ { PCI_DEVICE(0x8086, 0x4104), .driver_data = (long) &oaktrail_chip_ops },
+ { PCI_DEVICE(0x8086, 0x4105), .driver_data = (long) &oaktrail_chip_ops },
+ { PCI_DEVICE(0x8086, 0x4106), .driver_data = (long) &oaktrail_chip_ops },
+ { PCI_DEVICE(0x8086, 0x4107), .driver_data = (long) &oaktrail_chip_ops },
+ { PCI_DEVICE(0x8086, 0x4108), .driver_data = (long) &oaktrail_chip_ops },
/* Cedar Trail */
- { 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0be2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0be3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0be4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0be5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0be6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0be7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0be8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0be9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0bea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0beb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0bec, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0bed, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0bee, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0x8086, 0x0bef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
- { 0, }
+ { PCI_DEVICE(0x8086, 0x0be0), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0be1), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0be2), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0be3), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0be4), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0be5), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0be6), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0be7), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0be8), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0be9), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0bea), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0beb), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0bec), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0bed), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0bee), .driver_data = (long) &cdv_chip_ops },
+ { PCI_DEVICE(0x8086, 0x0bef), .driver_data = (long) &cdv_chip_ops },
+ { }
};
MODULE_DEVICE_TABLE(pci, pciidlist);
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.c b/drivers/gpu/drm/loongson/lsdc_drv.c
index 1ece1ea42f78..f9f7271ddbff 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.c
+++ b/drivers/gpu/drm/loongson/lsdc_drv.c
@@ -444,8 +444,8 @@ static const struct dev_pm_ops lsdc_pm_ops = {
};
static const struct pci_device_id lsdc_pciid_list[] = {
- {PCI_VDEVICE(LOONGSON, 0x7a06), CHIP_LS7A1000},
- {PCI_VDEVICE(LOONGSON, 0x7a36), CHIP_LS7A2000},
+ { PCI_VDEVICE(LOONGSON, 0x7a06), .driver_data = CHIP_LS7A1000 },
+ { PCI_VDEVICE(LOONGSON, 0x7a36), .driver_data = CHIP_LS7A2000 },
{ }
};
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
index a32be27c39e8..8ad4ddb60ee6 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -205,18 +205,18 @@ int mgag200_device_init(struct mga_device *mdev,
*/
static const struct pci_device_id mgag200_pciidlist[] = {
- { PCI_VENDOR_ID_MATROX, 0x520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_PCI },
- { PCI_VENDOR_ID_MATROX, 0x521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_AGP },
- { PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_A },
- { PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B },
- { PCI_VENDOR_ID_MATROX, 0x530, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EV },
- { PCI_VENDOR_ID_MATROX, 0x532, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_WB },
- { PCI_VENDOR_ID_MATROX, 0x533, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EH },
- { PCI_VENDOR_ID_MATROX, 0x534, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_ER },
- { PCI_VENDOR_ID_MATROX, 0x536, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EW3 },
- { PCI_VENDOR_ID_MATROX, 0x538, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EH3 },
- { PCI_VENDOR_ID_MATROX, 0x53a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EH5 },
- {0,}
+ { PCI_VDEVICE(MATROX, 0x0520), .driver_data = G200_PCI },
+ { PCI_VDEVICE(MATROX, 0x0521), .driver_data = G200_AGP },
+ { PCI_VDEVICE(MATROX, 0x0522), .driver_data = G200_SE_A },
+ { PCI_VDEVICE(MATROX, 0x0524), .driver_data = G200_SE_B },
+ { PCI_VDEVICE(MATROX, 0x0530), .driver_data = G200_EV },
+ { PCI_VDEVICE(MATROX, 0x0532), .driver_data = G200_WB },
+ { PCI_VDEVICE(MATROX, 0x0533), .driver_data = G200_EH },
+ { PCI_VDEVICE(MATROX, 0x0534), .driver_data = G200_ER },
+ { PCI_VDEVICE(MATROX, 0x0536), .driver_data = G200_EW3 },
+ { PCI_VDEVICE(MATROX, 0x0538), .driver_data = G200_EH3 },
+ { PCI_VDEVICE(MATROX, 0x053a), .driver_data = G200_EH5 },
+ { }
};
MODULE_DEVICE_TABLE(pci, mgag200_pciidlist);
diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
index 2bbb1168a3ff..6c3c309b8e4d 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.c
+++ b/drivers/gpu/drm/qxl/qxl_drv.c
@@ -50,11 +50,16 @@
#include "qxl_object.h"
static const struct pci_device_id pciidlist[] = {
- { 0x1b36, 0x100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8,
- 0xffff00, 0 },
- { 0x1b36, 0x100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_OTHER << 8,
- 0xffff00, 0 },
- { 0, 0, 0 },
+ {
+ PCI_DEVICE(0x1b36, 0x0100),
+ .class = PCI_CLASS_DISPLAY_VGA << 8,
+ .class_mask = 0xffff00
+ }, {
+ PCI_DEVICE(0x1b36, 0x0100),
+ .class = PCI_CLASS_DISPLAY_OTHER << 8,
+ .class_mask = 0xffff00
+ },
+ { },
};
MODULE_DEVICE_TABLE(pci, pciidlist);
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
--
2.47.3
^ permalink raw reply related
* Re: [PATCH net] vsock/virtio: fix potential unbounded skb queue
From: patchwork-bot+netdevbpf @ 2026-05-05 2:20 UTC (permalink / raw)
To: Eric Dumazet
Cc: davem, kuba, pabeni, horms, netdev, eric.dumazet, AVKrasnov,
stefanha, sgarzare, mst, jasowang, xuanzhuo, eperezma, kvm,
virtualization
In-Reply-To: <20260430122653.554058-1-edumazet@google.com>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Thu, 30 Apr 2026 12:26:52 +0000 you wrote:
> virtio_transport_inc_rx_pkt() checks vvs->rx_bytes + len > vvs->buf_alloc.
>
> virtio_transport_recv_enqueue() skips coalescing for packets
> with VIRTIO_VSOCK_SEQ_EOM.
>
> If fed with packets with len == 0 and VIRTIO_VSOCK_SEQ_EOM,
> a very large number of packets can be queued
> because vvs->rx_bytes stays at 0.
>
> [...]
Here is the summary with links:
- [net] vsock/virtio: fix potential unbounded skb queue
https://git.kernel.org/netdev/net/c/059b7dbd20a6
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH net-next 0/3] net: Convert AF_NETLINK and AF_VSOCK to getsockopt_iter API
From: patchwork-bot+netdevbpf @ 2026-05-05 2:20 UTC (permalink / raw)
To: Breno Leitao
Cc: davem, edumazet, kuba, pabeni, horms, sgarzare, shuah, sdf.kernel,
netdev, linux-kernel, virtualization, linux-kselftest,
kernel-team
In-Reply-To: <20260501-getsock_one-v1-0-810ce23ea70e@debian.org>
Hello:
This series was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Fri, 01 May 2026 08:52:50 -0700 you wrote:
> Continue the work to convert protocols to the new getsockopt_iter API.
>
> Convert AF_NETLINK and AF_VSOCK getsockopt implementations to the new
> sockopt_t/getsockopt_iter API, and add kselftests that verify the size
> and errno semantics are preserved across the conversion.
>
> I chose these two socket families because they are probably one of the
> most used protocols,, ensuring that any potential bugs will be
> discovered and reported quickly.
>
> [...]
Here is the summary with links:
- [net-next,1/3] netlink: convert to getsockopt_iter
https://git.kernel.org/netdev/net-next/c/390bf43b7788
- [net-next,2/3] vsock: convert to getsockopt_iter
https://git.kernel.org/netdev/net-next/c/e21bf72954df
- [net-next,3/3] net: selftests: add getsockopt_iter regression tests
https://git.kernel.org/netdev/net-next/c/d39887f55d8e
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH] ALSA: virtio: Add missing 384 kHz PCM rate mapping
From: Cássio Gabriel @ 2026-05-05 4:40 UTC (permalink / raw)
To: Takashi Iwai, Anton Yakovlev, Michael S. Tsirkin, Jaroslav Kysela
Cc: virtualization, linux-sound, linux-kernel, stable,
Cássio Gabriel
The VirtIO sound UAPI defines VIRTIO_SND_PCM_RATE_384000, and ALSA
has SNDRV_PCM_RATE_384000. However, virtio-snd's rate conversion
tables stop at 192 kHz.
A device advertising only 384 kHz is rejected as having no supported
PCM frame rates. A device advertising 384 kHz together with lower rates
does not expose 384 kHz through the ALSA hardware constraints. The
selected ALSA rate also needs a reverse mapping for SET_PARAMS.
Add the missing 384 kHz entries to both conversion tables.
Fixes: 29b96bf50ba9 ("ALSA: virtio: build PCM devices and substream hardware descriptors")
Fixes: da76e9f3e43a ("ALSA: virtio: PCM substream operators")
Cc: stable@vger.kernel.org
Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
---
sound/virtio/virtio_pcm.c | 3 ++-
sound/virtio/virtio_pcm_ops.c | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c
index eb9cc8131905..be3893de40a5 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -77,7 +77,8 @@ static const struct virtsnd_v2a_rate g_v2a_rate_map[] = {
[VIRTIO_SND_PCM_RATE_88200] = { SNDRV_PCM_RATE_88200, 88200 },
[VIRTIO_SND_PCM_RATE_96000] = { SNDRV_PCM_RATE_96000, 96000 },
[VIRTIO_SND_PCM_RATE_176400] = { SNDRV_PCM_RATE_176400, 176400 },
- [VIRTIO_SND_PCM_RATE_192000] = { SNDRV_PCM_RATE_192000, 192000 }
+ [VIRTIO_SND_PCM_RATE_192000] = { SNDRV_PCM_RATE_192000, 192000 },
+ [VIRTIO_SND_PCM_RATE_384000] = { SNDRV_PCM_RATE_384000, 384000 }
};
/**
diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c
index 6297a9c61e70..1105e7ff3523 100644
--- a/sound/virtio/virtio_pcm_ops.c
+++ b/sound/virtio/virtio_pcm_ops.c
@@ -90,7 +90,8 @@ static const struct virtsnd_a2v_rate g_a2v_rate_map[] = {
{ 88200, VIRTIO_SND_PCM_RATE_88200 },
{ 96000, VIRTIO_SND_PCM_RATE_96000 },
{ 176400, VIRTIO_SND_PCM_RATE_176400 },
- { 192000, VIRTIO_SND_PCM_RATE_192000 }
+ { 192000, VIRTIO_SND_PCM_RATE_192000 },
+ { 384000, VIRTIO_SND_PCM_RATE_384000 }
};
static int virtsnd_pcm_sync_stop(struct snd_pcm_substream *substream);
---
base-commit: fac9a31701803e4e41fdb7b5c71582c65cf47176
change-id: 20260422-alsa-virtio-384k-rate-723fe9772fa6
Best regards,
--
Cássio Gabriel <cassiogabrielcontato@gmail.com>
^ permalink raw reply related
* [PATCH RFC 0/6] Add Rust virtio bindings and sample device
From: Manos Pitsidianakis @ 2026-05-05 8:14 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Manos Pitsidianakis, Peter Hilber, Stefano Garzarella,
Stefan Hajnoczi, Viresh Kumar, Michael S. Tsirkin, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, rust-for-linux,
Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
linux-kernel, Manos Pitsidianakis
Hi all, this RFC series adds Rust bindings for Virtio drivers
(frontends in virtio parlance).
As a PoC, it also adds a sample virtio-rtc driver which performs
capability discovery through the virtqueue without registering any clock.
Before I send a cleaned-up non-RFC I would like some initial feedback
(i.e. is it something the upstream wants?)
This was tested with the rust-vmm vhost-device-rtc device backend that I
wrote[^0]:
[^0]: https://github.com/rust-vmm/vhost-device/tree/main/vhost-device-rtc
Instructions:
Run the daemon in a separate terminal:
$ cargo run --bin vhost-device-rtc -- -s /tmp/rtc.sock
Then run the VM:
$ qemu-system-aarch64 \
-machine type=virt,virtualization=off,acpi=on \
-cpu host \
-smp 8 \
-accel kvm \
-drive if=virtio,format=qcow2,file=./debian-13-nocloud-arm64-daily.qcow2 \
-device virtio-net-pci,netdev=unet \
-device virtio-scsi-pci \
-serial mon:stdio \
-m 8192 \
-object memory-backend-memfd,id=mem,size=8G,share=on \
-numa node,memdev=mem \
-display none \
-vga none \
-kernel /path/to/linux/build/arch/arm64/boot/Image \
-device vhost-user-test-device,chardev=rtc,id=rtc,virtio-id=17,num_vqs=2,vq_size=1024 \
-chardev socket,path=/tmp/rtc.sock,id=rtc \
...
Example output:
[ 1.105238] rust_virtio_rtc: Probe Rust virtio driver sample.
[ 1.105645] rust_virtio_rtc: Found 1 vqs.
[ 1.136050] rust_virtio_rtc: process_requestq got buf 16 bytes
[ 1.136125] rust_virtio_rtc: Got response! Ok(RespCfg { head: ReqHead { msg_type: Le16(0), reserved: [0, 0, 0, 0, 0, 0] }, num_clocks: Le16(3), reserved: [0, 0, 0, 0, 0, 0] })
[ 1.136701] rust_virtio_rtc: Got response! Ok(RespClockCap { head: ReqHead { msg_type: Le16(0), reserved: [0, 0, 0, 0, 0, 0] }, clock_type: 3, leap_second_smearing: 0, flags: 0, reserved: [0, 0, 0, 0, 0] })
[ 1.136724] rust_virtio_rtc virtio0: cannot expose clock 0 (type 3, variant 0, flags 0) to userspace
[ 1.137259] rust_virtio_rtc: Got response! Ok(RespRead { head: ReqHead { msg_type: Le16(0), reserved: [0, 0, 0, 0, 0, 0] }, clock_reading: Le64(1777890485031060388) })
[ 1.137277] rust_virtio_rtc: #0 clock reading = 1777890485031060388
[ 1.137749] rust_virtio_rtc: Got response! Ok(RespClockCap { head: ReqHead { msg_type: Le16(0), reserved: [0, 0, 0, 0, 0, 0] }, clock_type: 1, leap_second_smearing: 0, flags: 0, reserved: [0, 0, 0, 0, 0] })
[ 1.137769] rust_virtio_rtc virtio0: cannot expose clock 1 (type 1, variant 0, flags 0) to userspace
[ 1.138247] rust_virtio_rtc: Got response! Ok(RespRead { head: ReqHead { msg_type: Le16(0), reserved: [0, 0, 0, 0, 0, 0] }, clock_reading: Le64(1777890485032086075) })
[ 1.138264] rust_virtio_rtc: #1 clock reading = 1777890485032086075
[ 1.138730] rust_virtio_rtc: Got response! Ok(RespClockCap { head: ReqHead { msg_type: Le16(0), reserved: [0, 0, 0, 0, 0, 0] }, clock_type: 2, leap_second_smearing: 0, flags: 0, reserved: [0, 0, 0, 0, 0] })
[ 1.138751] rust_virtio_rtc virtio0: cannot expose clock 2 (type 2, variant 0, flags 0) to userspace
[ 1.139253] rust_virtio_rtc: Got response! Ok(RespRead { head: ReqHead { msg_type: Le16(0), reserved: [0, 0, 0, 0, 0, 0] }, clock_reading: Le64(338567896865557) })
[ 1.139270] rust_virtio_rtc: #2 clock reading = 338567896865557
Concerns - Notes - TODOs
========================
- Virtqueue lifetimes don't neatly apply to Rust as expected, so a lot
of times we have to go through unsafe pointer dereferences (though
which are guaranteed by Virtio subsystem to be valid, for example when
a callback is called with the vq argument). There's a potential for
misuse and definitely could use better thinking.
- `struct virtio_device` is not reference-counted like other implemented
device types in rust/kernel. Maybe we need to change C API first to
make them reference counted, assuming this doesn't break anything?
- Not sure if adding data smaller than PAGE_SIZE to virtqueue is safe
(which current C code does a lot), so I made those allocations at
least PAGE_SIZE.
- The sample driver obviously conflicts with the C implementation, so
this would either need to move out of samples/ or figure out some way
to handle this in kbuild.
- kernel::virtio module and its types need a few rustdoc examples that I
will add in followup series
- Note that the registration of RTC clocks etc in the sample driver is
not done, I'm putting it off until I receive some feedback first. The
sample driver otherwise does send and receive data from the virtqueue
as a PoC. The code and data structures can be cleaned up further
before followup series.
PS: No LLMs used so any mistakes and goofs are solely written by me.
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
---
Manos Pitsidianakis (6):
rust/bindings: generate virtio bindings
rust/helpers: add virtio.c
rust: add virtio module
rust/scatterlist: add SGEntry::init_one
rust: impl interruptible waits for Completion
samples/rust: Add sample virtio-rtc driver [WIP]
MAINTAINERS | 9 +
rust/bindings/bindings_helper.h | 5 +
rust/helpers/helpers.c | 3 +
rust/helpers/virtio.c | 35 +++
rust/kernel/lib.rs | 2 +
rust/kernel/scatterlist.rs | 20 +-
rust/kernel/sync/completion.rs | 39 ++++
rust/kernel/virtio.rs | 415 +++++++++++++++++++++++++++++++++++
rust/kernel/virtio/utils.rs | 65 ++++++
rust/kernel/virtio/virtqueue.rs | 181 ++++++++++++++++
samples/rust/Kconfig | 15 ++
samples/rust/Makefile | 1 +
samples/rust/rust_virtio_rtc.rs | 470 ++++++++++++++++++++++++++++++++++++++++
13 files changed, 1259 insertions(+), 1 deletion(-)
---
base-commit: 028ef9c96e96197026887c0f092424679298aae8
change-id: 20260504-rust-virtio-8523b01dfdc2
Best regards,
--
Manos Pitsidianakis <manos@pitsidianak.is>
^ permalink raw reply
* [PATCH RFC 1/6] rust/bindings: generate virtio bindings
From: Manos Pitsidianakis @ 2026-05-05 8:14 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Manos Pitsidianakis, Peter Hilber, Stefano Garzarella,
Stefan Hajnoczi, Viresh Kumar, Michael S. Tsirkin, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, rust-for-linux,
Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
linux-kernel, Manos Pitsidianakis
In-Reply-To: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is>
Add virtio headers if CONFIG_VIRTIO is enabled.
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
---
rust/bindings/bindings_helper.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 083cc44aa952c2b29ab82d5d481063a1cf48bccf..2b0a3cf49fdaf14517afc88688c545aaa977b5c6 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -151,3 +151,8 @@ const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE = VM_NOHUGEPAGE;
#include "../../drivers/android/binder/rust_binder_events.h"
#include "../../drivers/android/binder/page_range_helper.h"
#endif
+
+#if defined(CONFIG_VIRTIO)
+#include <linux/virtio_config.h>
+#include <uapi/linux/virtio_ids.h>
+#endif /* defined(CONFIG_VIRTIO) */
--
2.47.3
^ permalink raw reply related
* [PATCH RFC 2/6] rust/helpers: add virtio.c
From: Manos Pitsidianakis @ 2026-05-05 8:14 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Manos Pitsidianakis, Peter Hilber, Stefano Garzarella,
Stefan Hajnoczi, Viresh Kumar, Michael S. Tsirkin, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, rust-for-linux,
Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
linux-kernel, Manos Pitsidianakis
In-Reply-To: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is>
Some internal kernel virtio API functions are inline macros, so define
their symbols in a helper file.
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
---
MAINTAINERS | 6 ++++++
rust/helpers/helpers.c | 3 +++
rust/helpers/virtio.c | 35 +++++++++++++++++++++++++++++++++++
3 files changed, 44 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index d1cc0e12fe1f004da89b1aa339116908f642e894..48c9c666d90b5a256ab6fae1f42508b789a0ce50 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27930,6 +27930,12 @@ F: include/uapi/linux/virtio_*.h
F: net/vmw_vsock/virtio*
F: tools/virtio/
+VIRTIO CORE API BINDINGS [RUST]
+M: Manos Pitsidianakis <manos@pitsidianak.is>
+L: virtualization@lists.linux.dev
+S: Maintained
+F: rust/helpers/virtio.c
+
VIRTIO CRYPTO DRIVER
M: Gonglei <arei.gonglei@huawei.com>
L: virtualization@lists.linux.dev
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index a3c42e51f00a0990bea81ebce6e99bb397ce7533..84b54690d95be37699ef9a9c4d7cedec0bbae6d3 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -62,6 +62,9 @@
#include "uaccess.c"
#include "usb.c"
#include "vmalloc.c"
+#if defined(CONFIG_VIRTIO)
+#include "virtio.c"
+#endif /* defined(CONFIG_VIRTIO) */
#include "wait.c"
#include "workqueue.c"
#include "xarray.c"
diff --git a/rust/helpers/virtio.c b/rust/helpers/virtio.c
new file mode 100644
index 0000000000000000000000000000000000000000..cd8a811d59960e7b6aea1c08016f4154b29d5a97
--- /dev/null
+++ b/rust/helpers/virtio.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/virtio_config.h>
+
+__rust_helper bool
+rust_helper_virtio_has_feature(const struct virtio_device *vdev,
+ unsigned int fbit)
+{
+ return virtio_has_feature(vdev, fbit);
+}
+__rust_helper void rust_helper_virtio_get_features(struct virtio_device *vdev,
+ u64 *features_out)
+{
+ return virtio_get_features(vdev, features_out);
+}
+
+__rust_helper int rust_helper_virtio_find_vqs(struct virtio_device *vdev,
+ unsigned int nvqs,
+ struct virtqueue *vqs[],
+ struct virtqueue_info vqs_info[],
+ struct irq_affinity *desc)
+{
+ return virtio_find_vqs(vdev, nvqs, vqs, vqs_info, desc);
+}
+
+__rust_helper void rust_helper_virtio_device_ready(struct virtio_device *dev)
+{
+ return virtio_device_ready(dev);
+}
+
+__rust_helper bool
+rust_helper_virtio_is_little_endian(struct virtio_device *vdev)
+{
+ return virtio_is_little_endian(vdev);
+}
--
2.47.3
^ permalink raw reply related
* [PATCH RFC 3/6] rust: add virtio module
From: Manos Pitsidianakis @ 2026-05-05 8:14 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Manos Pitsidianakis, Peter Hilber, Stefano Garzarella,
Stefan Hajnoczi, Viresh Kumar, Michael S. Tsirkin, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, rust-for-linux,
Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
linux-kernel, Manos Pitsidianakis
In-Reply-To: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is>
Add module that exposes bindings for the virtio API.
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
---
MAINTAINERS | 2 +
rust/kernel/lib.rs | 2 +
rust/kernel/scatterlist.rs | 2 +-
rust/kernel/virtio.rs | 415 ++++++++++++++++++++++++++++++++++++++++
rust/kernel/virtio/utils.rs | 65 +++++++
rust/kernel/virtio/virtqueue.rs | 181 ++++++++++++++++++
6 files changed, 666 insertions(+), 1 deletion(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 48c9c666d90b5a256ab6fae1f42508b789a0ce50..e8012f708df5d4ee858c82aec3269e615fc8caad 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27935,6 +27935,8 @@ M: Manos Pitsidianakis <manos@pitsidianak.is>
L: virtualization@lists.linux.dev
S: Maintained
F: rust/helpers/virtio.c
+F: rust/kernel/virtio.rs
+F: rust/kernel/virtio/
VIRTIO CRYPTO DRIVER
M: Gonglei <arei.gonglei@huawei.com>
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index d93292d47420f1f298a452ade5feefedce5ade86..c1fe1b06fd89e80f23c5de22aeb36c80f653e1ab 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -161,6 +161,8 @@
pub mod uaccess;
#[cfg(CONFIG_USB = "y")]
pub mod usb;
+#[cfg(CONFIG_VIRTIO)]
+pub mod virtio;
pub mod workqueue;
pub mod xarray;
diff --git a/rust/kernel/scatterlist.rs b/rust/kernel/scatterlist.rs
index b83c468b5c63311f3a6d92f0f1bf05f6dfe12076..146e738cbd4351b41c11dd39a45e20f404c5cd64 100644
--- a/rust/kernel/scatterlist.rs
+++ b/rust/kernel/scatterlist.rs
@@ -75,7 +75,7 @@ unsafe fn from_raw<'a>(ptr: *mut bindings::scatterlist) -> &'a Self {
/// Obtain the raw `struct scatterlist *`.
#[inline]
- fn as_raw(&self) -> *mut bindings::scatterlist {
+ pub(crate) fn as_raw(&self) -> *mut bindings::scatterlist {
self.0.get()
}
diff --git a/rust/kernel/virtio.rs b/rust/kernel/virtio.rs
new file mode 100644
index 0000000000000000000000000000000000000000..38e4f273ce76ab2dfa2e91b4ff8c4d5ddde0121c
--- /dev/null
+++ b/rust/kernel/virtio.rs
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! VIRTIO abstraction.
+
+use crate::{
+ bindings,
+ device_id::RawDeviceId,
+ error::{
+ from_result,
+ to_result,
+ Error,
+ Result, //
+ },
+ ffi::c_uint,
+ prelude::*,
+ types::Opaque, //
+};
+
+use core::{
+ marker::PhantomData,
+ pin::Pin, //
+};
+
+pub mod utils;
+pub mod virtqueue;
+
+/// IdTable type for virtio drivers.
+pub type IdTable<T> = &'static dyn crate::device_id::IdTable<DeviceId, T>;
+
+/// A VIRTIO device id.
+///
+/// [`struct virtio_device_id`]: srctree/include/linux/mod_devicetable.h
+#[repr(transparent)]
+#[derive(Clone, Copy)]
+pub struct DeviceId(bindings::virtio_device_id);
+
+// SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct virtio_device_id` and
+// does not add additional invariants, so it's safe to transmute to `RawType`.
+unsafe impl RawDeviceId for DeviceId {
+ type RawType = bindings::virtio_device_id;
+}
+
+impl DeviceId {
+ #[inline]
+ /// Create a new device id
+ pub const fn new(device: VirtioID) -> Self {
+ Self::new_with_vendor(device, VIRTIO_DEV_ANY_ID)
+ }
+
+ /// Create a new device id with vendor
+ pub const fn new_with_vendor(device: VirtioID, vendor: u32) -> Self {
+ // Replace with `bindings::of_device_id::default()` once stabilized for `const`.
+ // SAFETY: FFI type is valid to be zero-initialized.
+ let mut ret: bindings::virtio_device_id = unsafe { core::mem::zeroed() };
+ ret.device = device as u32;
+ ret.vendor = vendor;
+ Self(ret)
+ }
+}
+
+/// Create a virtio `IdTable` with its alias for modpost.
+#[macro_export]
+macro_rules! virtio_device_table {
+ ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data:expr) => {
+ const $table_name: $crate::device_id::IdArray<
+ $crate::virtio::DeviceId,
+ $id_info_type,
+ { $table_data.len() },
+ > = $crate::device_id::IdArray::new_without_index($table_data);
+
+ $crate::module_device_table!("virtio", $module_table_name, $table_name);
+ };
+}
+
+/// Declares a kernel module that exposes a single virtio driver.
+#[macro_export]
+macro_rules! module_virtio_driver {
+($($f:tt)*) => {
+ $crate::module_driver!(<T>, $crate::virtio::Adapter<T>, { $($f)* });
+};
+}
+
+/// The Virtio driver trait.
+///
+/// Drivers must implement this trait in order to get a virtio driver registered.
+pub trait Driver: Send {
+ /// The type holding information about each device id supported by the driver.
+ // TODO: Use `associated_type_defaults` once stabilized:
+ //
+ // ```
+ // type IdInfo: 'static = ();
+ // ```
+ type IdInfo: 'static;
+
+ /// The table of device ids supported by the driver.
+ const ID_TABLE: IdTable<Self::IdInfo>;
+
+ /// virtio driver probe.
+ ///
+ /// Called when a new virtio device is added or discovered. Implementers should
+ /// attempt to initialize the device here, but not sleep, since driver data is set after this
+ /// method returns successfully.
+ fn probe(dev: &Device<crate::device::Core>) -> impl PinInit<Self, Error>;
+
+ /// virtio driver init.
+ ///
+ /// Called after a virtio device is probed successfully, can sleep.
+ fn init(&self, dev: &Device<crate::device::Core>) -> Result;
+
+ /// virtio driver remove.
+ ///
+ /// Called when a [`Device`] is removed from its [`Driver`]. Implementing this callback
+ /// is optional.
+ ///
+ /// This callback serves as a place for drivers to perform teardown operations that require a
+ /// `&Device<Core>` or `&Device<Bound>` reference. For instance, drivers may try to perform I/O
+ /// operations to gracefully tear down the device.
+ ///
+ /// Otherwise, release operations for driver resources should be performed in `Self::drop`.
+ fn remove(dev: &Device, this: Pin<&Self>);
+}
+
+/// Abstraction for the virtio device structure (`struct virtio_device`).
+///
+/// [`struct virtio_device`]: srctree/include/linux/virtio.h
+#[repr(transparent)]
+pub struct Device<Ctx: crate::device::DeviceContext = crate::device::Normal>(
+ Opaque<bindings::virtio_device>,
+ PhantomData<Ctx>,
+);
+
+impl<Ctx: crate::device::DeviceContext> Device<Ctx> {
+ #[inline]
+ fn as_raw(&self) -> *mut bindings::virtio_device {
+ self.0.get()
+ }
+}
+
+// SAFETY: `virtio::Device` is a transparent wrapper of `struct virtio_device`.
+// The offset is guaranteed to point to a valid device field inside `virtio::Device`.
+unsafe impl<Ctx: crate::device::DeviceContext> crate::device::AsBusDevice<Ctx> for Device<Ctx> {
+ const OFFSET: usize = core::mem::offset_of!(bindings::virtio_device, dev);
+}
+
+// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
+// argument.
+kernel::impl_device_context_deref!(unsafe { Device });
+
+impl<Ctx: crate::device::DeviceContext> Device<Ctx> {
+ // TODO: return VirtioID
+ /// Returns the virtio device ID.
+ #[inline]
+ pub fn device_id(&self) -> u32 {
+ // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a
+ // `struct virtio_device`.
+ unsafe { (*self.as_raw()).id.device }
+ }
+
+ /// Returns the virtio vendor ID.
+ #[inline]
+ pub fn vendor_id(&self) -> u32 {
+ // SAFETY: `self.as_raw` is a valid pointer to a `struct virtio_device`.
+ unsafe { (*self.as_raw()).id.vendor }
+ }
+
+ /// Reset device.
+ #[doc(alias = "virtio_reset_device")]
+ pub fn reset(&self) {
+ // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a
+ // `struct virtio_device`.
+ unsafe { bindings::virtio_reset_device(self.as_raw()) }
+ }
+
+ /// Mark device as ready.
+ #[doc(alias = "virtio_device_ready")]
+ pub fn ready(&self) {
+ // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a
+ // `struct virtio_device`.
+ unsafe { bindings::virtio_device_ready(self.as_raw()) }
+ }
+
+ /// Return virtqueues for this device.
+ #[doc(alias = "virtio_find_vqs")]
+ pub fn find_vqs(
+ &self,
+ info: &[virtqueue::VirtqueueInfo],
+ ) -> Result<KVec<*mut virtqueue::Virtqueue>> {
+ let mut vqs = KVec::with_capacity(info.len(), GFP_KERNEL)?;
+ // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a
+ // `struct virtio_device`.
+ to_result(unsafe {
+ bindings::virtio_find_vqs(
+ self.as_raw(),
+ info.len().try_into()?,
+ vqs.spare_capacity_mut().as_mut_ptr().cast(),
+ info.as_ptr().cast_mut().cast(),
+ core::ptr::null_mut(),
+ )
+ })?;
+ // SAFETY: virtio_find_vqs returned successfully so `vqs` must be populated.
+ unsafe { vqs.inc_len(info.len()) };
+ Ok(vqs)
+ }
+
+ /// Delete virtqueues from this device.
+ pub fn del_vqs(&self) {
+ // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a
+ // `struct virtio_device`.
+ let config = unsafe { (*self.as_raw()).config };
+ // SAFETY: `config` points to a valid virtqueue config struct.
+ if let Some(del_vqs) = unsafe { (*config).del_vqs } {
+ // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a
+ // `struct virtio_device`.
+ unsafe { del_vqs(self.as_raw()) }
+ }
+ }
+
+ /// Checks if the device has a feature bit.
+ pub fn has_feature(&self, fbit: c_uint) -> bool {
+ // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a
+ // `struct virtio_device`.
+ unsafe { bindings::virtio_has_feature(self.as_raw(), fbit) }
+ }
+
+ /// Return all feature bits for this device.
+ pub fn get_features(&self) -> u64 {
+ let mut features = 0;
+ // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a
+ // `struct virtio_device`.
+ unsafe { bindings::virtio_get_features(self.as_raw(), &raw mut features) };
+ features
+ }
+}
+
+impl<Ctx: crate::device::DeviceContext> AsRef<crate::device::Device<Ctx>> for Device<Ctx> {
+ fn as_ref(&self) -> &crate::device::Device<Ctx> {
+ // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
+ // `struct virtio_device`.
+ let dev = unsafe { core::ptr::addr_of_mut!((*self.as_raw()).dev) };
+
+ // SAFETY: `dev` points to a valid `struct device`.
+ unsafe { crate::device::Device::from_raw(dev) }
+ }
+}
+
+// SAFETY: A `Device` can be used rom any thread.
+unsafe impl Send for Device {}
+
+// SAFETY: `Device` can be shared among threads because all methods of `Device`
+// (i.e. `Device<Normal>) are thread safe.
+unsafe impl Sync for Device {}
+
+/// An adapter for the registration of virtio drivers.
+pub struct Adapter<T: Driver>(T);
+
+// SAFETY:
+// - `bindings::virtio_driver` is a C type declared as `repr(C)`.
+// - `T` is the type of the driver's device private data.
+// - `struct virtio_driver` embeds a `struct device_driver`.
+// - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`.
+unsafe impl<T: Driver + 'static> crate::driver::DriverLayout for Adapter<T> {
+ type DriverType = bindings::virtio_driver;
+ type DriverData = T;
+ const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver);
+}
+
+// SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if
+// a preceding call to `register` has been successful.
+unsafe impl<T: Driver + 'static> crate::driver::RegistrationOps for Adapter<T> {
+ unsafe fn register(
+ vdrv: &Opaque<Self::DriverType>,
+ name: &'static CStr,
+ module: &'static ThisModule,
+ ) -> Result {
+ // SAFETY: It's safe to set the fields of `struct virtio_driver` on initialization.
+ unsafe {
+ (*vdrv.get()).driver.name = name.as_char_ptr();
+ (*vdrv.get()).id_table = T::ID_TABLE.as_ptr();
+ (*vdrv.get()).probe = Some(Self::probe_callback);
+ (*vdrv.get()).remove = Some(Self::remove_callback);
+ }
+
+ // SAFETY: `vdrv` is guaranteed to be a valid `DriverType`.
+ to_result(unsafe { bindings::__register_virtio_driver(vdrv.get(), module.0) })
+ }
+
+ unsafe fn unregister(vdrv: &Opaque<Self::DriverType>) {
+ // SAFETY: `vdrv` is guaranteed to be a valid `DriverType`.
+ unsafe { bindings::unregister_virtio_driver(vdrv.get()) }
+ }
+}
+
+impl<T: Driver + 'static> Adapter<T> {
+ extern "C" fn probe_callback(vdev: *mut bindings::virtio_device) -> c_int {
+ // SAFETY: The kernel only ever calls the probe callback with a valid pointer to a `struct
+ // virtio_device`.
+ //
+ // INVARIANT: `vdev` is valid for the duration of `probe_callback()`.
+ let dev = unsafe { &*vdev.cast::<Device<crate::device::CoreInternal>>() };
+ from_result(|| {
+ let data = T::probe(dev);
+
+ dev.as_ref().set_drvdata(data)?;
+ // SAFETY: `Device::set_drvdata()` was just called so it's safe to borrow the data.
+ let data = unsafe { dev.as_ref().drvdata_borrow::<T>() };
+ T::init(&data, dev)?;
+ Ok(0)
+ })
+ }
+
+ extern "C" fn remove_callback(vdev: *mut bindings::virtio_device) {
+ // SAFETY: The kernel only ever calls the remove callback with a valid pointer to a `struct
+ // virtio_device`.
+ //
+ // INVARIANT: `vdev` is valid for the duration of `remove_callback()`.
+ let dev = unsafe { &*vdev.cast::<Device<crate::device::CoreInternal>>() };
+
+ // SAFETY: `remove_callback` is only ever called after a successful call to
+ // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called
+ // and stored a `Pin<KBox<T>>`.
+ let data = unsafe { dev.as_ref().drvdata_borrow::<T>() };
+
+ T::remove(dev, data);
+ }
+}
+
+/// Any vendor
+pub const VIRTIO_DEV_ANY_ID: u32 = 0xffffffff;
+
+/// Virtio IDs
+///
+/// C header: [`include/uapi/linux/virtio_ids.h`](srctree/include/uapi/linux/virtio_ids.h)
+#[repr(u32)]
+pub enum VirtioID {
+ /// virtio net
+ Net = bindings::VIRTIO_ID_NET,
+ /// virtio block
+ Block = bindings::VIRTIO_ID_BLOCK,
+ /// virtio console
+ Console = bindings::VIRTIO_ID_CONSOLE,
+ /// virtio rng
+ Rng = bindings::VIRTIO_ID_RNG,
+ /// virtio balloon
+ Balloon = bindings::VIRTIO_ID_BALLOON,
+ /// virtio ioMemory
+ IOMem = bindings::VIRTIO_ID_IOMEM,
+ /// virtio remote processor messaging
+ RPMSG = bindings::VIRTIO_ID_RPMSG,
+ /// virtio scsi
+ Scsi = bindings::VIRTIO_ID_SCSI,
+ /// 9p virtio console
+ NineP = bindings::VIRTIO_ID_9P,
+ /// virtio WLAN MAC
+ Mac80211Wlan = bindings::VIRTIO_ID_MAC80211_WLAN,
+ /// virtio remoteproc serial link
+ RPROCSerial = bindings::VIRTIO_ID_RPROC_SERIAL,
+ /// Virtio caif
+ CAIF = bindings::VIRTIO_ID_CAIF,
+ /// virtio memory balloon
+ MemoryBalloon = bindings::VIRTIO_ID_MEMORY_BALLOON,
+ /// virtio GPU
+ GPU = bindings::VIRTIO_ID_GPU,
+ /// virtio clock/timer
+ Clock = bindings::VIRTIO_ID_CLOCK,
+ /// virtio input
+ Input = bindings::VIRTIO_ID_INPUT,
+ /// virtio vsock transport
+ VSock = bindings::VIRTIO_ID_VSOCK,
+ /// virtio crypto
+ Crypto = bindings::VIRTIO_ID_CRYPTO,
+ /// virtio signal distribution device
+ SignalDist = bindings::VIRTIO_ID_SIGNAL_DIST,
+ /// virtio pstore device
+ Pstore = bindings::VIRTIO_ID_PSTORE,
+ /// virtio IOMMU
+ Iommu = bindings::VIRTIO_ID_IOMMU,
+ /// virtio mem
+ Mem = bindings::VIRTIO_ID_MEM,
+ /// virtio sound
+ Sound = bindings::VIRTIO_ID_SOUND,
+ /// virtio filesystem
+ FS = bindings::VIRTIO_ID_FS,
+ /// virtio pmem
+ PMem = bindings::VIRTIO_ID_PMEM,
+ /// virtio rpmb
+ RPMB = bindings::VIRTIO_ID_RPMB,
+ /// virtio mac80211-hwsim
+ Mac80211Hwsim = bindings::VIRTIO_ID_MAC80211_HWSIM,
+ /// virtio video encoder
+ VideoEncoder = bindings::VIRTIO_ID_VIDEO_ENCODER,
+ /// virtio video decoder
+ VideoDecoder = bindings::VIRTIO_ID_VIDEO_DECODER,
+ /// virtio SCMI
+ SCMI = bindings::VIRTIO_ID_SCMI,
+ /// virtio nitro secure module
+ NitroSecMod = bindings::VIRTIO_ID_NITRO_SEC_MOD,
+ /// virtio i2c adapter
+ I2CAdapter = bindings::VIRTIO_ID_I2C_ADAPTER,
+ /// virtio watchdog
+ Watchdog = bindings::VIRTIO_ID_WATCHDOG,
+ /// virtio can
+ CAN = bindings::VIRTIO_ID_CAN,
+ /// virtio dmabuf
+ DMABuf = bindings::VIRTIO_ID_DMABUF,
+ /// virtio parameter server
+ ParamServ = bindings::VIRTIO_ID_PARAM_SERV,
+ /// virtio audio policy
+ AudioPolicy = bindings::VIRTIO_ID_AUDIO_POLICY,
+ /// virtio bluetooth
+ BT = bindings::VIRTIO_ID_BT,
+ /// virtio gpio
+ GPIO = bindings::VIRTIO_ID_GPIO,
+ /// virtio spi
+ SPI = bindings::VIRTIO_ID_SPI,
+}
diff --git a/rust/kernel/virtio/utils.rs b/rust/kernel/virtio/utils.rs
new file mode 100644
index 0000000000000000000000000000000000000000..0c078202915127d38c3ba0bb1675c7f4cd94df6e
--- /dev/null
+++ b/rust/kernel/virtio/utils.rs
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Helper types and utilities
+
+macro_rules! endian_type {
+ (le $old_type:ident, $new_type:ident) => {
+ endian_type!($old_type, $new_type, to_le, from_le);
+ };
+ (be $old_type:ident, $new_type:ident) => {
+ endian_type!($old_type, $new_type, to_be, from_be);
+ };
+ ($old_type:ident, $new_type:ident, $to_new:ident, $from_new:ident) => {
+ /// An unsigned integer type of with an explicit endianness.
+ #[derive(Copy, Clone, Eq, PartialEq, Debug, Default, pin_init::Zeroable)]
+ #[repr(transparent)]
+ pub struct $new_type($old_type);
+
+ $crate::static_assert!(
+ ::core::mem::align_of::<$new_type>() == ::core::mem::align_of::<$old_type>()
+ );
+ $crate::static_assert!(
+ ::core::mem::size_of::<$new_type>() == ::core::mem::size_of::<$old_type>()
+ );
+
+ impl $new_type {
+ /// Convert to CPU/native endianness.
+ pub const fn to_cpu(self) -> $old_type {
+ $old_type::$from_new(self.0)
+ }
+ }
+
+ impl PartialEq<$old_type> for $new_type {
+ fn eq(&self, other: &$old_type) -> bool {
+ self.0 == $old_type::$to_new(*other)
+ }
+ }
+
+ impl PartialEq<$new_type> for $old_type {
+ fn eq(&self, other: &$new_type) -> bool {
+ $old_type::$to_new(other.0) == *self
+ }
+ }
+
+ impl From<$new_type> for $old_type {
+ fn from(v: $new_type) -> $old_type {
+ v.to_cpu()
+ }
+ }
+
+ impl From<$old_type> for $new_type {
+ fn from(v: $old_type) -> $new_type {
+ $new_type($old_type::$to_new(v))
+ }
+ }
+ };
+}
+
+endian_type!(u16, Le16, to_le, from_le);
+endian_type!(u32, Le32, to_le, from_le);
+endian_type!(u64, Le64, to_le, from_le);
+endian_type!(usize, LeSize, to_le, from_le);
+endian_type!(u16, Be16, to_be, from_be);
+endian_type!(u32, Be32, to_be, from_be);
+endian_type!(u64, Be64, to_be, from_be);
+endian_type!(usize, BeSize, to_be, from_be);
diff --git a/rust/kernel/virtio/virtqueue.rs b/rust/kernel/virtio/virtqueue.rs
new file mode 100644
index 0000000000000000000000000000000000000000..754fdad8c10199ee10e77658a7e773c8e4e95286
--- /dev/null
+++ b/rust/kernel/virtio/virtqueue.rs
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Virtqueue functionality.
+
+use crate::{
+ alloc::{
+ Flags, //
+ },
+ bindings,
+ error::{
+ code::EINVAL,
+ to_result,
+ Result, //
+ },
+ scatterlist::SGEntry,
+ str::CStr,
+ types::Opaque,
+ virtio::Device, //
+};
+
+use core::{
+ ffi::c_uint,
+ ptr::NonNull, //
+};
+
+/// Info for a virtqueue.
+///
+/// [`struct virtqueue_info`]: srctree/include/linux/virtio_config.h
+#[doc(alias = "virtqueue_info")]
+#[repr(transparent)]
+pub struct VirtqueueInfo(Opaque<bindings::virtqueue_info>);
+
+impl VirtqueueInfo {
+ /// Create a new [`VirtqueueInfo`]
+ pub const fn new(
+ name: &'static CStr,
+ ctx: bool,
+ callback: unsafe extern "C" fn(*mut bindings::virtqueue),
+ ) -> Self {
+ Self(Opaque::new(bindings::virtqueue_info {
+ name: name.as_ptr(),
+ ctx,
+ callback: Some(callback),
+ }))
+ }
+}
+
+/// An opaque handler for a virtqueue.
+///
+/// [`struct virtqueue`]: srctree/include/linux/virtio.h
+#[repr(transparent)]
+pub struct Virtqueue(Opaque<bindings::virtqueue>);
+
+impl Virtqueue {
+ /// Create a [`Virtqueue`] from a raw pointer.
+ ///
+ /// # Safety
+ ///
+ /// Callers must ensure that `ptr` is a properly initialized valid `virtqueue` pointer.
+ #[inline]
+ pub unsafe fn from_raw<'a>(ptr: *mut bindings::virtqueue) -> &'a Self {
+ // SAFETY: The safety requirements of this function guarantee that `ptr` is a valid
+ // pointer to a `struct virtqueue` for the duration of `'a`.
+ unsafe { &*ptr.cast() }
+ }
+
+ /// Obtain the raw `struct virtqueue *`.
+ #[inline]
+ pub(crate) fn as_raw(&self) -> *mut bindings::virtqueue {
+ self.0.get()
+ }
+
+ /// Get the [`Device`] associated with this virtqueue.
+ pub fn dev<Ctx: crate::device::DeviceContext>(&self) -> &Device<Ctx> {
+ // SAFETY: the pointer has been promised to be valid when self was created
+ let vdev = unsafe { *self.as_raw() }.vdev;
+ // SAFETY: the pointer has been promised to be valid when self was created
+ unsafe { &*vdev.cast::<Device<Ctx>>() }
+ }
+
+ /// Get the vring size.
+ #[doc(alias = "virtqueue_get_vring_size")]
+ pub fn vring_size(&self) -> u32 {
+ // SAFETY: the pointer has been promised to be valid when self was created
+ unsafe { bindings::virtqueue_get_vring_size(self.as_raw()) }
+ }
+
+ /// Notify virtqueue.
+ #[doc(alias = "virtqueue_notify")]
+ pub fn notify(&self) -> bool {
+ // SAFETY: the pointer has been promised to be valid when self was created
+ unsafe { bindings::virtqueue_notify(self.as_raw()) }
+ }
+
+ /// Kick and prepare virtqueue.
+ #[doc(alias = "virtqueue_kick_prepare")]
+ pub fn kick_prepare(&self) -> bool {
+ // SAFETY: the pointer has been promised to be valid when self was created
+ unsafe { bindings::virtqueue_kick_prepare(self.as_raw()) }
+ }
+
+ /// Kick virtqueue.
+ #[doc(alias = "virtqueue_kick")]
+ pub fn kick(&self) -> bool {
+ // SAFETY: the pointer has been promised to be valid when self was created
+ unsafe { bindings::virtqueue_kick(self.as_raw()) }
+ }
+
+ /// Enable virtqueue's callback.
+ #[doc(alias = "virtqueue_enable_cb")]
+ pub fn enable_cb(&self) -> bool {
+ // SAFETY: the pointer has been promised to be valid when self was created
+ unsafe { bindings::virtqueue_enable_cb(self.as_raw()) }
+ }
+
+ /// Disable virtqueue's callback.
+ #[doc(alias = "virtqueue_disable_cb")]
+ pub fn disable_cb(&self) {
+ // SAFETY: the pointer has been promised to be valid when self was created
+ unsafe { bindings::virtqueue_disable_cb(self.as_raw()) }
+ }
+
+ /// Get a buffer from the virtqueue, if available.
+ #[doc(alias = "virtqueue_get_buf")]
+ pub fn get_buf(&'_ self) -> Option<(NonNull<u8>, u32)> {
+ let mut len = 0;
+ // SAFETY: the pointer has been promised to be valid when self was created
+ let ptr = unsafe { bindings::virtqueue_get_buf(self.as_raw(), &mut len) };
+ Some((NonNull::new(ptr.cast())?, len))
+ }
+
+ /// Make a device write-only buffer available.
+ #[doc(alias = "virtqueue_add_inbuf")]
+ pub fn add_inbuf(&'_ self, sg: &SGEntry, token: *mut u8, gfp: Flags) -> Result {
+ // SAFETY: the pointer has been promised to be valid when self was created
+ to_result(unsafe {
+ bindings::virtqueue_add_inbuf(self.as_raw(), sg.as_raw(), 1, token.cast(), gfp.as_raw())
+ })
+ }
+
+ /// Make a device read-only buffer available.
+ #[doc(alias = "virtqueue_add_outbuf")]
+ pub fn add_outbuf(&'_ self, sg: &SGEntry, token: *mut u8, gfp: Flags) -> Result {
+ // SAFETY: the pointer has been promised to be valid when self was created
+ to_result(unsafe {
+ bindings::virtqueue_add_outbuf(
+ self.as_raw(),
+ sg.as_raw(),
+ 1,
+ token.cast(),
+ gfp.as_raw(),
+ )
+ })
+ }
+
+ /// Add a list of scatter-gather lists to virtqueue.
+ #[doc(alias = "virtqueue_add_sgs")]
+ pub fn add_sgs(
+ &'_ self,
+ sgs: &[&SGEntry],
+ out_sgs: c_uint,
+ in_sgs: c_uint,
+ token: *mut u8,
+ gfp: Flags,
+ ) -> Result {
+ if (out_sgs + in_sgs) as usize != sgs.len() {
+ return Err(EINVAL);
+ }
+ // SAFETY: the pointer has been promised to be valid when self was created
+ to_result(unsafe {
+ bindings::virtqueue_add_sgs(
+ self.as_raw(),
+ sgs.as_ptr().cast_mut().cast(),
+ out_sgs,
+ in_sgs,
+ token.cast(),
+ gfp.as_raw(),
+ )
+ })
+ }
+}
--
2.47.3
^ permalink raw reply related
* [PATCH RFC 4/6] rust/scatterlist: add SGEntry::init_one
From: Manos Pitsidianakis @ 2026-05-05 8:14 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Manos Pitsidianakis, Peter Hilber, Stefano Garzarella,
Stefan Hajnoczi, Viresh Kumar, Michael S. Tsirkin, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, rust-for-linux,
Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
linux-kernel, Manos Pitsidianakis
In-Reply-To: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is>
Add a method to allow creation of an SGEntry with borrowed data.
Analogous of `sg_init_one` in C.
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
---
rust/kernel/scatterlist.rs | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/rust/kernel/scatterlist.rs b/rust/kernel/scatterlist.rs
index 146e738cbd4351b41c11dd39a45e20f404c5cd64..b065762af1a734fcdd5d3acde89199f1a626fd89 100644
--- a/rust/kernel/scatterlist.rs
+++ b/rust/kernel/scatterlist.rs
@@ -95,6 +95,24 @@ pub fn dma_len(&self) -> ResourceSize {
// SAFETY: `self.as_raw()` is a valid pointer to a `struct scatterlist`.
unsafe { bindings::sg_dma_len(self.as_raw()) }.into()
}
+
+ /// Initialize a new entry with borrowed data.
+ ///
+ /// # Safety
+ ///
+ /// Callers must ensure that:
+ /// - `buf` is a valid pointer
+ /// - `buf_len` describes a valid allocation size for this pointer
+ pub unsafe fn init_one(
+ val: &'_ mut core::mem::MaybeUninit<bindings::scatterlist>,
+ buf: NonNull<u8>,
+ buf_len: u32,
+ ) -> &'_ Self {
+ // SAFETY: `val` points to a correctly sized `struct scatterlist`.
+ unsafe { bindings::sg_init_one(val.as_mut_ptr(), buf.as_ptr().cast(), buf_len) };
+ // SAFETY: `val` points to an initialized `struct scatterlist`.
+ unsafe { Self::from_raw(val.as_mut_ptr()) }
+ }
}
/// The borrowed generic type of an [`SGTable`], representing a borrowed or externally managed
--
2.47.3
^ permalink raw reply related
* [PATCH RFC 5/6] rust: impl interruptible waits for Completion
From: Manos Pitsidianakis @ 2026-05-05 8:14 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Manos Pitsidianakis, Peter Hilber, Stefano Garzarella,
Stefan Hajnoczi, Viresh Kumar, Michael S. Tsirkin, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, rust-for-linux,
Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
linux-kernel, Manos Pitsidianakis
In-Reply-To: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is>
Allow Completion to wait interruptibly.
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
---
rust/kernel/sync/completion.rs | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/rust/kernel/sync/completion.rs b/rust/kernel/sync/completion.rs
index c50012a940a3c7a3e0edf302c8f833bdc4415200..958e26f00a8e645ab080cb5d8529e31ac3042dd0 100644
--- a/rust/kernel/sync/completion.rs
+++ b/rust/kernel/sync/completion.rs
@@ -109,4 +109,43 @@ pub fn wait_for_completion(&self) {
// SAFETY: `self.as_raw()` is a pointer to a valid `struct completion`.
unsafe { bindings::wait_for_completion(self.as_raw()) };
}
+
+ /// Wait for completion of a task.
+ ///
+ /// This method waits for the completion of a task; it is not interruptible and there is no
+ /// timeout.
+ ///
+ /// See also [`Completion::complete_all`].
+ pub fn wait_for_completion_interruptible(&self) -> Result {
+ // SAFETY: `self.as_raw()` is a pointer to a valid `struct completion`.
+ let err = unsafe { bindings::wait_for_completion_interruptible(self.as_raw()) };
+ if err < 0 {
+ Err(Error::from_errno(err))
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Wait for completion of a task.
+ ///
+ /// This method waits for the completion of a task; it is not interruptible and there is no
+ /// timeout.
+ ///
+ /// See also [`Completion::complete_all`].
+ pub fn wait_for_completion_interruptible_timeout(
+ &self,
+ timeout_jiffies: c_ulong,
+ ) -> Result<c_long> {
+ // SAFETY: `self.as_raw()` is a pointer to a valid `struct completion`.
+ let ret: c_long = unsafe {
+ bindings::wait_for_completion_interruptible_timeout(self.as_raw(), timeout_jiffies)
+ };
+ if ret == 0 {
+ Err(ETIMEDOUT)
+ } else if ret < 0 {
+ Err(Error::from_errno(ret as c_int))
+ } else {
+ Ok(ret)
+ }
+ }
}
--
2.47.3
^ permalink raw reply related
* [PATCH RFC 6/6] samples/rust: Add sample virtio-rtc driver [WIP]
From: Manos Pitsidianakis @ 2026-05-05 8:14 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Manos Pitsidianakis, Peter Hilber, Stefano Garzarella,
Stefan Hajnoczi, Viresh Kumar, Michael S. Tsirkin, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, rust-for-linux,
Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
linux-kernel, Manos Pitsidianakis
In-Reply-To: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is>
While the driver queries clocks and capabilities for each clock, it
doesn't actually register them yet (TODO).
Until I implement missing functionality, there is some dead code and
some missing SAFETY comments.
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
---
MAINTAINERS | 1 +
samples/rust/Kconfig | 15 ++
samples/rust/Makefile | 1 +
samples/rust/rust_virtio_rtc.rs | 470 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 487 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index e8012f708df5d4ee858c82aec3269e615fc8caad..3ed579e8d3cc64d1749cf261cd68f6338a830c4d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27937,6 +27937,7 @@ S: Maintained
F: rust/helpers/virtio.c
F: rust/kernel/virtio.rs
F: rust/kernel/virtio/
+F: samples/rust/rust_virtio_rtc.rs
VIRTIO CRYPTO DRIVER
M: Gonglei <arei.gonglei@huawei.com>
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
index c49ab910634596aea4a1a73dac87585e084f420a..96a16aecc27198fd99f4ffd0ecdf0bc0876860c6 100644
--- a/samples/rust/Kconfig
+++ b/samples/rust/Kconfig
@@ -179,4 +179,19 @@ config SAMPLE_RUST_HOSTPROGS
If unsure, say N.
+config SAMPLE_RUST_VIRTIO_RTC
+ tristate "Rust Virtio RTC driver"
+ depends on VIRTIO
+ depends on PTP_1588_CLOCK_OPTIONAL
+ help
+ This driver provides current time from a Virtio RTC device. The driver
+ provides the time through one or more clocks. The Virtio RTC PTP
+ clocks and/or the Real Time Clock driver for Virtio RTC must be
+ enabled to expose the clocks to userspace.
+
+ To compile this code as a module, choose M here: the module will be
+ called rust_virtio_rtc.
+
+ If unsure, say M.
+
endif # SAMPLES_RUST
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
index 6c0aaa58ccccfd12ef019f68ca784f6d977bc668..0142fd8656bb8cdc95b7ef54e3183b5e51358954 100644
--- a/samples/rust/Makefile
+++ b/samples/rust/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX) += rust_driver_faux.o
obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY) += rust_driver_auxiliary.o
obj-$(CONFIG_SAMPLE_RUST_CONFIGFS) += rust_configfs.o
obj-$(CONFIG_SAMPLE_RUST_SOC) += rust_soc.o
+obj-$(CONFIG_SAMPLE_RUST_VIRTIO_RTC) += rust_virtio_rtc.o
rust_print-y := rust_print_main.o rust_print_events.o
diff --git a/samples/rust/rust_virtio_rtc.rs b/samples/rust/rust_virtio_rtc.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f580ed83a0a57a4b051372a51f56b787d53ed602
--- /dev/null
+++ b/samples/rust/rust_virtio_rtc.rs
@@ -0,0 +1,470 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust virtio driver sample.
+
+use core::{
+ cell::Cell,
+ marker::PhantomData,
+ ptr::NonNull, //
+};
+
+use kernel::{
+ device::{
+ Core,
+ CoreInternal, //
+ },
+ new_mutex, new_spinlock, page,
+ prelude::*,
+ scatterlist::SGEntry,
+ sync::Completion,
+ sync::{Mutex, SpinLock},
+ virtio::{
+ self,
+ utils::*,
+ virtqueue::*, //
+ },
+};
+
+use pin_init::stack_try_pin_init;
+
+#[pin_data]
+struct Token {
+ resp_actual_size: u32,
+ #[pin]
+ responded: Completion,
+}
+
+#[pin_data]
+struct Message<Request: Zeroable, Response: Zeroable> {
+ msg_type: u16,
+ #[pin]
+ req: KVec<u8>,
+ #[pin]
+ resp: KVec<u8>,
+ req_ptr: NonNull<Request>,
+ resp_ptr: NonNull<Response>,
+ #[pin]
+ token: Token,
+ _ph_req: PhantomData<Request>,
+ _ph_resp: PhantomData<Response>,
+}
+
+#[derive(Copy, Clone, Debug, Zeroable)]
+#[repr(C)]
+#[doc(alias = "virtio_rtc_req_head")]
+struct ReqHead {
+ msg_type: Le16,
+ reserved: [u8; 6],
+}
+
+#[derive(Debug, Zeroable)]
+#[repr(C)]
+#[doc(alias = "virtio_rtc_resp_head")]
+struct RespHead {
+ status: u8,
+ reserved: [u8; 7],
+}
+
+#[derive(Debug, Zeroable)]
+#[repr(C)]
+#[doc(alias = "virtio_rtc_resp_cfg")]
+struct RespCfg {
+ head: ReqHead,
+ /** # of clocks -> clock ids < num_clocks are valid */
+ num_clocks: Le16,
+ reserved: [u8; 6],
+}
+
+#[derive(Debug, Zeroable)]
+#[repr(C)]
+#[doc(alias = "virtio_rtc_req_clock_cap")]
+struct ReqClockCap {
+ head: ReqHead,
+ clock_id: Le16,
+ reserved: [u8; 6],
+}
+
+#[derive(Copy, Clone, Debug, Zeroable)]
+#[repr(C)]
+#[doc(alias = "virtio_rtc_resp_clock_cap")]
+struct RespClockCap {
+ head: ReqHead,
+ clock_type: u8,
+ leap_second_smearing: u8,
+ flags: u8,
+ reserved: [u8; 5],
+}
+
+#[derive(Debug, Zeroable)]
+#[repr(C)]
+#[doc(alias = "virtio_rtc_req_read")]
+struct ReqRead {
+ head: ReqHead,
+ clock_id: Le16,
+ reserved: [u8; 6],
+}
+
+#[derive(Copy, Clone, Debug, Zeroable)]
+#[repr(C)]
+#[doc(alias = "virtio_rtc_resp_read")]
+struct RespRead {
+ head: ReqHead,
+ clock_reading: Le64,
+}
+
+#[repr(u8)]
+enum ClockType {
+ #[doc(alias = "VIRTIO_RTC_CLOCK_UTC")]
+ Utc = 0,
+ #[doc(alias = "VIRTIO_RTC_CLOCK_TAI")]
+ Tai = 1,
+ #[doc(alias = "VIRTIO_RTC_CLOCK_MONOTONIC")]
+ Monotonic = 2,
+ #[doc(alias = "VIRTIO_RTC_CLOCK_UTC_SMEARED")]
+ UtcSmeared = 3,
+ #[doc(alias = "VIRTIO_RTC_CLOCK_UTC_MAYBE_SMEARED")]
+ UtcMaybeSmeared = 4,
+}
+
+// SAFETY: `Message` is safe to be send to any task.
+unsafe impl<Request: Zeroable, Response: Zeroable> Send for Message<Request, Response> {}
+
+// SAFETY: `Message` is safe to be accessed concurrently.
+unsafe impl<Request: Zeroable, Response: Zeroable> Sync for Message<Request, Response> {}
+
+impl<Request: Zeroable, Response: Zeroable> Message<Request, Response> {
+ /// Create an initializer for a new [`Message`].
+ fn new(req_data: Request, msg_type: u16) -> Result<impl PinInit<Self, Error>> {
+ macro_rules! alloc_buf {
+ ($t:ty) => {{
+ let size = (core::mem::size_of::<$t>() / page::PAGE_SIZE + 1) * page::PAGE_SIZE;
+ KVec::<u8>::with_capacity(size, GFP_KERNEL)
+ }};
+ }
+ let mut req = alloc_buf!(Request)?;
+ let mut resp = alloc_buf!(Response)?;
+ let req_ptr: NonNull<Request> = NonNull::new(req.as_mut_ptr().cast()).unwrap();
+ let resp_ptr = NonNull::new(resp.as_mut_ptr().cast()).unwrap();
+ // SAFETY: `req_ptr` is a valid Request allocation
+ unsafe {
+ core::ptr::write(req_ptr.as_ptr(), req_data);
+ }
+ Ok(pin_init!(Self {
+ req,
+ resp,
+ msg_type,
+ req_ptr,
+ resp_ptr,
+ token <- pin_init!(Token {
+ resp_actual_size: 0,
+ responded <- Completion::new(),
+ }),
+ _ph_req: PhantomData,
+ _ph_resp: PhantomData,
+ }? Error))
+ }
+
+ fn get_response(&self) -> Result<&Response, Error> {
+ if self.token.resp_actual_size as usize != core::mem::size_of::<Response>() {
+ if self.token.resp_actual_size as usize >= core::mem::size_of::<RespHead>() {
+ let head: &RespHead = unsafe { self.resp_ptr.cast().as_ref() };
+ return match head.status {
+ 0 | 3 => Err(EINVAL),
+ 1 => Err(ENOTSUPP),
+ 2 => Err(ENODEV),
+ 4 | 5_u8..=u8::MAX => Err(EIO),
+ };
+ }
+ return Err(EINVAL);
+ }
+ Ok(unsafe { self.resp_ptr.as_ref() })
+ }
+
+ fn send(&self, vq: &SpinLock<VirtioRtcVq>, timeout_jiffies: c_ulong) -> Result {
+ let guard = vq.lock();
+
+ let mut sg_in = core::mem::MaybeUninit::zeroed();
+ let mut sg_out = core::mem::MaybeUninit::zeroed();
+ let req = unsafe {
+ SGEntry::init_one(
+ &mut sg_out,
+ self.req_ptr.cast(),
+ core::mem::size_of::<Request>() as u32,
+ )
+ };
+ let resp = unsafe {
+ SGEntry::init_one(
+ &mut sg_in,
+ self.resp_ptr.cast(),
+ core::mem::size_of::<Response>() as u32,
+ )
+ };
+ let sgs = [req, resp];
+ guard.as_ref().add_sgs(
+ &sgs,
+ 1,
+ 1,
+ (&raw const self.token).cast_mut().cast(),
+ GFP_ATOMIC,
+ )?;
+
+ if guard.as_ref().kick_prepare() {
+ guard.as_ref().notify();
+ }
+ drop(guard);
+
+ if timeout_jiffies > 0 {
+ self.token
+ .responded
+ .wait_for_completion_interruptible_timeout(timeout_jiffies)?;
+ } else {
+ self.token.responded.wait_for_completion_interruptible()?;
+ }
+ Ok(())
+ }
+}
+
+// TODO: use a proper enum
+
+const VIRTIO_RTC_REQ_READ: u16 = 0x0001;
+const VIRTIO_RTC_REQ_CFG: u16 = 0x1000;
+const VIRTIO_RTC_REQ_CLOCK_CAP: u16 = 0x1001;
+
+struct VirtioRtcVq {
+ ptr: NonNull<Virtqueue>,
+}
+
+// SAFETY: `VirtioRtcVq` is safe to be send to any task.
+unsafe impl Send for VirtioRtcVq {}
+
+impl VirtioRtcVq {
+ fn new(ptr: *mut Virtqueue) -> impl PinInit<SpinLock<Self>> {
+ let ptr = NonNull::new(ptr).unwrap();
+ new_spinlock!(Self { ptr })
+ }
+
+ fn as_ref(&self) -> &Virtqueue {
+ unsafe { self.ptr.as_ref() }
+ }
+}
+
+struct VirtioRtcDriver {
+ reqvq: Pin<KBox<SpinLock<VirtioRtcVq>>>,
+ alarmvq: Option<Pin<KBox<SpinLock<VirtioRtcVq>>>>,
+ num_clocks: Cell<u16>,
+ registered_clocks: Pin<KBox<Mutex<KVec<()>>>>,
+}
+
+impl Drop for VirtioRtcDriver {
+ fn drop(&mut self) {
+ pr_info!("Remove Rust virtio driver sample.\n");
+ }
+}
+
+unsafe extern "C" fn vq_requestq_callback(vq: *mut kernel::bindings::virtqueue) {
+ let vq = unsafe { Virtqueue::from_raw(vq) };
+ let dev: &virtio::Device<CoreInternal> = vq.dev();
+ let data = unsafe { dev.as_ref().drvdata_borrow::<VirtioRtcDriver>() };
+ data.process_requestq();
+}
+
+impl VirtioRtcDriver {
+ /// Submit `VIRTIO_RTC_REQ_CFG` and return response (`num_clocks`)
+ fn req_cfg(&self) -> Result<u16> {
+ let head = ReqHead {
+ msg_type: VIRTIO_RTC_REQ_CFG.into(),
+ reserved: [0; 6],
+ };
+ stack_try_pin_init!(
+ let msg: Message::<ReqHead, RespCfg> =
+ Message::new(head, VIRTIO_RTC_REQ_CFG)?);
+ let msg: core::pin::Pin<&mut Message<ReqHead, RespCfg>> = msg?;
+ msg.send(&self.reqvq, 0)?;
+ pr_info!("Got response! {:?}\n", msg.get_response());
+
+ let response: &RespCfg = msg.get_response()?;
+ Ok(response.num_clocks.into())
+ }
+
+ fn process_requestq(&self) {
+ let mut cb_enabled = true;
+ loop {
+ let guard = self.reqvq.lock();
+ if cb_enabled {
+ guard.as_ref().disable_cb();
+ cb_enabled = false;
+ }
+ if let Some((token, len)) = guard.as_ref().get_buf() {
+ drop(guard);
+ pr_info!("process_requestq got buf {len} bytes\n");
+ let mut token = token.cast::<Token>();
+
+ unsafe { token.as_mut().resp_actual_size = len };
+ unsafe { token.as_mut().responded.complete_all() };
+ } else {
+ if guard.as_ref().enable_cb() {
+ return;
+ }
+ cb_enabled = true;
+ }
+ }
+ }
+
+ fn clock_cap(&self, clock_id: u16) -> Result<RespClockCap> {
+ type ClockCapMsg = Message<ReqClockCap, RespClockCap>;
+
+ let req = ReqClockCap {
+ head: ReqHead {
+ msg_type: VIRTIO_RTC_REQ_CLOCK_CAP.into(),
+ reserved: [0; 6],
+ },
+ clock_id: clock_id.into(),
+ reserved: [0; 6],
+ };
+ stack_try_pin_init!(
+ let msg: ClockCapMsg = Message::new(req, VIRTIO_RTC_REQ_CLOCK_CAP)?
+ );
+ let msg: core::pin::Pin<&mut ClockCapMsg> = msg?;
+ msg.send(&self.reqvq, 0)?;
+ pr_info!("Got response! {:?}\n", msg.get_response());
+ let response: &RespClockCap = msg.get_response()?;
+ Ok(*response)
+ }
+
+ fn read(&self, clock_id: u16) -> Result<u64> {
+ type ReadMsg = Message<ReqRead, RespRead>;
+
+ let req = ReqRead {
+ head: ReqHead {
+ msg_type: VIRTIO_RTC_REQ_READ.into(),
+ reserved: [0; 6],
+ },
+ clock_id: clock_id.into(),
+ reserved: [0; 6],
+ };
+ stack_try_pin_init!(
+ let msg: ReadMsg = Message::new(req, VIRTIO_RTC_REQ_CLOCK_CAP)?
+ );
+ let msg: core::pin::Pin<&mut ReadMsg> = msg?;
+ msg.send(&self.reqvq, 0)?;
+ pr_info!("Got response! {:?}\n", msg.get_response());
+ let response: &RespRead = msg.get_response()?;
+ Ok(response.clock_reading.into())
+ }
+}
+
+impl virtio::Driver for VirtioRtcDriver {
+ type IdInfo = ();
+
+ /// The table of device ids supported by the driver.
+ const ID_TABLE: virtio::IdTable<Self::IdInfo> = &VIRTIO_RTC_TABLE;
+
+ fn probe(vdev: &virtio::Device<Core>) -> impl PinInit<Self, Error> {
+ const VQS_INFO: [VirtqueueInfo; 1] = [
+ VirtqueueInfo::new(c"requestq", false, vq_requestq_callback),
+ //VirtqueueInfo::new(c"alarmq", false, vq_callback),
+ ];
+ let init_fn = move |slot: *mut Self| {
+ pr_info!("Probe Rust virtio driver sample.\n");
+ let vqs = match vdev.find_vqs(&VQS_INFO) {
+ Ok(vqs) => {
+ pr_info!("Found {} vqs.\n", vqs.len());
+ vqs
+ }
+ Err(err) => {
+ pr_info!("Could not find vqs: {err:?}.\n");
+
+ return Err(err);
+ }
+ };
+ let reqvq = KBox::pin_init(VirtioRtcVq::new(vqs[0]), GFP_ATOMIC)?;
+ let registered_clocks =
+ KBox::pin_init(new_mutex!(KVec::with_capacity(0, GFP_KERNEL)?), GFP_KERNEL)?;
+ unsafe {
+ core::ptr::write(
+ slot,
+ Self {
+ num_clocks: Cell::new(0),
+ reqvq,
+ alarmvq: None,
+ registered_clocks,
+ },
+ )
+ };
+ Ok(())
+ };
+ unsafe { pin_init::pin_init_from_closure(init_fn) }
+ }
+
+ fn init(&self, vdev: &virtio::Device<Core>) -> Result {
+ vdev.ready();
+ self.num_clocks.set(self.req_cfg()?);
+ for i in 0..(self.num_clocks.get()) {
+ let mut is_exposed = false;
+
+ let resp = self.clock_cap(i)?;
+ let (clock_type, leap_second_smearing, flags) =
+ (resp.clock_type, resp.leap_second_smearing, resp.flags);
+ if cfg!(CONFIG_VIRTIO_RTC_CLASS)
+ && (clock_type == ClockType::Utc as u8
+ || clock_type == ClockType::UtcSmeared as u8
+ || clock_type == ClockType::UtcMaybeSmeared as u8)
+ {
+ // TODO:
+
+ // ret = viortc_init_rtc_class_clock(viortc, vio_clk_id,
+ // clock_type, flags);
+ // if (ret < 0)
+ // return ret;
+ // if (ret > 0)
+ // is_exposed = true;
+ dev_warn!(vdev.as_ref(), "CONFIG_VIRTIO_RTC_CLASS TODO ");
+ }
+
+ if cfg!(CONFIG_VIRTIO_RTC_PTP) {
+ // TODO:
+
+ // ret = viortc_init_ptp_clock(viortc, vio_clk_id, clock_type,
+ // leap_second_smearing);
+ // if (ret < 0)
+ // return ret;
+ // if (ret > 0)
+ // is_exposed = true;
+ // todo!()
+ dev_warn!(vdev.as_ref(), "CONFIG_VIRTIO_RTC_PTP TODO ");
+ }
+
+ if !is_exposed {
+ dev_warn!(
+ vdev.as_ref(),
+ "cannot expose clock {i} (type {clock_type}, variant {leap_second_smearing}, \
+ flags {flags}) to userspace\n"
+ );
+ }
+ let clock_reading = self.read(i)?;
+ pr_info!("#{i} clock reading = {clock_reading}\n");
+ }
+ Ok(())
+ }
+
+ fn remove(vdev: &virtio::Device, _this: Pin<&Self>) {
+ pr_info!("Removing Rust virtio driver sample.\n");
+ vdev.reset();
+ vdev.del_vqs();
+ }
+}
+
+kernel::virtio_device_table!(
+ VIRTIO_RTC_TABLE,
+ MODULE_VIRTIO_RTC_TABLE,
+ <VirtioRtcDriver as virtio::Driver>::IdInfo,
+ [(virtio::DeviceId::new(virtio::VirtioID::Clock), ())]
+);
+
+kernel::module_virtio_driver! {
+ type: VirtioRtcDriver,
+ name: "rust_virtio_rtc",
+ authors: ["Manos Pitsidianakis"],
+ description: "Rust virtio driver",
+ license: "GPL v2",
+}
--
2.47.3
^ permalink raw reply related
* Re: [PATCH] vsock/virtio: fix vsockmon info leak in non-linear tap copy
From: Paolo Abeni @ 2026-05-05 10:26 UTC (permalink / raw)
To: sgarzare, stefanha
Cc: netdev, linux-kernel, mst, jasowang, xuanzhuo, eperezma, davem,
edumazet, kuba, horms, Yiqi Sun, kvm, virtualization
In-Reply-To: <20260430071110.380509-1-sunyiqixm@gmail.com>
On 4/30/26 9:11 AM, Yiqi Sun wrote:
> vsockmon mirrors packets through virtio_transport_build_skb(), which
> builds a new skb and copies the payload into it. For non-linear skbs,
> this goes through virtio_transport_copy_nonlinear_skb().
>
> Helper manually initializes a iov_iter, but leaves iov_iter.count unset.
> As a result, skb_copy_datagram_iter() sees zero writable bytes
> in the destination iterator and copies no payload data.
>
> This becomes an info leak because virtio_transport_build_skb() has
> already reserved payload_len bytes in the new skb with skb_put(). The
> skb is then returned to the tap path with that payload area still
> uninitialized, so userspace reading from a vsockmon device can observe
> heap contents and potentially kernel address.
>
> Fix it by initializing iov_iter.count to the number of bytes to copy.
>
> Fixes: 4b0bf10eb077 ("vsock/virtio: non-linear skb handling for tap")
> Signed-off-by: Yiqi Sun <sunyiqixm@gmail.com>
> ---
> net/vmw_vsock/virtio_transport_common.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
> index 416d533f493d..6b26ee57ccab 100644
> --- a/net/vmw_vsock/virtio_transport_common.c
> +++ b/net/vmw_vsock/virtio_transport_common.c
> @@ -152,7 +152,7 @@ static void virtio_transport_copy_nonlinear_skb(const struct sk_buff *skb,
> iov_iter.nr_segs = 1;
>
> to_copy = min_t(size_t, len, skb->len);
> -
> + iov_iter.count = to_copy;
> skb_copy_datagram_iter(skb, VIRTIO_VSOCK_SKB_CB(skb)->offset,
> &iov_iter, to_copy);
@Stefano, @Stefan, the patch LGTM, but sashiko pointed out to a
pre-existing issue you should probably want to address:
> to_copy = min_t(size_t, len, skb->len);
Does this length calculation account for the offset when a packet is
split across multiple transmissions?
If a packet is requeued, VIRTIO_VSOCK_SKB_CB(skb)->offset is increased,
but to_copy still evaluates to the full length of the skb.
/P
^ permalink raw reply
* Re: [PATCH] vsock/virtio: fix vsockmon info leak in non-linear tap copy
From: Stefano Garzarella @ 2026-05-05 12:44 UTC (permalink / raw)
To: Paolo Abeni, Arseniy Krasnov, Bobby Eshleman
Cc: stefanha, netdev, linux-kernel, mst, jasowang, xuanzhuo, eperezma,
davem, edumazet, kuba, horms, Yiqi Sun, kvm, virtualization
In-Reply-To: <f4e52dcd-59ba-4c2e-9936-49cf27528b21@redhat.com>
CCing Arseniy and Bobby.
On Tue, May 05, 2026 at 12:26:21PM +0200, Paolo Abeni wrote:
>On 4/30/26 9:11 AM, Yiqi Sun wrote:
>> vsockmon mirrors packets through virtio_transport_build_skb(), which
>> builds a new skb and copies the payload into it. For non-linear skbs,
>> this goes through virtio_transport_copy_nonlinear_skb().
>>
>> Helper manually initializes a iov_iter, but leaves iov_iter.count unset.
>> As a result, skb_copy_datagram_iter() sees zero writable bytes
>> in the destination iterator and copies no payload data.
>>
>> This becomes an info leak because virtio_transport_build_skb() has
>> already reserved payload_len bytes in the new skb with skb_put(). The
>> skb is then returned to the tap path with that payload area still
>> uninitialized, so userspace reading from a vsockmon device can observe
>> heap contents and potentially kernel address.
>>
>> Fix it by initializing iov_iter.count to the number of bytes to copy.
>>
>> Fixes: 4b0bf10eb077 ("vsock/virtio: non-linear skb handling for tap")
>> Signed-off-by: Yiqi Sun <sunyiqixm@gmail.com>
>> ---
>> net/vmw_vsock/virtio_transport_common.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
>> index 416d533f493d..6b26ee57ccab 100644
>> --- a/net/vmw_vsock/virtio_transport_common.c
>> +++ b/net/vmw_vsock/virtio_transport_common.c
>> @@ -152,7 +152,7 @@ static void virtio_transport_copy_nonlinear_skb(const struct sk_buff *skb,
>> iov_iter.nr_segs = 1;
>>
>> to_copy = min_t(size_t, len, skb->len);
>> -
>> + iov_iter.count = to_copy;
>> skb_copy_datagram_iter(skb, VIRTIO_VSOCK_SKB_CB(skb)->offset,
>> &iov_iter, to_copy);
>
>@Stefano, @Stefan, the patch LGTM, but sashiko pointed out to a
>pre-existing issue you should probably want to address:
>
>> to_copy = min_t(size_t, len, skb->len);
>Does this length calculation account for the offset when a packet is
>split across multiple transmissions?
>If a packet is requeued, VIRTIO_VSOCK_SKB_CB(skb)->offset is increased,
>but to_copy still evaluates to the full length of the skb.
Yep, I just checked and vhost-vsock is the only place where we call
virtio_transport_deliver_tap_pkt() wiht an offset != 0, but I agree that
we should also fix it.
Looking better in net/vmw_vsock/virtio_transport_common.c I think this
is a regression, indeed we have this comment in
virtio_transport_build_skb():
/* A packet could be split to fit the RX buffer, so we can retrieve
* the payload length from the header and the buffer pointer taking
* care of the offset in the original packet.
*/
pkt_hdr = virtio_vsock_hdr(pkt);
Before commit 71dc9ec9ac7d ("virtio/vsock: replace virtio_vsock_pkt with
sk_buff") we read the payload lenght from the header that is always set
to the right value before delivering the packet to the tap.
From that commit, we don't to consider the offset anymore since we
started to use `len` from the skb, so IMO we should go back to what we
did before it, I mean:
payload_len = le32_to_cpu(pkt->hdr.len);
@Bobby do you remember why we did that change? Or if you see any issue
going back to what we did initially?
Also IMO we should avoid to set all the iov_iter fields by hand and
start to use iov_iter_kvec(). Plus, we can just use
skb_copy_datagram_iter() in any case, like we already do in vhost-vsock,
since it already handles linear vs non linear.
At the end I mean something like this:
@@ -171,7 +150,7 @@ static struct sk_buff *virtio_transport_build_skb(void *opaque)
* care of the offset in the original packet.
*/
pkt_hdr = virtio_vsock_hdr(pkt);
- payload_len = pkt->len;
+ payload_len = le32_to_cpu(pkt_hdr->len);
skb = alloc_skb(sizeof(*hdr) + sizeof(*pkt_hdr) + payload_len,
GFP_ATOMIC);
@@ -214,13 +193,17 @@ static struct sk_buff *virtio_transport_build_skb(void *opaque)
skb_put_data(skb, pkt_hdr, sizeof(*pkt_hdr));
if (payload_len) {
- if (skb_is_nonlinear(pkt)) {
- void *data = skb_put(skb, payload_len);
+ struct iov_iter iov_iter;
+ struct kvec kvec;
+ void *data = skb_put(skb, payload_len);
- virtio_transport_copy_nonlinear_skb(pkt, data, payload_len);
- } else {
- skb_put_data(skb, pkt->data, payload_len);
- }
+ kvec.iov_base = data;
+ kvec.iov_len = payload_len;
+ iov_iter_kvec(&iov_iter, READ, &kvec, 1, payload_len);
+
+ skb_copy_datagram_iter(pkt,
+ VIRTIO_VSOCK_SKB_CB(pkt)->offset,
+ &iov_iter, payload_len);
}
return skb;
And removing virtio_transport_copy_nonlinear_skb().
If you agree, I can send a proper series with these changes that should
fix the issue reported by Yiqi Sun introduced by commit 4b0bf10eb077
("vsock/virtio: non-linear skb handling for tap") and the issue
introduced by commit 71dc9ec9ac7d ("virtio/vsock: replace
virtio_vsock_pkt with sk_buff").
Thanks,
Stefano
^ permalink raw reply
* Re: [PATCH net] vsock/virtio: fix potential unbounded skb queue
From: Stefano Garzarella @ 2026-05-05 13:51 UTC (permalink / raw)
To: Eric Dumazet
Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
netdev, eric.dumazet, Arseniy Krasnov, Stefan Hajnoczi,
Michael S. Tsirkin, Jason Wang, Xuan Zhuo, Eugenio Pérez,
kvm, virtualization
In-Reply-To: <20260430122653.554058-1-edumazet@google.com>
On Thu, Apr 30, 2026 at 12:26:52PM +0000, Eric Dumazet wrote:
>virtio_transport_inc_rx_pkt() checks vvs->rx_bytes + len > vvs->buf_alloc.
>
>virtio_transport_recv_enqueue() skips coalescing for packets
>with VIRTIO_VSOCK_SEQ_EOM.
>
>If fed with packets with len == 0 and VIRTIO_VSOCK_SEQ_EOM,
>a very large number of packets can be queued
>because vvs->rx_bytes stays at 0.
>
>Fix this by estimating the skb metadata size:
>
> (Number of skbs in the queue) * SKB_TRUESIZE(0)
>
>Fixes: 077706165717 ("virtio/vsock: don't use skbuff state to account credit")
>Signed-off-by: Eric Dumazet <edumazet@google.com>
>Cc: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
>Cc: Stefan Hajnoczi <stefanha@redhat.com>
>Cc: Stefano Garzarella <sgarzare@redhat.com>
>Cc: "Michael S. Tsirkin" <mst@redhat.com>
>Cc: Jason Wang <jasowang@redhat.com>
>Cc: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
>Cc: "Eugenio Pérez" <eperezma@redhat.com>
>Cc: kvm@vger.kernel.org
>Cc: virtualization@lists.linux.dev
>---
> net/vmw_vsock/virtio_transport_common.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
>diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
>index 416d533f493d7b07e9c77c43f741d28cfcd0953e..9b8014516f4fb1130ae184635fbba4dfee58bd64 100644
>--- a/net/vmw_vsock/virtio_transport_common.c
>+++ b/net/vmw_vsock/virtio_transport_common.c
>@@ -447,7 +447,9 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
> static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs,
> u32 len)
> {
>- if (vvs->buf_used + len > vvs->buf_alloc)
>+ u64 skb_overhead = (skb_queue_len(&vvs->rx_queue) + 1) * SKB_TRUESIZE(0);
>+
>+ if (skb_overhead + vvs->buf_used + len > vvs->buf_alloc)
> return false;
I'm not sure about this fix, I mean that maybe this is incomplete.
In virtio-vsock, there is a credit mechanism between the two peers:
https://docs.oasis-open.org/virtio/virtio/v1.3/csd01/virtio-v1.3-csd01.html#x1-4850003
This takes only the payload into account, so it’s true that this problem
exists; however, perhaps we should also inform the other peer of a lower
credit balance, otherwise the other peer will believe it has much more
credit than it actually does, send a large payload, and then the packet
will be discarded and the data lost (there are no retransmissions,
etc.).
Thanks,
Stefano
^ permalink raw reply
* Re: [PATCH net] vsock/virtio: fix potential unbounded skb queue
From: Eric Dumazet @ 2026-05-05 14:14 UTC (permalink / raw)
To: Stefano Garzarella
Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
netdev, eric.dumazet, Arseniy Krasnov, Stefan Hajnoczi,
Michael S. Tsirkin, Jason Wang, Xuan Zhuo, Eugenio Pérez,
kvm, virtualization
In-Reply-To: <afn0ZdvZWswBuDMm@sgarzare-redhat>
On Tue, May 5, 2026 at 6:52 AM Stefano Garzarella <sgarzare@redhat.com> wrote:
>
> On Thu, Apr 30, 2026 at 12:26:52PM +0000, Eric Dumazet wrote:
> >virtio_transport_inc_rx_pkt() checks vvs->rx_bytes + len > vvs->buf_alloc.
> >
> >virtio_transport_recv_enqueue() skips coalescing for packets
> >with VIRTIO_VSOCK_SEQ_EOM.
> >
> >If fed with packets with len == 0 and VIRTIO_VSOCK_SEQ_EOM,
> >a very large number of packets can be queued
> >because vvs->rx_bytes stays at 0.
> >
> >Fix this by estimating the skb metadata size:
> >
> > (Number of skbs in the queue) * SKB_TRUESIZE(0)
> >
> >Fixes: 077706165717 ("virtio/vsock: don't use skbuff state to account credit")
> >Signed-off-by: Eric Dumazet <edumazet@google.com>
> >Cc: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
> >Cc: Stefan Hajnoczi <stefanha@redhat.com>
> >Cc: Stefano Garzarella <sgarzare@redhat.com>
> >Cc: "Michael S. Tsirkin" <mst@redhat.com>
> >Cc: Jason Wang <jasowang@redhat.com>
> >Cc: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
> >Cc: "Eugenio Pérez" <eperezma@redhat.com>
> >Cc: kvm@vger.kernel.org
> >Cc: virtualization@lists.linux.dev
> >---
> > net/vmw_vsock/virtio_transport_common.c | 4 +++-
> > 1 file changed, 3 insertions(+), 1 deletion(-)
> >
> >diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
> >index 416d533f493d7b07e9c77c43f741d28cfcd0953e..9b8014516f4fb1130ae184635fbba4dfee58bd64 100644
> >--- a/net/vmw_vsock/virtio_transport_common.c
> >+++ b/net/vmw_vsock/virtio_transport_common.c
> >@@ -447,7 +447,9 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
> > static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs,
> > u32 len)
> > {
> >- if (vvs->buf_used + len > vvs->buf_alloc)
> >+ u64 skb_overhead = (skb_queue_len(&vvs->rx_queue) + 1) * SKB_TRUESIZE(0);
> >+
> >+ if (skb_overhead + vvs->buf_used + len > vvs->buf_alloc)
> > return false;
>
> I'm not sure about this fix, I mean that maybe this is incomplete.
> In virtio-vsock, there is a credit mechanism between the two peers:
> https://docs.oasis-open.org/virtio/virtio/v1.3/csd01/virtio-v1.3-csd01.html#x1-4850003
>
> This takes only the payload into account, so it’s true that this problem
> exists; however, perhaps we should also inform the other peer of a lower
> credit balance, otherwise the other peer will believe it has much more
> credit than it actually does, send a large payload, and then the packet
> will be discarded and the data lost (there are no retransmissions,
> etc.).
I dunno, perhaps revert 077706165717 ("virtio/vsock: don't use skbuff
state to account credit")
and find a better fix then?
There is always a discrepancy between skb->len and skb->truesize.
You will not be able to announce a 1MB window, and accept one milliion
skb of 1-byte each.
This kind of contract is broken.
^ permalink raw reply
* Re: [PATCH net] vsock/virtio: fix potential unbounded skb queue
From: Stefano Garzarella @ 2026-05-05 16:11 UTC (permalink / raw)
To: Eric Dumazet, Arseniy Krasnov, Bobby Eshleman, Stefan Hajnoczi,
Michael S. Tsirkin
Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
netdev, eric.dumazet, Arseniy Krasnov, Stefan Hajnoczi,
Michael S. Tsirkin, Jason Wang, Xuan Zhuo, Eugenio Pérez,
kvm, virtualization
In-Reply-To: <CANn89iLs8DOWJwDpf_ARoMrV+6b2tbhEJ=VVzeC8gCm5dRGaig@mail.gmail.com>
On Tue, May 05, 2026 at 07:14:36AM -0700, Eric Dumazet wrote:
>On Tue, May 5, 2026 at 6:52 AM Stefano Garzarella <sgarzare@redhat.com> wrote:
>>
>> On Thu, Apr 30, 2026 at 12:26:52PM +0000, Eric Dumazet wrote:
>> >virtio_transport_inc_rx_pkt() checks vvs->rx_bytes + len > vvs->buf_alloc.
>> >
>> >virtio_transport_recv_enqueue() skips coalescing for packets
>> >with VIRTIO_VSOCK_SEQ_EOM.
>> >
>> >If fed with packets with len == 0 and VIRTIO_VSOCK_SEQ_EOM,
>> >a very large number of packets can be queued
>> >because vvs->rx_bytes stays at 0.
>> >
>> >Fix this by estimating the skb metadata size:
>> >
>> > (Number of skbs in the queue) * SKB_TRUESIZE(0)
>> >
>> >Fixes: 077706165717 ("virtio/vsock: don't use skbuff state to account credit")
>> >Signed-off-by: Eric Dumazet <edumazet@google.com>
>> >Cc: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
>> >Cc: Stefan Hajnoczi <stefanha@redhat.com>
>> >Cc: Stefano Garzarella <sgarzare@redhat.com>
>> >Cc: "Michael S. Tsirkin" <mst@redhat.com>
>> >Cc: Jason Wang <jasowang@redhat.com>
>> >Cc: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
>> >Cc: "Eugenio Pérez" <eperezma@redhat.com>
>> >Cc: kvm@vger.kernel.org
>> >Cc: virtualization@lists.linux.dev
>> >---
>> > net/vmw_vsock/virtio_transport_common.c | 4 +++-
>> > 1 file changed, 3 insertions(+), 1 deletion(-)
>> >
>> >diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
>> >index 416d533f493d7b07e9c77c43f741d28cfcd0953e..9b8014516f4fb1130ae184635fbba4dfee58bd64 100644
>> >--- a/net/vmw_vsock/virtio_transport_common.c
>> >+++ b/net/vmw_vsock/virtio_transport_common.c
>> >@@ -447,7 +447,9 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
>> > static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs,
>> > u32 len)
>> > {
>> >- if (vvs->buf_used + len > vvs->buf_alloc)
>> >+ u64 skb_overhead = (skb_queue_len(&vvs->rx_queue) + 1) * SKB_TRUESIZE(0);
>> >+
>> >+ if (skb_overhead + vvs->buf_used + len > vvs->buf_alloc)
>> > return false;
>>
>> I'm not sure about this fix, I mean that maybe this is incomplete.
>> In virtio-vsock, there is a credit mechanism between the two peers:
>> https://docs.oasis-open.org/virtio/virtio/v1.3/csd01/virtio-v1.3-csd01.html#x1-4850003
>>
>> This takes only the payload into account, so it’s true that this problem
>> exists; however, perhaps we should also inform the other peer of a lower
>> credit balance, otherwise the other peer will believe it has much more
>> credit than it actually does, send a large payload, and then the packet
>> will be discarded and the data lost (there are no retransmissions,
>> etc.).
>
>I dunno, perhaps revert 077706165717 ("virtio/vsock: don't use skbuff
>state to account credit")
>and find a better fix then?
IIRC the same issue was there before the commit fixed by that one
(commit 71dc9ec9ac7d ("virtio/vsock: replace virtio_vsock_pkt with
sk_buff")), so not sure about reverting it TBH.
CCing Arseniy and Bobby.
>
>There is always a discrepancy between skb->len and skb->truesize.
>You will not be able to announce a 1MB window, and accept one milliion
>skb of 1-byte each.
>
>This kind of contract is broken.
>
Yep, I agree, but before we start discarding data (and losing it), IMHO
we should at least inform the other peer that we're out of space.
@Stefan, @Michael, do you think we can do something in the spec to avoid
this issue and in some way take into account also the metadata in the
credit. I mean to avoid the 1-byte packets flooding.
Thanks,
Stefano
^ permalink raw reply
* Re: [PATCH net] vsock/virtio: fix potential unbounded skb queue
From: Bobby Eshleman @ 2026-05-05 16:37 UTC (permalink / raw)
To: Stefano Garzarella
Cc: Eric Dumazet, Arseniy Krasnov, Bobby Eshleman, Stefan Hajnoczi,
Michael S. Tsirkin, David S . Miller, Jakub Kicinski, Paolo Abeni,
Simon Horman, netdev, eric.dumazet, Arseniy Krasnov, Jason Wang,
Xuan Zhuo, Eugenio Pérez, kvm, virtualization
In-Reply-To: <afoF_cHfl6ygcupM@sgarzare-redhat>
On Tue, May 05, 2026 at 06:11:13PM +0200, Stefano Garzarella wrote:
> On Tue, May 05, 2026 at 07:14:36AM -0700, Eric Dumazet wrote:
> > On Tue, May 5, 2026 at 6:52 AM Stefano Garzarella <sgarzare@redhat.com> wrote:
> > >
> > > On Thu, Apr 30, 2026 at 12:26:52PM +0000, Eric Dumazet wrote:
> > > >virtio_transport_inc_rx_pkt() checks vvs->rx_bytes + len > vvs->buf_alloc.
> > > >
> > > >virtio_transport_recv_enqueue() skips coalescing for packets
> > > >with VIRTIO_VSOCK_SEQ_EOM.
> > > >
> > > >If fed with packets with len == 0 and VIRTIO_VSOCK_SEQ_EOM,
> > > >a very large number of packets can be queued
> > > >because vvs->rx_bytes stays at 0.
> > > >
> > > >Fix this by estimating the skb metadata size:
> > > >
> > > > (Number of skbs in the queue) * SKB_TRUESIZE(0)
> > > >
> > > >Fixes: 077706165717 ("virtio/vsock: don't use skbuff state to account credit")
> > > >Signed-off-by: Eric Dumazet <edumazet@google.com>
> > > >Cc: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
> > > >Cc: Stefan Hajnoczi <stefanha@redhat.com>
> > > >Cc: Stefano Garzarella <sgarzare@redhat.com>
> > > >Cc: "Michael S. Tsirkin" <mst@redhat.com>
> > > >Cc: Jason Wang <jasowang@redhat.com>
> > > >Cc: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
> > > >Cc: "Eugenio Pérez" <eperezma@redhat.com>
> > > >Cc: kvm@vger.kernel.org
> > > >Cc: virtualization@lists.linux.dev
> > > >---
> > > > net/vmw_vsock/virtio_transport_common.c | 4 +++-
> > > > 1 file changed, 3 insertions(+), 1 deletion(-)
> > > >
> > > >diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
> > > >index 416d533f493d7b07e9c77c43f741d28cfcd0953e..9b8014516f4fb1130ae184635fbba4dfee58bd64 100644
> > > >--- a/net/vmw_vsock/virtio_transport_common.c
> > > >+++ b/net/vmw_vsock/virtio_transport_common.c
> > > >@@ -447,7 +447,9 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
> > > > static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs,
> > > > u32 len)
> > > > {
> > > >- if (vvs->buf_used + len > vvs->buf_alloc)
> > > >+ u64 skb_overhead = (skb_queue_len(&vvs->rx_queue) + 1) * SKB_TRUESIZE(0);
> > > >+
> > > >+ if (skb_overhead + vvs->buf_used + len > vvs->buf_alloc)
> > > > return false;
> > >
> > > I'm not sure about this fix, I mean that maybe this is incomplete.
> > > In virtio-vsock, there is a credit mechanism between the two peers:
> > > https://docs.oasis-open.org/virtio/virtio/v1.3/csd01/virtio-v1.3-csd01.html#x1-4850003
> > >
> > > This takes only the payload into account, so it’s true that this problem
> > > exists; however, perhaps we should also inform the other peer of a lower
> > > credit balance, otherwise the other peer will believe it has much more
> > > credit than it actually does, send a large payload, and then the packet
> > > will be discarded and the data lost (there are no retransmissions,
> > > etc.).
> >
> > I dunno, perhaps revert 077706165717 ("virtio/vsock: don't use skbuff
> > state to account credit")
> > and find a better fix then?
>
> IIRC the same issue was there before the commit fixed by that one (commit
> 71dc9ec9ac7d ("virtio/vsock: replace virtio_vsock_pkt with sk_buff")), so
> not sure about reverting it TBH.
>
> CCing Arseniy and Bobby.
>
> >
> > There is always a discrepancy between skb->len and skb->truesize.
> > You will not be able to announce a 1MB window, and accept one milliion
> > skb of 1-byte each.
> >
> > This kind of contract is broken.
> >
>
> Yep, I agree, but before we start discarding data (and losing it), IMHO we
> should at least inform the other peer that we're out of space.
>
> @Stefan, @Michael, do you think we can do something in the spec to avoid
> this issue and in some way take into account also the metadata in the
> credit. I mean to avoid the 1-byte packets flooding.
>
> Thanks,
> Stefano
>
>
Indeed the old pre-fix skb code would have the same issue.
I can't think of any way around this without extending the spec.
Best,
Bobby
^ permalink raw reply
* Re: [PATCH v3 1/3] vfio/pci: Set up bar resources and maps in vfio_pci_core_enable()
From: Matt Evans @ 2026-05-05 16:40 UTC (permalink / raw)
To: Alex Williamson
Cc: Kevin Tian, Jason Gunthorpe, Ankit Agrawal, Alistair Popple,
Leon Romanovsky, Kees Cook, Shameer Kolothum, Yishai Hadas,
Alexey Kardashevskiy, Eric Auger, Peter Xu, Vivek Kasireddy,
Zhi Wang, kvm, linux-kernel, virtualization
In-Reply-To: <20260430141341.163ed827@shazbot.org>
Hi Alex,
On 30/04/2026 21:13, Alex Williamson wrote:
>
> On Thu, 30 Apr 2026 03:03:20 -0700
> Matt Evans <mattev@meta.com> wrote:
>
>> Previously BAR resource requests and the corresponding pci_iomap()
>> were performed on-demand and without synchronisation, which was racy.
>> Rather than add synchronisation, it's simplest to address this by
>> doing both activities from vfio_pci_core_enable().
>>
>> The resource allocation and/or pci_iomap() can still fail; their
>> status is tracked and existing calls to vfio_pci_core_setup_barmap()
>> will fail in a similar way to before. This keeps the point of failure
>> as observed by userspace the same, i.e. failures to request/map unused
>> BARs are benign.
>>
>> Fixes: 7f5764e179c6 ("vfio: use vfio_pci_core_setup_barmap to map bar in mmap")
>> Fixes: 0d77ed3589ac0 ("vfio/pci: Pull BAR mapping setup from read-write path")
>
> Neither of these introduced races, they only moved what they were
> already doing into a function or made use of that shared function for
> what they were already doing. I'm inclined to believe the raciness
> existed from the introduction, 89e1f7d4c66d.
>
>> Signed-off-by: Matt Evans <mattev@meta.com>
>> ---
>> drivers/vfio/pci/vfio_pci_core.c | 33 ++++++++++++++++++++++++++++++++
>> drivers/vfio/pci/vfio_pci_rdwr.c | 29 ++++++++++++----------------
>> 2 files changed, 45 insertions(+), 17 deletions(-)
>>
>> diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
>> index 3f8d093aacf8..eab4f2626b39 100644
>> --- a/drivers/vfio/pci/vfio_pci_core.c
>> +++ b/drivers/vfio/pci/vfio_pci_core.c
>> @@ -482,6 +482,38 @@ static int vfio_pci_core_runtime_resume(struct device *dev)
>> }
>> #endif /* CONFIG_PM */
>>
>> +static void vfio_pci_core_map_bars(struct vfio_pci_core_device *vdev)
>> +{
>> + struct pci_dev *pdev = vdev->pdev;
>> + int i;
>> +
>> + /*
>> + * Eager-request BAR resources, and iomap. Soft failures are
>> + * allowed, and consumers must check the barmap before use in
>> + * order to give compatible user-visible behaviour with the
>> + * previous on-demand allocation method.
>> + */
>> + for (i = 0; i < PCI_STD_NUM_BARS; i++) {
>> + int bar = i + PCI_STD_RESOURCES;
>> + void __iomem *io = ERR_PTR(-ENODEV);
>
> It would collapse the nesting depth to just do:
>
> vdev->barmap[bar] = ERR_PTR(-ENODEV);
>
> if (!pci_resource_len(pdev, i))
> continue;
>
> if (pci_request_selected_regions(pdev, 1 << bar, "vfio")) {
> pci_dbg(vdev->pdev, "Failed to reserve region %d\n", bar);
> vdev->barmap[bar] = ERR_PTR(-EBUSY);
> continue;
> }
>
> vdev->barmap[bar] = pci_iomap(pdev, bar, 0);
> if (!vdev->barmap[bar]) {
> pci_dbg(vdev->pdev, "Failed to iomap region %d\n", bar);
> vdev->barmap[bar] = ERR_PTR(-ENOMEM);
> }
>
> It's debatable what level to use for the errors, but we were previously
> silent on this, so going all the way to pci_warn() seems unnecessary.
Hm, okay, returned it to a nesting-less format and replaced pci_warn()s
with pci_dbg().
>> +
>> + if (pci_resource_len(pdev, i) > 0) {
>> + if (pci_request_selected_regions(pdev, 1 << bar, "vfio")) {
>> + pci_warn(vdev->pdev, "Failed to reserve region %d\n", bar);
>> + io = ERR_PTR(-EBUSY);
>> + } else {
>> + io = pci_iomap(pdev, bar, 0);
>> + if (!io) {
>> + pci_warn(vdev->pdev, "Failed to iomap region %d\n",
>> + bar);
>> + io = ERR_PTR(-ENOMEM);
>> + }
>> + }
>> + }
>> + vdev->barmap[bar] = io;
>> + }
>> +}
>> +
>> /*
>> * The pci-driver core runtime PM routines always save the device state
>> * before going into suspended state. If the device is going into low power
>> @@ -568,6 +600,7 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev)
>> if (!vfio_vga_disabled() && vfio_pci_is_vga(pdev))
>> vdev->has_vga = true;
>>
>> + vfio_pci_core_map_bars(vdev);
>>
>> return 0;
>
> You're missing the barmap test in vfio_pci_core_disable() now, it's
> still testing for NULL, which is (almost?) never true. It needs to
> convert to IS_ERR_OR_NULL().
Arrrrgh, yes it does, thank you. (For the second time, the first being
the !IS_ERR() typo you caught in patch #3 :( Thanks there also; it
slipped by my usual testing routine.)
>> diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c
>> index 4251ee03e146..f66ad3d96481 100644
>> --- a/drivers/vfio/pci/vfio_pci_rdwr.c
>> +++ b/drivers/vfio/pci/vfio_pci_rdwr.c
>> @@ -200,25 +200,20 @@ EXPORT_SYMBOL_GPL(vfio_pci_core_do_io_rw);
>>
>> int vfio_pci_core_setup_barmap(struct vfio_pci_core_device *vdev, int bar)
>> {
>> - struct pci_dev *pdev = vdev->pdev;
>> - int ret;
>> - void __iomem *io;
>> -
>> - if (vdev->barmap[bar])
>> - return 0;
>> -
>> - ret = pci_request_selected_regions(pdev, 1 << bar, "vfio");
>> - if (ret)
>> - return ret;
>> -
>> - io = pci_iomap(pdev, bar, 0);
>> - if (!io) {
>> - pci_release_selected_regions(pdev, 1 << bar);
>> - return -ENOMEM;
>> - }
>> + /*
>> + * The barmap is set up in vfio_pci_core_enable(). Callers
>> + * use this function to check that the BAR resources are
>> + * requested or that the pci_iomap() was done.
>> + */
>
> Looks like a function level comment to be placed above the function
> definition. TBH, the comment in the previous function could also be
> pulled up as a function level comment.
>
>> + if (bar < 0 || bar >= PCI_STD_NUM_BARS)
>
> Maybe `if ((unsigned)bar >= PCI_STD_NUM_BARS)` but really author
> preference here.
>
>> + return -EINVAL;
>>
>> - vdev->barmap[bar] = io;
>> + /* Did vfio_pci_core_map_bars() set it up yet? */
>> + if (!vdev->barmap[bar])
>> + return -ENODEV;
>
> What hits this? Should it be a WARN_ON_ONCE? It would need to be a use
> case that accesses barmap outside of the window between enable and
> disable, where I think we're defining the contract that it's only valid
> between those events. Both this and the range check could move to the
> iomap implemenation to keep the Fixes: patch reasonably small since
> afaik they're not triggered. The BAR range test could be WARN_ON_ONCE
> as well, only driver bugs should hit it. Thanks,
I've reduced the fix patch #1 to just an IS_ERR test (without the null
or range checks as you suggest). And indeed WARN_ON_ONCE() is a good
idea as only tremendous mishaps would lead to these conditions
triggering (worth testing though).
Also ack on your suggestion on patch #2 to make the call to
nvgrace_gpu_wait_device_ready() more minimalist, and to order the 2x
fixes up front. Posting v4 shortly, cheers!
Thanks,
Matt
^ permalink raw reply
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