aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/virtio
diff options
context:
space:
mode:
authorDavid Hildenbrand <david@redhat.com>2021-08-25 12:24:15 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2021-08-27 11:39:36 -0700
commit425bec0032f59eeee12520085cd054fac09cc66e (patch)
tree25477a10d8312d0c89b9ab2779c4821c8c7d56b5 /drivers/virtio
parentMerge tag 'riscv-for-linus-5.14-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux (diff)
downloadlinux-dev-425bec0032f59eeee12520085cd054fac09cc66e.tar.xz
linux-dev-425bec0032f59eeee12520085cd054fac09cc66e.zip
virtio-mem: fix sleeping in RCU read side section in virtio_mem_online_page_cb()
virtio_mem_set_fake_offline() might sleep now, and we call it under rcu_read_lock(). To fix it, simply move the rcu_read_unlock() further up, as we're done with the device. Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Fixes: 6cc26d77613a: "virtio-mem: use page_offline_(start|end) when setting PageOffline() Cc: "Michael S. Tsirkin" <mst@redhat.com> Cc: Jason Wang <jasowang@redhat.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: virtualization@lists.linux-foundation.org Signed-off-by: David Hildenbrand <david@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/virtio')
-rw-r--r--drivers/virtio/virtio_mem.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c
index 09ed55de07d7..b91bc810a87e 100644
--- a/drivers/virtio/virtio_mem.c
+++ b/drivers/virtio/virtio_mem.c
@@ -1242,12 +1242,19 @@ static void virtio_mem_online_page_cb(struct page *page, unsigned int order)
do_online = virtio_mem_bbm_get_bb_state(vm, id) !=
VIRTIO_MEM_BBM_BB_FAKE_OFFLINE;
}
+
+ /*
+ * virtio_mem_set_fake_offline() might sleep, we don't need
+ * the device anymore. See virtio_mem_remove() how races
+ * between memory onlining and device removal are handled.
+ */
+ rcu_read_unlock();
+
if (do_online)
generic_online_page(page, order);
else
virtio_mem_set_fake_offline(PFN_DOWN(addr), 1 << order,
false);
- rcu_read_unlock();
return;
}
rcu_read_unlock();