int ap_owned_by_def_drv(int card, int queue)
{
int rc = 0;
@@ -824,25 +835,31 @@ int ap_owned_by_def_drv(int card, int queue)
if (card < 0 || card >= AP_DEVICES || queue < 0 || queue >=
AP_DOMAINS)
return -EINVAL;
- mutex_lock(&ap_perms_mutex);
-
if (test_bit_inv(card, ap_perms.apm)
&& test_bit_inv(queue, ap_perms.aqm))
rc = 1;
- mutex_unlock(&ap_perms_mutex);
-
return rc;
}
EXPORT_SYMBOL(ap_owned_by_def_drv);
+/**
+ * ap_apqn_in_matrix_owned_by_def_drv: indicates whether every APQN
contained in
+ * a set is reserved for the host drivers
+ * or not.
+ * @apm: a bitmap specifying a set of APIDs comprising the APQNs to
check
+ * @aqm: a bitmap specifying a set of APQIs comprising the APQNs to
check
+ *
+ * Note: the ap_perms_mutex must be locked by the caller of this
function.
+ *
+ * Return: an int specifying whether each APQN is reserved for the
host (1) or
+ * not (0)
+ */
int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm,
unsigned long *aqm)
{
int card, queue, rc = 0;
- mutex_lock(&ap_perms_mutex);
-
for (card = 0; !rc && card < AP_DEVICES; card++)
if (test_bit_inv(card, apm) &&
test_bit_inv(card, ap_perms.apm))
@@ -851,8 +868,6 @@ int ap_apqn_in_matrix_owned_by_def_drv(unsigned
long *apm,
test_bit_inv(queue, ap_perms.aqm))
rc = 1;
- mutex_unlock(&ap_perms_mutex);
-
return rc;
}
EXPORT_SYMBOL(ap_apqn_in_matrix_owned_by_def_drv);
diff --git a/drivers/s390/crypto/vfio_ap_drv.c
b/drivers/s390/crypto/vfio_ap_drv.c
index c258e5f7fdfc..2c3084589347 100644
--- a/drivers/s390/crypto/vfio_ap_drv.c
+++ b/drivers/s390/crypto/vfio_ap_drv.c
@@ -107,6 +107,7 @@ static const struct attribute_group
vfio_queue_attr_group = {
static struct ap_driver vfio_ap_drv = {
.probe = vfio_ap_mdev_probe_queue,
.remove = vfio_ap_mdev_remove_queue,
+ .in_use = vfio_ap_mdev_resource_in_use,
.ids = ap_queue_ids,
};
diff --git a/drivers/s390/crypto/vfio_ap_ops.c
b/drivers/s390/crypto/vfio_ap_ops.c
index 49ed54dc9e05..3ece2cd9f1e7 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -902,6 +902,21 @@ static int
vfio_ap_mdev_verify_no_sharing(unsigned long *mdev_apm,
return 0;
}
+/**
+ * vfio_ap_mdev_validate_masks - verify that the APQNs assigned to
the mdev are
+ * not reserved for the default zcrypt driver and
+ * are not assigned to another mdev.
+ *
+ * @matrix_mdev: the mdev to which the APQNs being validated are
assigned.
+ *
+ * Return: One of the following values:
+ * o the error returned from the
ap_apqn_in_matrix_owned_by_def_drv() function,
+ * most likely -EBUSY indicating the ap_perms_mutex lock is
already held.
+ * o EADDRNOTAVAIL if an APQN assigned to @matrix_mdev is reserved
for the
+ * zcrypt default driver.
+ * o EADDRINUSE if an APQN assigned to @matrix_mdev is assigned to
another mdev
+ * o A zero indicating validation succeeded.
+ */
static int vfio_ap_mdev_validate_masks(struct ap_matrix_mdev
*matrix_mdev)
{
if (ap_apqn_in_matrix_owned_by_def_drv(matrix_mdev->matrix.apm,
@@ -951,6 +966,10 @@ static void vfio_ap_mdev_link_adapter(struct
ap_matrix_mdev *matrix_mdev,
* An APQN derived from the cross product of the APID being
assigned
* and the APQIs previously assigned is being used by another
mediated
* matrix device
+ *
+ * 5. -EAGAIN
+ * A lock required to validate the mdev's AP configuration
could not
+ * be obtained.
*/
static ssize_t assign_adapter_store(struct device *dev,
struct device_attribute *attr,
@@ -961,6 +980,7 @@ static ssize_t assign_adapter_store(struct device
*dev,
DECLARE_BITMAP(apm_delta, AP_DEVICES);
struct ap_matrix_mdev *matrix_mdev = dev_get_drvdata(dev);
+ mutex_lock(&ap_perms_mutex);
get_update_locks_for_mdev(matrix_mdev);
ret = kstrtoul(buf, 0, &apid);
@@ -991,6 +1011,7 @@ static ssize_t assign_adapter_store(struct
device *dev,
ret = count;
done:
release_update_locks_for_mdev(matrix_mdev);
+ mutex_unlock(&ap_perms_mutex);
return ret;
}
@@ -1144,6 +1165,10 @@ static void vfio_ap_mdev_link_domain(struct
ap_matrix_mdev *matrix_mdev,
* An APQN derived from the cross product of the APQI being
assigned
* and the APIDs previously assigned is being used by another
mediated
* matrix device
+ *
+ * 5. -EAGAIN
+ * The lock required to validate the mdev's AP configuration
could not
+ * be obtained.
*/
static ssize_t assign_domain_store(struct device *dev,
struct device_attribute *attr,
@@ -1154,6 +1179,7 @@ static ssize_t assign_domain_store(struct
device *dev,
DECLARE_BITMAP(aqm_delta, AP_DOMAINS);
struct ap_matrix_mdev *matrix_mdev = dev_get_drvdata(dev);
+ mutex_lock(&ap_perms_mutex);
get_update_locks_for_mdev(matrix_mdev);
ret = kstrtoul(buf, 0, &apqi);
@@ -1184,6 +1210,7 @@ static ssize_t assign_domain_store(struct
device *dev,
ret = count;
done:
release_update_locks_for_mdev(matrix_mdev);
+ mutex_unlock(&ap_perms_mutex);
return ret;
}
@@ -1868,3 +1895,44 @@ void vfio_ap_mdev_remove_queue(struct
ap_device *apdev)
kfree(q);
release_update_locks_for_mdev(matrix_mdev);
}
+
+/**
+ * vfio_ap_mdev_resource_in_use: check whether any of a set of APQNs is
+ * assigned to a mediated device under the control
+ * of the vfio_ap device driver.
+ *
+ * @apm: a bitmap specifying a set of APIDs comprising the APQNs to
check.
+ * @aqm: a bitmap specifying a set of APQIs comprising the APQNs to
check.
+ *
+ * This function is invoked by the AP bus when changes to the
apmask/aqmask
+ * attributes will result in giving control of the queue devices
specified via
+ * @apm and @aqm to the default zcrypt device driver. Prior to
calling this
+ * function, the AP bus locks the ap_perms_mutex. If this function
is called
+ * while an adapter or domain is being assigned to a mediated
device, the
+ * assignment operations will take the matrix_dev->guests_lock and
+ * matrix_dev->mdevs_lock then call the
ap_apqn_in_matrix_owned_by_def_drv
+ * function, which also locks the ap_perms_mutex. This could result
in a
+ * deadlock.
+ *
+ * To avoid a deadlock, this function will verify that the
+ * matrix_dev->guests_lock and matrix_dev->mdevs_lock are not
currently held and
+ * will return -EBUSY if the locks can not be obtained.