On Mon, Sep 6, 2021 at 4:01 PM Michael S. Tsirkin <mst@xxxxxxxxxx> wrote: > > On Mon, Sep 06, 2021 at 03:06:44PM +0800, Yongji Xie wrote: > > On Mon, Sep 6, 2021 at 2:37 PM Michael S. Tsirkin <mst@xxxxxxxxxx> wrote: > > > > > > On Mon, Sep 06, 2021 at 02:09:25PM +0800, Yongji Xie wrote: > > > > On Mon, Sep 6, 2021 at 1:56 PM Michael S. Tsirkin <mst@xxxxxxxxxx> wrote: > > > > > > > > > > On Tue, Aug 31, 2021 at 06:36:26PM +0800, Xie Yongji wrote: > > > > > > This adds a new callback to support device specific reset > > > > > > behavior. The vdpa bus driver will call the reset function > > > > > > instead of setting status to zero during resetting. > > > > > > > > > > > > Signed-off-by: Xie Yongji <xieyongji@xxxxxxxxxxxxx> > > > > > > > > > > > > > > > This does gloss over a significant change though: > > > > > > > > > > > > > > > > --- > > > > > > @@ -348,12 +352,12 @@ static inline struct device *vdpa_get_dma_dev(struct vdpa_device *vdev) > > > > > > return vdev->dma_dev; > > > > > > } > > > > > > > > > > > > -static inline void vdpa_reset(struct vdpa_device *vdev) > > > > > > +static inline int vdpa_reset(struct vdpa_device *vdev) > > > > > > { > > > > > > const struct vdpa_config_ops *ops = vdev->config; > > > > > > > > > > > > vdev->features_valid = false; > > > > > > - ops->set_status(vdev, 0); > > > > > > + return ops->reset(vdev); > > > > > > } > > > > > > > > > > > > static inline int vdpa_set_features(struct vdpa_device *vdev, u64 features) > > > > > > > > > > > > > > > Unfortunately this breaks virtio_vdpa: > > > > > > > > > > > > > > > static void virtio_vdpa_reset(struct virtio_device *vdev) > > > > > { > > > > > struct vdpa_device *vdpa = vd_get_vdpa(vdev); > > > > > > > > > > vdpa_reset(vdpa); > > > > > } > > > > > > > > > > > > > > > and there's no easy way to fix this, kernel can't recover > > > > > from a reset failure e.g. during driver unbind. > > > > > > > > > > > > > Yes, but it should be safe with the protection of software IOTLB even > > > > if the reset() fails during driver unbind. > > > > > > > > Thanks, > > > > Yongji > > > > > > Hmm. I don't see it. > > > What exactly will happen? What prevents device from poking at > > > memory after reset? Note that dma unmap in e.g. del_vqs happens > > > too late. > > > > But I didn't see any problems with touching the memory for virtqueues. > > Drivers make the assumption that after reset returns no new > buffers will be consumed. For example a bunch of drivers > call virtqueue_detach_unused_buf. I'm not sure if I get your point. But it looks like virtqueue_detach_unused_buf() will check the driver's metadata first rather than read the memory from virtqueue. > I can't say whether block makes this assumption anywhere. > Needs careful auditing. > > > The memory should not be freed after dma unmap? > > But unmap does not happen until after the reset. > I mean the memory is totally allocated and controlled by the VDUSE driver. The VDUSE driver will not return them to the buddy system unless userspace unmap it. > > > And the memory for the bounce buffer should also be safe to be > > accessed by userspace in this case. > > > > > And what about e.g. interrupts? > > > E.g. we have this: > > > > > > /* Virtqueues are stopped, nothing can use vblk->vdev anymore. */ > > > vblk->vdev = NULL; > > > > > > and this is no longer true at this point. > > > > > > > You're right. But I didn't see where the interrupt handler will use > > the vblk->vdev. > > static void virtblk_done(struct virtqueue *vq) > { > struct virtio_blk *vblk = vq->vdev->priv; > > vq->vdev is the same as vblk->vdev. > We will test the vq->ready (will be set to false in del_vqs()) before injecting an interrupt in the VDUSE driver. So it should be OK? > > > So it seems to be not too late to fix it: > > > > diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c > > b/drivers/vdpa/vdpa_user/vduse_dev.c > > index 5c25ff6483ad..ea41a7389a26 100644 > > --- a/drivers/vdpa/vdpa_user/vduse_dev.c > > +++ b/drivers/vdpa/vdpa_user/vduse_dev.c > > @@ -665,13 +665,13 @@ static void vduse_vdpa_set_config(struct > > vdpa_device *vdpa, unsigned int offset, > > static int vduse_vdpa_reset(struct vdpa_device *vdpa) > > { > > struct vduse_dev *dev = vdpa_to_vduse(vdpa); > > + int ret; > > > > - if (vduse_dev_set_status(dev, 0)) > > - return -EIO; > > + ret = vduse_dev_set_status(dev, 0); > > > > vduse_dev_reset(dev); > > > > - return 0; > > + return ret; > > } > > > > static u32 vduse_vdpa_get_generation(struct vdpa_device *vdpa) > > > > Thanks, > > Yongji > > Needs some comments to explain why it's done like this. > This is used to make sure the userspace can't not inject the interrupt any more after reset. The vduse_dev_reset() will clear the interrupt callback and flush the irq kworker. > BTW device is generally wedged at this point right? > E.g. if reset during initialization fails, userspace > will still get the reset at some later point and be > confused ... > Sorry, I don't get why userspace will get the reset at some later point? Thanks, Yongji