Message ID | 20230602141125.448833-3-akrowiak@linux.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | s390x/ap: fix hang when mdev attached to guest is removed | expand |
Hello Tony, On 6/2/23 16:11, Tony Krowiak wrote: > Let's wire up the device request notifier interface to handle device unplug > requests for AP. > > Signed-off-by: Tony Krowiak <akrowiak@linux.ibm.com> > Link: https://lore.kernel.org/qemu-devel/20230530225544.280031-1-akrowiak@linux.ibm.com/ > --- > hw/vfio/ap.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 113 insertions(+) > > diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c > index e0dd561e85a3..6e21d1da5a70 100644 > --- a/hw/vfio/ap.c > +++ b/hw/vfio/ap.c > @@ -18,6 +18,8 @@ > #include "hw/vfio/vfio-common.h" > #include "hw/s390x/ap-device.h" > #include "qemu/error-report.h" > +#include "qemu/event_notifier.h" > +#include "qemu/main-loop.h" > #include "qemu/module.h" > #include "qemu/option.h" > #include "qemu/config-file.h" > @@ -33,6 +35,7 @@ > struct VFIOAPDevice { > APDevice apdev; > VFIODevice vdev; > + EventNotifier req_notifier; > }; > > OBJECT_DECLARE_SIMPLE_TYPE(VFIOAPDevice, VFIO_AP_DEVICE) > @@ -84,10 +87,110 @@ static VFIOGroup *vfio_ap_get_group(VFIOAPDevice *vapdev, Error **errp) > return vfio_get_group(groupid, &address_space_memory, errp); > } > > +static void vfio_ap_req_notifier_handler(void *opaque) > +{ > + VFIOAPDevice *vapdev = opaque; > + Error *err = NULL; > + > + if (!event_notifier_test_and_clear(&vapdev->req_notifier)) { > + return; > + } > + > + qdev_unplug(DEVICE(vapdev), &err); > + > + if (err) { > + warn_reportf_err(err, VFIO_MSG_PREFIX, vapdev->vdev.name); > + } > +} > + > +static void vfio_ap_register_irq_notifier(VFIOAPDevice *vapdev, > + unsigned int irq, Error **errp) > +{ > + int fd; > + size_t argsz; > + IOHandler *fd_read; > + EventNotifier *notifier; > + struct vfio_irq_info *irq_info; > + VFIODevice *vdev = &vapdev->vdev; > + > + switch (irq) { Do you have plan for more interrupts ? If not, you could convert the 'switch' statement to a simple 'if' and remove the fd_read variable. > + case VFIO_AP_REQ_IRQ_INDEX: > + notifier = &vapdev->req_notifier; > + fd_read = vfio_ap_req_notifier_handler; > + break; > + default: > + error_setg(errp, "vfio: Unsupported device irq(%d)", irq); > + return; > + } > + > + if (vdev->num_irqs < irq + 1) { > + error_setg(errp, "vfio: IRQ %u not available (number of irqs %u)", > + irq, vdev->num_irqs); > + return; > + } > + > + argsz = sizeof(*irq_info); > + irq_info = g_malloc0(argsz); > + irq_info->index = irq; > + irq_info->argsz = argsz; > + > + if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, > + irq_info) < 0 || irq_info->count < 1) { > + error_setg_errno(errp, errno, "vfio: Error getting irq info"); > + goto out_free_info; > + } > + > + if (event_notifier_init(notifier, 0)) { > + error_setg_errno(errp, errno, > + "vfio: Unable to init event notifier for irq (%d)", > + irq); > + goto out_free_info; > + } > + > + fd = event_notifier_get_fd(notifier); > + qemu_set_fd_handler(fd, fd_read, NULL, vapdev); > + > + if (vfio_set_irq_signaling(vdev, irq, 0, VFIO_IRQ_SET_ACTION_TRIGGER, fd, > + errp)) { > + qemu_set_fd_handler(fd, NULL, NULL, vapdev); > + event_notifier_cleanup(notifier); > + } > + > +out_free_info: > + g_free(irq_info); > + > +} > + > +static void vfio_ap_unregister_irq_notifier(VFIOAPDevice *vapdev, > + unsigned int irq) > +{ > + Error *err = NULL; > + EventNotifier *notifier; > + > + switch (irq) { > + case VFIO_AP_REQ_IRQ_INDEX: > + notifier = &vapdev->req_notifier; > + break; > + default: > + error_report("vfio: Unsupported device irq(%d)", irq); > + return; > + } > + > + if (vfio_set_irq_signaling(&vapdev->vdev, irq, 0, > + VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { > + warn_reportf_err(err, VFIO_MSG_PREFIX, vapdev->vdev.name); > + } > + > + qemu_set_fd_handler(event_notifier_get_fd(notifier), > + NULL, NULL, vapdev); > + event_notifier_cleanup(notifier); > +} > + > static void vfio_ap_realize(DeviceState *dev, Error **errp) > { > int ret; > char *mdevid; > + Error *err = NULL; > VFIOGroup *vfio_group; > APDevice *apdev = AP_DEVICE(dev); > VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); > @@ -116,6 +219,15 @@ static void vfio_ap_realize(DeviceState *dev, Error **errp) > goto out_get_dev_err; > } > > + vfio_ap_register_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX, &err); > + if (err) { > + /* > + * Report this error, but do not make it a failing condition. > + * Lack of this IRQ in the host does not prevent normal operation. > + */ > + error_report_err(err); May be issue a warning instead ? Thanks, C. > + } > + > return; > > out_get_dev_err: > @@ -129,6 +241,7 @@ static void vfio_ap_unrealize(DeviceState *dev) > VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); > VFIOGroup *group = vapdev->vdev.group; > > + vfio_ap_unregister_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX); > vfio_ap_put_device(vapdev); > vfio_put_group(group); > }
On 6/2/23 10:28 AM, Cédric Le Goater wrote: > Hello Tony, > > On 6/2/23 16:11, Tony Krowiak wrote: >> Let's wire up the device request notifier interface to handle device >> unplug >> requests for AP. >> >> Signed-off-by: Tony Krowiak <akrowiak@linux.ibm.com> >> Link: >> https://lore.kernel.org/qemu-devel/20230530225544.280031-1-akrowiak@linux.ibm.com/ >> --- >> hw/vfio/ap.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 113 insertions(+) >> >> diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c >> index e0dd561e85a3..6e21d1da5a70 100644 >> --- a/hw/vfio/ap.c >> +++ b/hw/vfio/ap.c >> @@ -18,6 +18,8 @@ >> #include "hw/vfio/vfio-common.h" >> #include "hw/s390x/ap-device.h" >> #include "qemu/error-report.h" >> +#include "qemu/event_notifier.h" >> +#include "qemu/main-loop.h" >> #include "qemu/module.h" >> #include "qemu/option.h" >> #include "qemu/config-file.h" >> @@ -33,6 +35,7 @@ >> struct VFIOAPDevice { >> APDevice apdev; >> VFIODevice vdev; >> + EventNotifier req_notifier; >> }; >> OBJECT_DECLARE_SIMPLE_TYPE(VFIOAPDevice, VFIO_AP_DEVICE) >> @@ -84,10 +87,110 @@ static VFIOGroup *vfio_ap_get_group(VFIOAPDevice >> *vapdev, Error **errp) >> return vfio_get_group(groupid, &address_space_memory, errp); >> } >> +static void vfio_ap_req_notifier_handler(void *opaque) >> +{ >> + VFIOAPDevice *vapdev = opaque; >> + Error *err = NULL; >> + >> + if (!event_notifier_test_and_clear(&vapdev->req_notifier)) { >> + return; >> + } >> + >> + qdev_unplug(DEVICE(vapdev), &err); >> + >> + if (err) { >> + warn_reportf_err(err, VFIO_MSG_PREFIX, vapdev->vdev.name); >> + } >> +} >> + >> +static void vfio_ap_register_irq_notifier(VFIOAPDevice *vapdev, >> + unsigned int irq, Error >> **errp) >> +{ >> + int fd; >> + size_t argsz; >> + IOHandler *fd_read; >> + EventNotifier *notifier; >> + struct vfio_irq_info *irq_info; >> + VFIODevice *vdev = &vapdev->vdev; >> + >> + switch (irq) { > > Do you have plan for more interrupts ? If not, you could convert the > 'switch' statement to a simple 'if' and remove the fd_read variable. At this time there are no plans for further interrupts, but the switch does make it easy to add them:) On the other hand, I have no problem changing this to an 'if' statement. The fd_read variable is used below in the call to the qemu_set_fd_handler() function, so I can't get rid of it. > >> + case VFIO_AP_REQ_IRQ_INDEX: >> + notifier = &vapdev->req_notifier; >> + fd_read = vfio_ap_req_notifier_handler; >> + break; >> + default: >> + error_setg(errp, "vfio: Unsupported device irq(%d)", irq); >> + return; >> + } >> + >> + if (vdev->num_irqs < irq + 1) { >> + error_setg(errp, "vfio: IRQ %u not available (number of irqs >> %u)", >> + irq, vdev->num_irqs); >> + return; >> + } >> + >> + argsz = sizeof(*irq_info); >> + irq_info = g_malloc0(argsz); >> + irq_info->index = irq; >> + irq_info->argsz = argsz; >> + >> + if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, >> + irq_info) < 0 || irq_info->count < 1) { >> + error_setg_errno(errp, errno, "vfio: Error getting irq info"); >> + goto out_free_info; >> + } >> + >> + if (event_notifier_init(notifier, 0)) { >> + error_setg_errno(errp, errno, >> + "vfio: Unable to init event notifier for irq >> (%d)", >> + irq); >> + goto out_free_info; >> + } >> + >> + fd = event_notifier_get_fd(notifier); >> + qemu_set_fd_handler(fd, fd_read, NULL, vapdev); >> + >> + if (vfio_set_irq_signaling(vdev, irq, 0, >> VFIO_IRQ_SET_ACTION_TRIGGER, fd, >> + errp)) { >> + qemu_set_fd_handler(fd, NULL, NULL, vapdev); >> + event_notifier_cleanup(notifier); >> + } >> + >> +out_free_info: >> + g_free(irq_info); >> + >> +} >> + >> +static void vfio_ap_unregister_irq_notifier(VFIOAPDevice *vapdev, >> + unsigned int irq) >> +{ >> + Error *err = NULL; >> + EventNotifier *notifier; >> + >> + switch (irq) { >> + case VFIO_AP_REQ_IRQ_INDEX: >> + notifier = &vapdev->req_notifier; >> + break; >> + default: >> + error_report("vfio: Unsupported device irq(%d)", irq); >> + return; >> + } >> + >> + if (vfio_set_irq_signaling(&vapdev->vdev, irq, 0, >> + VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { >> + warn_reportf_err(err, VFIO_MSG_PREFIX, vapdev->vdev.name); >> + } >> + >> + qemu_set_fd_handler(event_notifier_get_fd(notifier), >> + NULL, NULL, vapdev); >> + event_notifier_cleanup(notifier); >> +} >> + >> static void vfio_ap_realize(DeviceState *dev, Error **errp) >> { >> int ret; >> char *mdevid; >> + Error *err = NULL; >> VFIOGroup *vfio_group; >> APDevice *apdev = AP_DEVICE(dev); >> VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); >> @@ -116,6 +219,15 @@ static void vfio_ap_realize(DeviceState *dev, >> Error **errp) >> goto out_get_dev_err; >> } >> + vfio_ap_register_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX, &err); >> + if (err) { >> + /* >> + * Report this error, but do not make it a failing condition. >> + * Lack of this IRQ in the host does not prevent normal >> operation. >> + */ >> + error_report_err(err); > > May be issue a warning instead ? Given the comment above - i.e., not a failing condition - it probably makes sense to make it a warning. > > Thanks, > > C. > >> + } >> + >> return; >> out_get_dev_err: >> @@ -129,6 +241,7 @@ static void vfio_ap_unrealize(DeviceState *dev) >> VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); >> VFIOGroup *group = vapdev->vdev.group; >> + vfio_ap_unregister_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX); >> vfio_ap_put_device(vapdev); >> vfio_put_group(group); >> } >
diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c index e0dd561e85a3..6e21d1da5a70 100644 --- a/hw/vfio/ap.c +++ b/hw/vfio/ap.c @@ -18,6 +18,8 @@ #include "hw/vfio/vfio-common.h" #include "hw/s390x/ap-device.h" #include "qemu/error-report.h" +#include "qemu/event_notifier.h" +#include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/option.h" #include "qemu/config-file.h" @@ -33,6 +35,7 @@ struct VFIOAPDevice { APDevice apdev; VFIODevice vdev; + EventNotifier req_notifier; }; OBJECT_DECLARE_SIMPLE_TYPE(VFIOAPDevice, VFIO_AP_DEVICE) @@ -84,10 +87,110 @@ static VFIOGroup *vfio_ap_get_group(VFIOAPDevice *vapdev, Error **errp) return vfio_get_group(groupid, &address_space_memory, errp); } +static void vfio_ap_req_notifier_handler(void *opaque) +{ + VFIOAPDevice *vapdev = opaque; + Error *err = NULL; + + if (!event_notifier_test_and_clear(&vapdev->req_notifier)) { + return; + } + + qdev_unplug(DEVICE(vapdev), &err); + + if (err) { + warn_reportf_err(err, VFIO_MSG_PREFIX, vapdev->vdev.name); + } +} + +static void vfio_ap_register_irq_notifier(VFIOAPDevice *vapdev, + unsigned int irq, Error **errp) +{ + int fd; + size_t argsz; + IOHandler *fd_read; + EventNotifier *notifier; + struct vfio_irq_info *irq_info; + VFIODevice *vdev = &vapdev->vdev; + + switch (irq) { + case VFIO_AP_REQ_IRQ_INDEX: + notifier = &vapdev->req_notifier; + fd_read = vfio_ap_req_notifier_handler; + break; + default: + error_setg(errp, "vfio: Unsupported device irq(%d)", irq); + return; + } + + if (vdev->num_irqs < irq + 1) { + error_setg(errp, "vfio: IRQ %u not available (number of irqs %u)", + irq, vdev->num_irqs); + return; + } + + argsz = sizeof(*irq_info); + irq_info = g_malloc0(argsz); + irq_info->index = irq; + irq_info->argsz = argsz; + + if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, + irq_info) < 0 || irq_info->count < 1) { + error_setg_errno(errp, errno, "vfio: Error getting irq info"); + goto out_free_info; + } + + if (event_notifier_init(notifier, 0)) { + error_setg_errno(errp, errno, + "vfio: Unable to init event notifier for irq (%d)", + irq); + goto out_free_info; + } + + fd = event_notifier_get_fd(notifier); + qemu_set_fd_handler(fd, fd_read, NULL, vapdev); + + if (vfio_set_irq_signaling(vdev, irq, 0, VFIO_IRQ_SET_ACTION_TRIGGER, fd, + errp)) { + qemu_set_fd_handler(fd, NULL, NULL, vapdev); + event_notifier_cleanup(notifier); + } + +out_free_info: + g_free(irq_info); + +} + +static void vfio_ap_unregister_irq_notifier(VFIOAPDevice *vapdev, + unsigned int irq) +{ + Error *err = NULL; + EventNotifier *notifier; + + switch (irq) { + case VFIO_AP_REQ_IRQ_INDEX: + notifier = &vapdev->req_notifier; + break; + default: + error_report("vfio: Unsupported device irq(%d)", irq); + return; + } + + if (vfio_set_irq_signaling(&vapdev->vdev, irq, 0, + VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { + warn_reportf_err(err, VFIO_MSG_PREFIX, vapdev->vdev.name); + } + + qemu_set_fd_handler(event_notifier_get_fd(notifier), + NULL, NULL, vapdev); + event_notifier_cleanup(notifier); +} + static void vfio_ap_realize(DeviceState *dev, Error **errp) { int ret; char *mdevid; + Error *err = NULL; VFIOGroup *vfio_group; APDevice *apdev = AP_DEVICE(dev); VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); @@ -116,6 +219,15 @@ static void vfio_ap_realize(DeviceState *dev, Error **errp) goto out_get_dev_err; } + vfio_ap_register_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX, &err); + if (err) { + /* + * Report this error, but do not make it a failing condition. + * Lack of this IRQ in the host does not prevent normal operation. + */ + error_report_err(err); + } + return; out_get_dev_err: @@ -129,6 +241,7 @@ static void vfio_ap_unrealize(DeviceState *dev) VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); VFIOGroup *group = vapdev->vdev.group; + vfio_ap_unregister_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX); vfio_ap_put_device(vapdev); vfio_put_group(group); }
Let's wire up the device request notifier interface to handle device unplug requests for AP. Signed-off-by: Tony Krowiak <akrowiak@linux.ibm.com> Link: https://lore.kernel.org/qemu-devel/20230530225544.280031-1-akrowiak@linux.ibm.com/ --- hw/vfio/ap.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+)