]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
s390/ap: Restrict driver_override versus apmask and aqmask use
authorHarald Freudenberger <freude@linux.ibm.com>
Wed, 19 Nov 2025 15:27:38 +0000 (16:27 +0100)
committerHeiko Carstens <hca@linux.ibm.com>
Mon, 24 Nov 2025 10:43:06 +0000 (11:43 +0100)
Introduce a restriction for the driver_override feature versus apmask
and aqmask:
- driver_override is only allowed when the apmask and aqmask values
  both are default (=0xffff..ffff).
- apmask and aqmask modifications are only allowed when there is no
  driver_override on any AP device active.
So in the end the user is restricted to choose to either use
apmask/apmask to divide the AP devices into host owned and vfio owned
or use the driver_override feature but not mix these two approaches.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/ap_bus.h
drivers/s390/crypto/ap_queue.c

index 3781b970fe619d9516781c8b2782fac976bbab53..e4bd4f79aaa33c7637526d71e73c68c0ad70ed70 100644 (file)
@@ -86,8 +86,13 @@ DEFINE_SPINLOCK(ap_queues_lock);
 /* Default permissions (ioctl, card and domain masking) */
 struct ap_perms ap_perms;
 EXPORT_SYMBOL(ap_perms);
+/* true if apmask and/or aqmask are NOT default */
+bool ap_apmask_aqmask_in_use;
+/* counter for how many driver_overrides are currently active */
+int ap_driver_override_ctr;
 /*
- * Mutex for consistent read and write of the ap_perms struct
+ * Mutex for consistent read and write of the ap_perms struct,
+ * ap_apmask_aqmask_in_use, ap_driver_override_ctr
  * and the ap bus sysfs attributes apmask and aqmask.
  */
 DEFINE_MUTEX(ap_attr_mutex);
@@ -1542,18 +1547,31 @@ static int apmask_commit(unsigned long *newapm)
 
        memcpy(ap_perms.apm, newapm, APMASKSIZE);
 
+       /*
+        * Update ap_apmask_aqmask_in_use. Note that the
+        * ap_attr_mutex has to be obtained here.
+        */
+       ap_apmask_aqmask_in_use =
+               bitmap_full(ap_perms.apm, AP_DEVICES) &&
+               bitmap_full(ap_perms.aqm, AP_DOMAINS) ?
+               false : true;
+
        return 0;
 }
 
 static ssize_t apmask_store(const struct bus_type *bus, const char *buf,
                            size_t count)
 {
-       int rc, changes = 0;
        DECLARE_BITMAP(newapm, AP_DEVICES);
+       int rc = -EINVAL, changes = 0;
 
        if (mutex_lock_interruptible(&ap_attr_mutex))
                return -ERESTARTSYS;
 
+       /* Do not allow apmask/aqmask if driver override is active */
+       if (ap_driver_override_ctr)
+               goto done;
+
        rc = ap_parse_bitmap_str(buf, ap_perms.apm, AP_DEVICES, newapm);
        if (rc)
                goto done;
@@ -1636,18 +1654,31 @@ static int aqmask_commit(unsigned long *newaqm)
 
        memcpy(ap_perms.aqm, newaqm, AQMASKSIZE);
 
+       /*
+        * Update ap_apmask_aqmask_in_use. Note that the
+        * ap_attr_mutex has to be obtained here.
+        */
+       ap_apmask_aqmask_in_use =
+               bitmap_full(ap_perms.apm, AP_DEVICES) &&
+               bitmap_full(ap_perms.aqm, AP_DOMAINS) ?
+               false : true;
+
        return 0;
 }
 
 static ssize_t aqmask_store(const struct bus_type *bus, const char *buf,
                            size_t count)
 {
-       int rc, changes = 0;
        DECLARE_BITMAP(newaqm, AP_DOMAINS);
+       int rc = -EINVAL, changes = 0;
 
        if (mutex_lock_interruptible(&ap_attr_mutex))
                return -ERESTARTSYS;
 
+       /* Do not allow apmask/aqmask if driver override is active */
+       if (ap_driver_override_ctr)
+               goto done;
+
        rc = ap_parse_bitmap_str(buf, ap_perms.aqm, AP_DOMAINS, newaqm);
        if (rc)
                goto done;
index 2b8804fc68b45bec270b4f7112a7eef880486031..51e08f27bd75e8541923740cd7bc1c34cbd6a735 100644 (file)
@@ -281,6 +281,8 @@ struct ap_perms {
 };
 
 extern struct ap_perms ap_perms;
+extern bool ap_apmask_aqmask_in_use;
+extern int ap_driver_override_ctr;
 extern struct mutex ap_attr_mutex;
 
 /*
index f05ff54f4c4b4eb0aac8af2e8946309b1ad8a6b2..4fe443d30f9b4a18a044f7c4c4ef1d85169807b0 100644 (file)
@@ -755,13 +755,30 @@ static ssize_t driver_override_store(struct device *dev,
 {
        struct ap_queue *aq = to_ap_queue(dev);
        struct ap_device *ap_dev = &aq->ap_dev;
-       int rc;
+       int rc = -EINVAL;
+       bool old_value;
+
+       if (mutex_lock_interruptible(&ap_attr_mutex))
+               return -ERESTARTSYS;
+
+       /* Do not allow driver override if apmask/aqmask is in use */
+       if (ap_apmask_aqmask_in_use)
+               goto out;
 
+       old_value = ap_dev->driver_override ? true : false;
        rc = driver_set_override(dev, &ap_dev->driver_override, buf, count);
        if (rc)
-               return rc;
+               goto out;
+       if (old_value && !ap_dev->driver_override)
+               --ap_driver_override_ctr;
+       else if (!old_value && ap_dev->driver_override)
+               ++ap_driver_override_ctr;
 
-       return count;
+       rc = count;
+
+out:
+       mutex_unlock(&ap_attr_mutex);
+       return rc;
 }
 
 static DEVICE_ATTR_RW(driver_override);