Commit e08a9fac authored by Kohei Enju's avatar Kohei Enju Committed by Jakub Kicinski
Browse files

vhost_net: fix sleeping with preempt-disabled in vhost_net_busy_poll()

syzbot reported "sleeping function called from invalid context" in
vhost_net_busy_poll().

Commit 03088137 ("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: 03088137 ("vhost_net: basic polling support")
Tested-by: default avatar <syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com>
Reported-by: default avatar <syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com>
Closes: https://lore.kernel.org/all/69e6a414.050a0220.24bfd3.002d.GAE@google.com/T/


Signed-off-by: default avatarKohei Enju <kohei@enjuk.jp>
Acked-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 076b8cad
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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);