]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
s390/vfio-ap: Signal eventfd when guest AP configuration is changed
authorRorie Reyes <rreyes@linux.ibm.com>
Tue, 7 Jan 2025 18:36:45 +0000 (13:36 -0500)
committerVasily Gorbik <gor@linux.ibm.com>
Tue, 18 Feb 2025 17:53:48 +0000 (18:53 +0100)
In this patch, an eventfd object is created by the vfio_ap device driver
and used to notify userspace when a guests's AP configuration is
dynamically changed. Such changes may occur whenever:

* An adapter, domain or control domain is assigned to or unassigned from a
  mediated device that is attached to the guest.
* A queue assigned to the mediated device that is attached to a guest is
  bound to or unbound from the vfio_ap device driver. This can occur
  either by manually binding/unbinding the queue via the vfio_ap driver's
  sysfs bind/unbind attribute interfaces, or because an adapter, domain or
  control domain assigned to the mediated device is added to or removed
  from the host's AP configuration via an SE/HMC

The purpose of this patch is to provide immediate notification of changes
made to a guest's AP configuration by the vfio_ap driver. This will enable
the guest to take immediate action rather than relying on polling or some
other inefficient mechanism to detect changes to its AP configuration.

Note that there are corresponding QEMU patches that will be shipped along
with this patch (see vfio-ap: Report vfio-ap configuration changes) that
will pick up the eventfd signal.

Signed-off-by: Rorie Reyes <rreyes@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Tested-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Link: https://lore.kernel.org/r/20250107183645.90082-1-rreyes@linux.ibm.com
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
drivers/s390/crypto/vfio_ap_ops.c
drivers/s390/crypto/vfio_ap_private.h
include/uapi/linux/vfio.h

index 4c6a6d91a13fa4439ec4ef535aa3dbcb8105074c..571f5dcb49c5174bfdd24ebba84c61923449b582 100644 (file)
@@ -650,13 +650,22 @@ static void vfio_ap_matrix_init(struct ap_config_info *info,
        matrix->adm_max = info->apxa ? info->nd : 15;
 }
 
+static void signal_guest_ap_cfg_changed(struct ap_matrix_mdev *matrix_mdev)
+{
+               if (matrix_mdev->cfg_chg_trigger)
+                       eventfd_signal(matrix_mdev->cfg_chg_trigger);
+}
+
 static void vfio_ap_mdev_update_guest_apcb(struct ap_matrix_mdev *matrix_mdev)
 {
-       if (matrix_mdev->kvm)
+       if (matrix_mdev->kvm) {
                kvm_arch_crypto_set_masks(matrix_mdev->kvm,
                                          matrix_mdev->shadow_apcb.apm,
                                          matrix_mdev->shadow_apcb.aqm,
                                          matrix_mdev->shadow_apcb.adm);
+
+               signal_guest_ap_cfg_changed(matrix_mdev);
+       }
 }
 
 static bool vfio_ap_mdev_filter_cdoms(struct ap_matrix_mdev *matrix_mdev)
@@ -792,6 +801,7 @@ static int vfio_ap_mdev_probe(struct mdev_device *mdev)
        if (ret)
                goto err_put_vdev;
        matrix_mdev->req_trigger = NULL;
+       matrix_mdev->cfg_chg_trigger = NULL;
        dev_set_drvdata(&mdev->dev, matrix_mdev);
        mutex_lock(&matrix_dev->mdevs_lock);
        list_add(&matrix_mdev->node, &matrix_dev->mdev_list);
@@ -1860,6 +1870,7 @@ static void vfio_ap_mdev_unset_kvm(struct ap_matrix_mdev *matrix_mdev)
                get_update_locks_for_kvm(kvm);
 
                kvm_arch_crypto_clear_masks(kvm);
+               signal_guest_ap_cfg_changed(matrix_mdev);
                vfio_ap_mdev_reset_queues(matrix_mdev);
                kvm_put_kvm(kvm);
                matrix_mdev->kvm = NULL;
@@ -2097,6 +2108,10 @@ static ssize_t vfio_ap_get_irq_info(unsigned long arg)
                info.count = 1;
                info.flags = VFIO_IRQ_INFO_EVENTFD;
                break;
+       case VFIO_AP_CFG_CHG_IRQ_INDEX:
+               info.count = 1;
+               info.flags = VFIO_IRQ_INFO_EVENTFD;
+               break;
        default:
                return -EINVAL;
        }
@@ -2160,6 +2175,39 @@ static int vfio_ap_set_request_irq(struct ap_matrix_mdev *matrix_mdev,
        return 0;
 }
 
+static int vfio_ap_set_cfg_change_irq(struct ap_matrix_mdev *matrix_mdev, unsigned long arg)
+{
+       s32 fd;
+       void __user *data;
+       unsigned long minsz;
+       struct eventfd_ctx *cfg_chg_trigger;
+
+       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 (matrix_mdev->cfg_chg_trigger)
+                       eventfd_ctx_put(matrix_mdev->cfg_chg_trigger);
+               matrix_mdev->cfg_chg_trigger = NULL;
+       } else if (fd >= 0) {
+               cfg_chg_trigger = eventfd_ctx_fdget(fd);
+               if (IS_ERR(cfg_chg_trigger))
+                       return PTR_ERR(cfg_chg_trigger);
+
+               if (matrix_mdev->cfg_chg_trigger)
+                       eventfd_ctx_put(matrix_mdev->cfg_chg_trigger);
+
+               matrix_mdev->cfg_chg_trigger = cfg_chg_trigger;
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int vfio_ap_set_irqs(struct ap_matrix_mdev *matrix_mdev,
                            unsigned long arg)
 {
@@ -2175,6 +2223,8 @@ static int vfio_ap_set_irqs(struct ap_matrix_mdev *matrix_mdev,
                switch (irq_set.index) {
                case VFIO_AP_REQ_IRQ_INDEX:
                        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);
                default:
                        return -EINVAL;
                }
index 9d16321777c8d4d47c9be420e98973cdb0764ec9..9bff666b0b35d3085ff9fb2bf94ea99603533470 100644 (file)
@@ -105,6 +105,7 @@ struct ap_queue_table {
  * @mdev:      the mediated device
  * @qtable:    table of queues (struct vfio_ap_queue) assigned to the mdev
  * @req_trigger eventfd ctx for signaling userspace to return a device
+ * @cfg_chg_trigger eventfd ctx to signal AP config changed to userspace
  * @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
@@ -120,6 +121,7 @@ struct ap_matrix_mdev {
        struct mdev_device *mdev;
        struct ap_queue_table qtable;
        struct eventfd_ctx *req_trigger;
+       struct eventfd_ctx *cfg_chg_trigger;
        DECLARE_BITMAP(apm_add, AP_DEVICES);
        DECLARE_BITMAP(aqm_add, AP_DOMAINS);
        DECLARE_BITMAP(adm_add, AP_DOMAINS);
index c8dbf8219c4fcb296fe48d40fa892f172838b579..a2d3e1ac62399bd1b413b29b9834ef22777e06d1 100644 (file)
@@ -671,6 +671,7 @@ enum {
  */
 enum {
        VFIO_AP_REQ_IRQ_INDEX,
+       VFIO_AP_CFG_CHG_IRQ_INDEX,
        VFIO_AP_NUM_IRQS
 };