]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
vhost_net: fix sleeping with preempt-disabled in vhost_net_busy_poll()
authorKohei Enju <kohei@enjuk.jp>
Wed, 22 Apr 2026 02:30:24 +0000 (02:30 +0000)
committerJakub Kicinski <kuba@kernel.org>
Thu, 23 Apr 2026 18:53:31 +0000 (11:53 -0700)
syzbot reported "sleeping function called from invalid context" in
vhost_net_busy_poll().

Commit 030881372460 ("vhost_net: basic polling support") introduced a
busy-poll loop and preempt_{disable,enable}() around it, where each
iteration calls a sleepable function inside the loop.

The purpose of disabling preemption was to keep local_clock()-based
timeout accounting on a single CPU, rather than as a requirement of
busy-poll itself:

https://lore.kernel.org/1448435489-5949-4-git-send-email-jasowang@redhat.com

From this perspective, migrate_disable() is sufficient here, so replace
preempt_disable() with migrate_disable(), avoiding sleepable accesses
from a preempt-disabled context.

Fixes: 030881372460 ("vhost_net: basic polling support")
Tested-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com
Reported-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/all/69e6a414.050a0220.24bfd3.002d.GAE@google.com/T/
Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/vhost/net.c

index 80965181920c363da044c1115a347e6150cf56de..c6536cad9c4f94f6ad38f116363c9f1949cf373d 100644 (file)
@@ -560,7 +560,7 @@ static void vhost_net_busy_poll(struct vhost_net *net,
        busyloop_timeout = poll_rx ? rvq->busyloop_timeout:
                                     tvq->busyloop_timeout;
 
-       preempt_disable();
+       migrate_disable();
        endtime = busy_clock() + busyloop_timeout;
 
        while (vhost_can_busy_poll(endtime)) {
@@ -577,7 +577,7 @@ static void vhost_net_busy_poll(struct vhost_net *net,
                cpu_relax();
        }
 
-       preempt_enable();
+       migrate_enable();
 
        if (poll_rx || sock_has_rx_data(sock))
                vhost_net_busy_poll_try_queue(net, vq);