vhost: create worker at end of vhost_dev_set_owner
authorMike Christie <michael.christie@oracle.com>
Mon, 26 Jun 2023 23:22:51 +0000 (18:22 -0500)
committerMichael S. Tsirkin <mst@redhat.com>
Mon, 3 Jul 2023 16:15:13 +0000 (12:15 -0400)
vsock can start queueing work after VHOST_VSOCK_SET_GUEST_CID, so
after we have called vhost_worker_create it can be calling
vhost_work_queue and trying to access the vhost worker/task. If
vhost_dev_alloc_iovecs fails, then vhost_worker_free could free
the worker/task from under vsock.

This moves vhost_worker_create to the end of vhost_dev_set_owner
where we know we can no longer fail in that path. If it fails
after the VHOST_SET_OWNER and userspace closes the device, then
the normal vsock release handling will do the right thing.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
Message-Id: <20230626232307.97930-2-michael.christie@oracle.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
drivers/vhost/vhost.c

index 60c9ebd629dd159d0ceb8a0c14f96091be193753..82966ffb4a5c255e6663ef3da2fa88ad2545ce37 100644 (file)
@@ -572,20 +572,27 @@ long vhost_dev_set_owner(struct vhost_dev *dev)
 
        vhost_attach_mm(dev);
 
+       err = vhost_dev_alloc_iovecs(dev);
+       if (err)
+               goto err_iovecs;
+
        if (dev->use_worker) {
+               /*
+                * This should be done last, because vsock can queue work
+                * before VHOST_SET_OWNER so it simplifies the failure path
+                * below since we don't have to worry about vsock queueing
+                * while we free the worker.
+                */
                err = vhost_worker_create(dev);
                if (err)
                        goto err_worker;
        }
 
-       err = vhost_dev_alloc_iovecs(dev);
-       if (err)
-               goto err_iovecs;
-
        return 0;
-err_iovecs:
-       vhost_worker_free(dev);
+
 err_worker:
+       vhost_dev_free_iovecs(dev);
+err_iovecs:
        vhost_detach_mm(dev);
 err_mm:
        return err;