vhost: create worker at end of vhost_dev_set_owner

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>
This commit is contained in:
Mike Christie 2023-06-26 18:22:51 -05:00 коммит произвёл Michael S. Tsirkin
Родитель 3845308fc8
Коммит 3e11c6eb6a
1 изменённых файлов: 13 добавлений и 6 удалений

Просмотреть файл

@ -572,20 +572,27 @@ long vhost_dev_set_owner(struct vhost_dev *dev)
vhost_attach_mm(dev); vhost_attach_mm(dev);
err = vhost_dev_alloc_iovecs(dev);
if (err)
goto err_iovecs;
if (dev->use_worker) { 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); err = vhost_worker_create(dev);
if (err) if (err)
goto err_worker; goto err_worker;
} }
err = vhost_dev_alloc_iovecs(dev);
if (err)
goto err_iovecs;
return 0; return 0;
err_iovecs:
vhost_worker_free(dev);
err_worker: err_worker:
vhost_dev_free_iovecs(dev);
err_iovecs:
vhost_detach_mm(dev); vhost_detach_mm(dev);
err_mm: err_mm:
return err; return err;