Re: [PATCH v2 5/7] s390: vfio-ap: allow hot plug/unplug of AP resources using mdev device

From: Tony Krowiak
Date: Mon May 06 2019 - 16:39:56 EST


On 5/6/19 6:42 AM, Pierre Morel wrote:
On 03/05/2019 23:14, Tony Krowiak wrote:
Let's allow AP resources to be assigned to or unassigned from an AP matrix
mdev device while it is in use by a guest. If a guest is using the mdev
device while assignment is taking place, the guest will be granted access
to the resource as long as the guest will not be given access to an AP
queue device that is not bound to the vfio_ap device driver. If a guest is
using the mdev device while unassignment is taking place, access to the
resource will be taken from the guest.

Signed-off-by: Tony Krowiak <akrowiak@xxxxxxxxxxxxx>
---
 drivers/s390/crypto/vfio_ap_ops.c | 116 ++++++++++++++++++++++++++++----------
 1 file changed, 86 insertions(+), 30 deletions(-)

diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
index ea24caf17a16..ede45184eb67 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -226,6 +226,8 @@ static struct device *vfio_ap_get_queue_dev(unsigned long apid,
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ &apqn, match_apqn);
 }
+
+

two white lines

I will fix it.


 static int vfio_ap_mdev_validate_masks(unsigned long *apm, unsigned long *aqm)
 {
ÂÂÂÂÂ int ret;
@@ -237,6 +239,26 @@ static int vfio_ap_mdev_validate_masks(unsigned long *apm, unsigned long *aqm)
ÂÂÂÂÂ return vfio_ap_mdev_verify_no_sharing(apm, aqm);
 }
+static bool vfio_ap_queues_on_drv(unsigned long *apm, unsigned long *aqm)
+{
+ÂÂÂ unsigned long apid, apqi, apqn;
+ÂÂÂ struct device *dev;
+
+ÂÂÂ for_each_set_bit_inv(apid, apm, AP_DEVICES) {
+ÂÂÂÂÂÂÂ for_each_set_bit_inv(apqi, aqm, AP_DOMAINS) {
+ÂÂÂÂÂÂÂÂÂÂÂ apqn = AP_MKQID(apid, apqi);

You do not use apqn in the function.

Must be a remnant of another iteration. I'll remove it.


+
+ÂÂÂÂÂÂÂÂÂÂÂ dev = vfio_ap_get_queue_dev(apid, apqi);
+ÂÂÂÂÂÂÂÂÂÂÂ if (!dev)
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ return false;
+
+ÂÂÂÂÂÂÂÂÂÂÂ put_device(dev);
+ÂÂÂÂÂÂÂ }
+ÂÂÂ }
+
+ÂÂÂ return true;
+}
+
 /**
ÂÂ * assign_adapter_store
ÂÂ *
@@ -247,7 +269,10 @@ static int vfio_ap_mdev_validate_masks(unsigned long *apm, unsigned long *aqm)
ÂÂ * @count:ÂÂÂ the number of bytes in @buf
ÂÂ *
ÂÂ * Parses the APID from @buf and sets the corresponding bit in the mediated
- * matrix device's APM.
+ * matrix device's APM. If a guest is using the mediated matrix device and each
+ * new APQN formed as a result of the assignment identifies an AP queue device
+ * that is bound to the vfio_ap device driver, the guest will be granted access
+ * to the adapter with the specified APID.
ÂÂ *
ÂÂ * Returns the number of bytes processed if the APID is valid; otherwise,
ÂÂ * returns one of the following errors:
@@ -279,10 +304,6 @@ static ssize_t assign_adapter_store(struct device *dev,
ÂÂÂÂÂ struct mdev_device *mdev = mdev_from_dev(dev);
ÂÂÂÂÂ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
-ÂÂÂ /* If the guest is running, disallow assignment of adapter */
-ÂÂÂ if (matrix_mdev->kvm)
-ÂÂÂÂÂÂÂ return -EBUSY;
-
ÂÂÂÂÂ ret = kstrtoul(buf, 0, &apid);
ÂÂÂÂÂ if (ret)
ÂÂÂÂÂÂÂÂÂ return ret;
@@ -300,6 +321,14 @@ static ssize_t assign_adapter_store(struct device *dev,
ÂÂÂÂÂÂÂÂÂ return ret;
ÂÂÂÂÂ }
ÂÂÂÂÂ set_bit_inv(apid, matrix_mdev->matrix.apm);
+
+ÂÂÂ if (matrix_mdev->shadow_crycb) {
+ÂÂÂÂÂÂÂ if (vfio_ap_queues_on_drv(apm,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ matrix_mdev->shadow_crycb->aqm)) {
+ÂÂÂÂÂÂÂÂÂÂÂ set_bit_inv(apid, matrix_mdev->shadow_crycb->apm);
+ÂÂÂÂÂÂÂÂÂÂÂ vfio_ap_mdev_update_crycb(matrix_mdev);
+ÂÂÂÂÂÂÂ }
+ÂÂÂ }
ÂÂÂÂÂ mutex_unlock(&matrix_dev->lock);
ÂÂÂÂÂ return count;
@@ -315,7 +344,9 @@ static DEVICE_ATTR_WO(assign_adapter);
ÂÂ * @count:ÂÂÂ the number of bytes in @buf
ÂÂ *
ÂÂ * Parses the APID from @buf and clears the corresponding bit in the mediated
- * matrix device's APM.
+ * matrix device's APM. If a guest is using the mediated matrix device and has
+ * access to the AP adapter with the specified APID, access to the adapter will
+ * be taken from the guest.
ÂÂ *
ÂÂ * Returns the number of bytes processed if the APID is valid; otherwise,
ÂÂ * returns one of the following errors:
@@ -332,10 +363,6 @@ static ssize_t unassign_adapter_store(struct device *dev,
ÂÂÂÂÂ struct mdev_device *mdev = mdev_from_dev(dev);
ÂÂÂÂÂ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
-ÂÂÂ /* If the guest is running, disallow un-assignment of adapter */
-ÂÂÂ if (matrix_mdev->kvm)
-ÂÂÂÂÂÂÂ return -EBUSY;
-
ÂÂÂÂÂ ret = kstrtoul(buf, 0, &apid);
ÂÂÂÂÂ if (ret)
ÂÂÂÂÂÂÂÂÂ return ret;
@@ -345,6 +372,13 @@ static ssize_t unassign_adapter_store(struct device *dev,
ÂÂÂÂÂ mutex_lock(&matrix_dev->lock);
ÂÂÂÂÂ clear_bit_inv((unsigned long)apid, matrix_mdev->matrix.apm);
+
+ÂÂÂ if (matrix_mdev->shadow_crycb) {
+ÂÂÂÂÂÂÂ if (test_bit_inv(apid, matrix_mdev->shadow_crycb->apm)) {
+ÂÂÂÂÂÂÂÂÂÂÂ clear_bit_inv(apid, matrix_mdev->shadow_crycb->apm);
+ÂÂÂÂÂÂÂÂÂÂÂ vfio_ap_mdev_update_crycb(matrix_mdev);
+ÂÂÂÂÂÂÂ }
+ÂÂÂ }
ÂÂÂÂÂ mutex_unlock(&matrix_dev->lock);
ÂÂÂÂÂ return count;
@@ -361,7 +395,10 @@ static DEVICE_ATTR_WO(unassign_adapter);
ÂÂ * @count:ÂÂÂ the number of bytes in @buf
ÂÂ *
ÂÂ * Parses the APQI from @buf and sets the corresponding bit in the mediated
- * matrix device's AQM.
+ * matrix device's AQM. If a guest is using the mediated matrix device and each
+ * new APQN formed as a result of the assignment identifies an AP queue device
+ * that is bound to the vfio_ap device driver, the guest will be given access
+ * to the AP queue(s) with the specified APQI.
ÂÂ *
ÂÂ * Returns the number of bytes processed if the APQI is valid; otherwise returns
ÂÂ * one of the following errors:
@@ -394,10 +431,6 @@ static ssize_t assign_domain_store(struct device *dev,
ÂÂÂÂÂ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
ÂÂÂÂÂ unsigned long max_apqi = matrix_mdev->matrix.aqm_max;
-ÂÂÂ /* If the guest is running, disallow assignment of domain */
-ÂÂÂ if (matrix_mdev->kvm)
-ÂÂÂÂÂÂÂ return -EBUSY;
-
ÂÂÂÂÂ ret = kstrtoul(buf, 0, &apqi);
ÂÂÂÂÂ if (ret)
ÂÂÂÂÂÂÂÂÂ return ret;
@@ -414,6 +447,14 @@ static ssize_t assign_domain_store(struct device *dev,
ÂÂÂÂÂÂÂÂÂ return ret;
ÂÂÂÂÂ }
ÂÂÂÂÂ set_bit_inv(apqi, matrix_mdev->matrix.aqm);
+
+ÂÂÂ if (matrix_mdev->shadow_crycb) {
+ÂÂÂÂÂÂÂ if (vfio_ap_queues_on_drv(matrix_mdev->shadow_crycb->apm,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ aqm)) {
+ÂÂÂÂÂÂÂÂÂÂÂ set_bit_inv(apqi, matrix_mdev->shadow_crycb->aqm);
+ÂÂÂÂÂÂÂÂÂÂÂ vfio_ap_mdev_update_crycb(matrix_mdev);
+ÂÂÂÂÂÂÂ }
+ÂÂÂ }
ÂÂÂÂÂ mutex_unlock(&matrix_dev->lock);
ÂÂÂÂÂ return count;
@@ -431,7 +472,9 @@ static DEVICE_ATTR_WO(assign_domain);
ÂÂ * @count:ÂÂÂ the number of bytes in @buf
ÂÂ *
ÂÂ * Parses the APQI from @buf and clears the corresponding bit in the
- * mediated matrix device's AQM.
+ * mediated matrix device's AQM. If a guest is using the mediated matrix device
+ * and has access to queue(s) with the specified domain APQI, access to
+ * the queue(s) will be taken away from the guest.
ÂÂ *
ÂÂ * Returns the number of bytes processed if the APQI is valid; otherwise,
ÂÂ * returns one of the following errors:
@@ -447,10 +490,6 @@ static ssize_t unassign_domain_store(struct device *dev,
ÂÂÂÂÂ struct mdev_device *mdev = mdev_from_dev(dev);
ÂÂÂÂÂ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
-ÂÂÂ /* If the guest is running, disallow un-assignment of domain */
-ÂÂÂ if (matrix_mdev->kvm)
-ÂÂÂÂÂÂÂ return -EBUSY;
-
ÂÂÂÂÂ ret = kstrtoul(buf, 0, &apqi);
ÂÂÂÂÂ if (ret)
ÂÂÂÂÂÂÂÂÂ return ret;
@@ -460,6 +499,13 @@ static ssize_t unassign_domain_store(struct device *dev,
ÂÂÂÂÂ mutex_lock(&matrix_dev->lock);
ÂÂÂÂÂ clear_bit_inv((unsigned long)apqi, matrix_mdev->matrix.aqm);
+
+ÂÂÂ if (matrix_mdev->shadow_crycb) {
+ÂÂÂÂÂÂÂ if (test_bit_inv(apqi, matrix_mdev->shadow_crycb->aqm)) {
+ÂÂÂÂÂÂÂÂÂÂÂ clear_bit_inv(apqi, matrix_mdev->shadow_crycb->aqm);
+ÂÂÂÂÂÂÂÂÂÂÂ vfio_ap_mdev_update_crycb(matrix_mdev);
+ÂÂÂÂÂÂÂ }
+ÂÂÂ }
ÂÂÂÂÂ mutex_unlock(&matrix_dev->lock);
ÂÂÂÂÂ return count;
@@ -475,7 +521,9 @@ static DEVICE_ATTR_WO(unassign_domain);
ÂÂ * @count:ÂÂÂ the number of bytes in @buf
ÂÂ *
ÂÂ * Parses the domain ID from @buf and sets the corresponding bit in the mediated
- * matrix device's ADM.
+ * matrix device's ADM. If a guest is using the mediated matrix device and the
+ * guest does not have access to the control domain with the specified ID, the
+ * guest will be granted access to it.
ÂÂ *
ÂÂ * Returns the number of bytes processed if the domain ID is valid; otherwise,
ÂÂ * returns one of the following errors:
@@ -491,10 +539,6 @@ static ssize_t assign_control_domain_store(struct device *dev,
ÂÂÂÂÂ struct mdev_device *mdev = mdev_from_dev(dev);
ÂÂÂÂÂ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
-ÂÂÂ /* If the guest is running, disallow assignment of control domain */
-ÂÂÂ if (matrix_mdev->kvm)
-ÂÂÂÂÂÂÂ return -EBUSY;
-
ÂÂÂÂÂ ret = kstrtoul(buf, 0, &id);
ÂÂÂÂÂ if (ret)
ÂÂÂÂÂÂÂÂÂ return ret;
@@ -504,6 +548,13 @@ static ssize_t assign_control_domain_store(struct device *dev,
ÂÂÂÂÂ mutex_lock(&matrix_dev->lock);
ÂÂÂÂÂ set_bit_inv(id, matrix_mdev->matrix.adm);
+
+ÂÂÂ if (matrix_mdev->shadow_crycb) {
+ÂÂÂÂÂÂÂ if (!test_bit_inv(id, matrix_mdev->shadow_crycb->adm)) {
+ÂÂÂÂÂÂÂÂÂÂÂ set_bit_inv(id, matrix_mdev->shadow_crycb->adm);
+ÂÂÂÂÂÂÂÂÂÂÂ vfio_ap_mdev_update_crycb(matrix_mdev);
+ÂÂÂÂÂÂÂ }
+ÂÂÂ }
ÂÂÂÂÂ mutex_unlock(&matrix_dev->lock);
ÂÂÂÂÂ return count;
@@ -519,7 +570,9 @@ static DEVICE_ATTR_WO(assign_control_domain);
ÂÂ * @count:ÂÂÂ the number of bytes in @buf
ÂÂ *
ÂÂ * Parses the domain ID from @buf and clears the corresponding bit in the
- * mediated matrix device's ADM.
+ * mediated matrix device's ADM. If a guest is using the mediated matrix device
+ * and has access to control domain with the specified domain ID, access to
+ * the control domain will be taken from the guest.
ÂÂ *
ÂÂ * Returns the number of bytes processed if the domain ID is valid; otherwise,
ÂÂ * returns one of the following errors:
@@ -536,10 +589,6 @@ static ssize_t unassign_control_domain_store(struct device *dev,
ÂÂÂÂÂ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
ÂÂÂÂÂ unsigned long max_domid =Â matrix_mdev->matrix.adm_max;
-ÂÂÂ /* If the guest is running, disallow un-assignment of control domain */
-ÂÂÂ if (matrix_mdev->kvm)
-ÂÂÂÂÂÂÂ return -EBUSY;
-
ÂÂÂÂÂ ret = kstrtoul(buf, 0, &domid);
ÂÂÂÂÂ if (ret)
ÂÂÂÂÂÂÂÂÂ return ret;
@@ -548,6 +597,13 @@ static ssize_t unassign_control_domain_store(struct device *dev,
ÂÂÂÂÂ mutex_lock(&matrix_dev->lock);
ÂÂÂÂÂ clear_bit_inv(domid, matrix_mdev->matrix.adm);
+
+ÂÂÂ if (matrix_mdev->shadow_crycb) {
+ÂÂÂÂÂÂÂ if (test_bit_inv(domid, matrix_mdev->shadow_crycb->adm)) {
+ÂÂÂÂÂÂÂÂÂÂÂ clear_bit_inv(domid, matrix_mdev->shadow_crycb->adm);
+ÂÂÂÂÂÂÂÂÂÂÂ vfio_ap_mdev_update_crycb(matrix_mdev);
+ÂÂÂÂÂÂÂ }
+ÂÂÂ }
ÂÂÂÂÂ mutex_unlock(&matrix_dev->lock);
ÂÂÂÂÂ return count;


beside the two NITs, look good to me.
Still need to test.