[PATCH v1 08/24] s390/vfio-ap: Signal event to enable/disable live guest migration

Anthony Krowiak
2026-03-25T21:02:07Z

Defines two new eventfd contexts for signaling userspace to enable and
disable vfio device migration. The IRQ indexes defined for these events are
defined in an enum in the include/uapi/linux/vfio.h header file:

VFIO_AP_ENABLE_MIG_IRQ_INDEX: enable vfio device migration
VFIO_AP_DISABLE_MIG_IRQ_INDEX: disable vfio device migration

Information about those IRQs can be retrieved from userspace via the
VFIO_DEVICE_GET_IRQ_INFO ioctl. These events are initialized by the vfio_ap
device driver via the in response to the VFIO_DEVICE_SET_IRQ_INFO ioctl.
The eventfd for these IRQs will be signaled whenever the sysfs migratable
attribute of the mediated device is changed.

Signed-off-by: Anthony Krowiak <akrowiak@linux.ibm.com>
---
drivers/s390/crypto/vfio_ap_ops.c | 70 +++++++++++++++++++++++++--
drivers/s390/crypto/vfio_ap_private.h | 6 +++
include/uapi/linux/vfio.h | 2 +
3 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
index 97ec1f2fdbd1..213832263dc9 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -658,6 +658,18 @@ static void signal_guest_ap_cfg_changed(struct ap_matrix_mdev *matrix_mdev)
eventfd_signal(matrix_mdev->cfg_chg_trigger);
}

+static void signal_enable_migration(struct ap_matrix_mdev *matrix_mdev)
+{
+ if (matrix_mdev->enable_mig_trigger)
+ eventfd_signal(matrix_mdev->enable_mig_trigger);
+}
+
+static void signal_disable_migration(struct ap_matrix_mdev *matrix_mdev)
+{
+ if (matrix_mdev->disable_mig_trigger)
+ eventfd_signal(matrix_mdev->disable_mig_trigger);
+}
+
static void vfio_ap_mdev_update_guest_apcb(struct ap_matrix_mdev *matrix_mdev)
{
if (matrix_mdev->kvm) {
@@ -805,6 +817,8 @@ static int vfio_ap_mdev_probe(struct mdev_device *mdev)
matrix_mdev->req_trigger = NULL;
matrix_mdev->cfg_chg_trigger = NULL;
matrix_mdev->migratable = VFIO_AP_DEVICE_MIGRATABLE_DEFAULT;
+ matrix_mdev->enable_mig_trigger = NULL;
+ matrix_mdev->disable_mig_trigger = NULL;
dev_set_drvdata(&mdev->dev, matrix_mdev);
mutex_lock(&matrix_dev->mdevs_lock);
list_add(&matrix_mdev->node, &matrix_dev->mdev_list);
@@ -1821,7 +1835,18 @@ static ssize_t migratable_store(struct device *dev, struct device_attribute *att
goto out_unlock;
}

+ if (matrix_mdev->migratable == migratable) {
+ ret = count;
+ goto out_unlock;
+ }
+
matrix_mdev->migratable = migratable;
+
+ if (matrix_mdev->migratable)
+ signal_enable_migration(matrix_mdev);
+ else
+ signal_disable_migration(matrix_mdev);
+
ret = count;
out_unlock:
mutex_unlock(&matrix_dev->mdevs_lock);
@@ -2193,10 +2218,9 @@ static ssize_t vfio_ap_get_irq_info(unsigned long arg)

switch (info.index) {
case VFIO_AP_REQ_IRQ_INDEX:
- info.count = 1;
- info.flags = VFIO_IRQ_INFO_EVENTFD;
- break;
case VFIO_AP_CFG_CHG_IRQ_INDEX:
+ case VFIO_AP_ENABLE_MIG_IRQ_INDEX:
+ case VFIO_AP_DISABLE_MIG_IRQ_INDEX:
info.count = 1;
info.flags = VFIO_IRQ_INFO_EVENTFD;
break;
@@ -2296,6 +2320,40 @@ static int vfio_ap_set_cfg_change_irq(struct ap_matrix_mdev *matrix_mdev, unsign
return 0;
}

+static int vfio_ap_set_mig_irq(struct eventfd_ctx **mig_trigger,
+ unsigned long arg)
+{
+ s32 fd;
+ void __user *data;
+ unsigned long minsz;
+ struct eventfd_ctx *mig_ctx;
+
+ minsz = offsetofend(struct vfio_irq_set, count);
+ data = (void __user *)(arg + minsz);
+
+ if (get_user(fd, (s32 __user *)data))
+ return -EFAULT;
+
+ if (fd == -1) {
+ if (*mig_trigger)
+ eventfd_ctx_put(*mig_trigger);
+ *mig_trigger = NULL;
+ } else if (fd >= 0) {
+ mig_ctx = eventfd_ctx_fdget(fd);
+ if (IS_ERR(mig_ctx))
+ return PTR_ERR(mig_ctx);
+
+ if (*mig_trigger)
+ eventfd_ctx_put(*mig_trigger);
+
+ *mig_trigger = mig_ctx;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int vfio_ap_set_irqs(struct ap_matrix_mdev *matrix_mdev,
unsigned long arg)
{
@@ -2313,6 +2371,12 @@ static int vfio_ap_set_irqs(struct ap_matrix_mdev *matrix_mdev,
return vfio_ap_set_request_irq(matrix_mdev, arg);
case VFIO_AP_CFG_CHG_IRQ_INDEX:
return vfio_ap_set_cfg_change_irq(matrix_mdev, arg);
+ case VFIO_AP_ENABLE_MIG_IRQ_INDEX:
+ return vfio_ap_set_mig_irq(&matrix_mdev->enable_mig_trigger,
+ arg);
+ case VFIO_AP_DISABLE_MIG_IRQ_INDEX:
+ return vfio_ap_set_mig_irq(&matrix_mdev->disable_mig_trigger,
+ arg);
default:
return -EINVAL;
}
diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h
index b75299c9c1d0..514de4a73678 100644
--- a/drivers/s390/crypto/vfio_ap_private.h
+++ b/drivers/s390/crypto/vfio_ap_private.h
@@ -108,6 +108,10 @@ struct ap_queue_table {
* migrated (1) or not (0)
* @req_trigger eventfd ctx for signaling userspace to return a device
* @cfg_chg_trigger eventfd ctx to signal AP config changed to userspace
+ * @enable_mig_trigger: eventfd ctx to signal userspace to enable vfio device
+ * migration
+ * @disable_mig_trigger: eventfd ctx to signal userspace to disable vfio device
+ * migration
* @apm_add: bitmap of APIDs added to the host's AP configuration
* @aqm_add: bitmap of APQIs added to the host's AP configuration
* @adm_add: bitmap of control domain numbers added to the host's AP
@@ -125,6 +129,8 @@ struct ap_matrix_mdev {
int migratable;
struct eventfd_ctx *req_trigger;
struct eventfd_ctx *cfg_chg_trigger;
+ struct eventfd_ctx *enable_mig_trigger;
+ struct eventfd_ctx *disable_mig_trigger;
DECLARE_BITMAP(apm_add, AP_DEVICES);
DECLARE_BITMAP(aqm_add, AP_DOMAINS);
DECLARE_BITMAP(adm_add, AP_DOMAINS);
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index bb7b89330d35..c661b8b22ead 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -673,6 +673,8 @@ enum {
enum {
VFIO_AP_REQ_IRQ_INDEX,
VFIO_AP_CFG_CHG_IRQ_INDEX,
+ VFIO_AP_ENABLE_MIG_IRQ_INDEX,
+ VFIO_AP_DISABLE_MIG_IRQ_INDEX,
VFIO_AP_NUM_IRQS
};

--
2.52.0