vdpasim_create() unwinds early allocation failures with put_device(), which invokes the vdpa free callback even when the worker, virtqueues or IOTLB arrays have not all been initialized. vdpasim_free() currently assumes the fully initialized path and can dereference NULL or ERR_PTR state during those failures.
Make the free callback tolerate partially initialized simulator devices before destroying the worker or walking optional arrays. Signed-off-by: Xiong Weimin <[email protected]> --- drivers/vdpa/vdpa_sim/vdpa_sim.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c index 8cb1cc2ea..77966e957 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c @@ -743,17 +743,22 @@ static void vdpasim_free(struct vdpa_device *vdpa) int i; kthread_cancel_work_sync(&vdpasim->work); - kthread_destroy_worker(vdpasim->worker); + if (!IS_ERR_OR_NULL(vdpasim->worker)) + kthread_destroy_worker(vdpasim->worker); - for (i = 0; i < vdpasim->dev_attr.nvqs; i++) { - vringh_kiov_cleanup(&vdpasim->vqs[i].out_iov); - vringh_kiov_cleanup(&vdpasim->vqs[i].in_iov); + if (vdpasim->vqs) { + for (i = 0; i < vdpasim->dev_attr.nvqs; i++) { + vringh_kiov_cleanup(&vdpasim->vqs[i].out_iov); + vringh_kiov_cleanup(&vdpasim->vqs[i].in_iov); + } } vdpasim->dev_attr.free(vdpasim); - for (i = 0; i < vdpasim->dev_attr.nas; i++) - vhost_iotlb_reset(&vdpasim->iommu[i]); + if (vdpasim->iommu) { + for (i = 0; i < vdpasim->dev_attr.nas; i++) + vhost_iotlb_reset(&vdpasim->iommu[i]); + } kfree(vdpasim->iommu); kfree(vdpasim->iommu_pt); kfree(vdpasim->vqs); -- 2.43.0

