Message ID | 1534196899-16987-11-git-send-email-akrowiak@linux.vnet.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | guest dedicated crypto adapters | expand |
On Mon, 13 Aug 2018 17:48:07 -0400 Tony Krowiak <akrowiak@linux.vnet.ibm.com> wrote: > +/** > + * assign_adapter_store > + * > + * @dev: the matrix device > + * @attr: a mediated matrix device attribute > + * @buf: a buffer containing the adapter ID (APID) to be assigned > + * @count: the number of bytes in @buf > + * > + * Parses the APID from @buf and assigns it to the mediated matrix device. > + * > + * Returns the number of bytes processed if the APID is valid; otherwise returns > + * an error. > + */ > +static ssize_t assign_adapter_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + int ret = 0; You don't need to initialize this to 0, as kstrtoul will set it in any case. > + unsigned long apid; > + struct mdev_device *mdev = mdev_from_dev(dev); > + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); > + unsigned long max_apid = matrix_mdev->matrix.apm_max; > + > + ret = kstrtoul(buf, 0, &apid); > + if (ret) > + return ret; > + if (apid > max_apid) > + return -EINVAL; > + > + /* Set the bit in the AP mask (APM) corresponding to the AP adapter > + * number (APID). The bits in the mask, from most significant to least > + * significant bit, correspond to APIDs 0-255. > + */ > + mutex_lock(&matrix_dev.lock); > + > + ret = vfio_ap_mdev_verify_queues_reserved_for_apid(matrix_mdev, apid); That function name really is a mouthful :) I don't have any better suggestions, though. > + if (ret) > + goto done; > + > + set_bit_inv(apid, matrix_mdev->matrix.apm); > + > + ret = vfio_ap_mdev_verify_no_sharing(matrix_mdev); > + if (ret) > + goto share_err; > + > + ret = count; > + goto done; > + > +share_err: > + clear_bit_inv(apid, matrix_mdev->matrix.apm); > +done: > + mutex_unlock(&matrix_dev.lock); > + > + return ret; > +} > +static DEVICE_ATTR_WO(assign_adapter); > + > +/** > + * unassign_adapter_store > + * > + * @dev: the matrix device > + * @attr: a mediated matrix device attribute > + * @buf: a buffer containing the adapter ID (APID) to be assigned > + * @count: the number of bytes in @buf > + * > + * Parses the APID from @buf and unassigns it from the mediated matrix device. > + * The APID must be a valid value A valid value, but not necessarily assigned, right? > + * > + * Returns the number of bytes processed if the APID is valid; otherwise returns > + * an error. > + */ > +static ssize_t unassign_adapter_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + int ret; > + unsigned long apid; > + struct mdev_device *mdev = mdev_from_dev(dev); > + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); > + > + ret = kstrtoul(buf, 0, &apid); > + if (ret) > + return ret; > + > + if (apid > matrix_mdev->matrix.apm_max) > + return -EINVAL; > + > + mutex_lock(&matrix_dev.lock); > + clear_bit_inv((unsigned long)apid, matrix_mdev->matrix.apm); > + mutex_unlock(&matrix_dev.lock); > + > + return count; > +} > +DEVICE_ATTR_WO(unassign_adapter); In general, looks good to me.
On 08/15/2018 05:52 AM, Cornelia Huck wrote: > On Mon, 13 Aug 2018 17:48:07 -0400 > Tony Krowiak <akrowiak@linux.vnet.ibm.com> wrote: > >> +/** >> + * assign_adapter_store >> + * >> + * @dev: the matrix device >> + * @attr: a mediated matrix device attribute >> + * @buf: a buffer containing the adapter ID (APID) to be assigned >> + * @count: the number of bytes in @buf >> + * >> + * Parses the APID from @buf and assigns it to the mediated matrix device. >> + * >> + * Returns the number of bytes processed if the APID is valid; otherwise returns >> + * an error. >> + */ >> +static ssize_t assign_adapter_store(struct device *dev, >> + struct device_attribute *attr, >> + const char *buf, size_t count) >> +{ >> + int ret = 0; > You don't need to initialize this to 0, as kstrtoul will set it in any > case. Right you are! Will change it. > >> + unsigned long apid; >> + struct mdev_device *mdev = mdev_from_dev(dev); >> + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); >> + unsigned long max_apid = matrix_mdev->matrix.apm_max; >> + >> + ret = kstrtoul(buf, 0, &apid); >> + if (ret) >> + return ret; >> + if (apid > max_apid) >> + return -EINVAL; >> + >> + /* Set the bit in the AP mask (APM) corresponding to the AP adapter >> + * number (APID). The bits in the mask, from most significant to least >> + * significant bit, correspond to APIDs 0-255. >> + */ >> + mutex_lock(&matrix_dev.lock); >> + >> + ret = vfio_ap_mdev_verify_queues_reserved_for_apid(matrix_mdev, apid); > That function name really is a mouthful :) I don't have any better > suggestions, though. It is, but I think it describes exactly what the function does. > >> + if (ret) >> + goto done; >> + >> + set_bit_inv(apid, matrix_mdev->matrix.apm); >> + >> + ret = vfio_ap_mdev_verify_no_sharing(matrix_mdev); >> + if (ret) >> + goto share_err; >> + >> + ret = count; >> + goto done; >> + >> +share_err: >> + clear_bit_inv(apid, matrix_mdev->matrix.apm); >> +done: >> + mutex_unlock(&matrix_dev.lock); >> + >> + return ret; >> +} >> +static DEVICE_ATTR_WO(assign_adapter); >> + >> +/** >> + * unassign_adapter_store >> + * >> + * @dev: the matrix device >> + * @attr: a mediated matrix device attribute >> + * @buf: a buffer containing the adapter ID (APID) to be assigned >> + * @count: the number of bytes in @buf >> + * >> + * Parses the APID from @buf and unassigns it from the mediated matrix device. >> + * The APID must be a valid value > A valid value, but not necessarily assigned, right? You are correct, if the APID is not assigned, then the corresponding bit will be cleared regardless. In a previous version, the functions failed if the APID is not assigned, but a colleague removed that check. I guess it makes sense given it really does not hurt anything to ask to unassign an APID that isn't assigned to begin with. Would you prefer I update the comment, or do you feel the user should be made aware of an attempt to unassign an APID that is not assigned? > >> + * >> + * Returns the number of bytes processed if the APID is valid; otherwise returns >> + * an error. >> + */ >> +static ssize_t unassign_adapter_store(struct device *dev, >> + struct device_attribute *attr, >> + const char *buf, size_t count) >> +{ >> + int ret; >> + unsigned long apid; >> + struct mdev_device *mdev = mdev_from_dev(dev); >> + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); >> + >> + ret = kstrtoul(buf, 0, &apid); >> + if (ret) >> + return ret; >> + >> + if (apid > matrix_mdev->matrix.apm_max) >> + return -EINVAL; >> + >> + mutex_lock(&matrix_dev.lock); >> + clear_bit_inv((unsigned long)apid, matrix_mdev->matrix.apm); >> + mutex_unlock(&matrix_dev.lock); >> + >> + return count; >> +} >> +DEVICE_ATTR_WO(unassign_adapter); > In general, looks good to me. That is good news indeed. >
On Wed, 15 Aug 2018 12:59:35 -0400 Tony Krowiak <akrowiak@linux.ibm.com> wrote: > On 08/15/2018 05:52 AM, Cornelia Huck wrote: > > On Mon, 13 Aug 2018 17:48:07 -0400 > > Tony Krowiak <akrowiak@linux.vnet.ibm.com> wrote: > >> +/** > >> + * unassign_adapter_store > >> + * > >> + * @dev: the matrix device > >> + * @attr: a mediated matrix device attribute > >> + * @buf: a buffer containing the adapter ID (APID) to be assigned > >> + * @count: the number of bytes in @buf > >> + * > >> + * Parses the APID from @buf and unassigns it from the mediated matrix device. > >> + * The APID must be a valid value > > A valid value, but not necessarily assigned, right? > > You are correct, if the APID is not assigned, then the corresponding bit > will be > cleared regardless. In a previous version, the functions failed if the > APID is > not assigned, but a colleague removed that check. I guess it makes sense > given > it really does not hurt anything to ask to unassign an APID that isn't > assigned > to begin with. Would you prefer I update the comment, or do you feel the > user > should be made aware of an attempt to unassign an APID that is not assigned? I think the code is fine; updating the comment would be good.
On 08/16/2018 03:30 AM, Cornelia Huck wrote: > On Wed, 15 Aug 2018 12:59:35 -0400 > Tony Krowiak <akrowiak@linux.ibm.com> wrote: > >> On 08/15/2018 05:52 AM, Cornelia Huck wrote: >>> On Mon, 13 Aug 2018 17:48:07 -0400 >>> Tony Krowiak <akrowiak@linux.vnet.ibm.com> wrote: >>>> +/** >>>> + * unassign_adapter_store >>>> + * >>>> + * @dev: the matrix device >>>> + * @attr: a mediated matrix device attribute >>>> + * @buf: a buffer containing the adapter ID (APID) to be assigned >>>> + * @count: the number of bytes in @buf >>>> + * >>>> + * Parses the APID from @buf and unassigns it from the mediated matrix device. >>>> + * The APID must be a valid value >>> A valid value, but not necessarily assigned, right? >> You are correct, if the APID is not assigned, then the corresponding bit >> will be >> cleared regardless. In a previous version, the functions failed if the >> APID is >> not assigned, but a colleague removed that check. I guess it makes sense >> given >> it really does not hurt anything to ask to unassign an APID that isn't >> assigned >> to begin with. Would you prefer I update the comment, or do you feel the >> user >> should be made aware of an attempt to unassign an APID that is not assigned? > I think the code is fine; updating the comment would be good. Will do. >
diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 8018c2d..dfb434c 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -106,9 +106,282 @@ static ssize_t device_api_show(struct kobject *kobj, struct device *dev, NULL, }; +struct vfio_ap_queue_reserved { + unsigned long *apid; + unsigned long *apqi; + bool reserved; +}; + +/** + * vfio_ap_has_queue + * + * @dev: an AP queue device + * @data: a struct vfio_ap_queue_reserved reference + * + * Flags whether the AP queue device (@dev) has a queue ID containing the APQN, + * apid or apqi specified in @data: + * + * - If @data contains both an apid and apqi value, then @data will be flagged + * as reserved if the APID and APQI fields for the AP queue device matches + * + * - If @data contains only an apid value, @data will be flagged as + * reserved if the APID field in the AP queue device matches + * + * - If @data contains only an apqi value, @data will be flagged as + * reserved if the APQI field in the AP queue device matches + * + * Returns 0 to indicate the input to function succeeded. Returns -EINVAL if + * @data does not contain either an apid or apqi. + */ +static int vfio_ap_has_queue(struct device *dev, void *data) +{ + struct vfio_ap_queue_reserved *qres = data; + struct ap_queue *ap_queue = to_ap_queue(dev); + ap_qid_t qid; + unsigned long id; + + if (qres->apid && qres->apqi) { + qid = AP_MKQID(*qres->apid, *qres->apqi); + if (qid == ap_queue->qid) + qres->reserved = true; + } else if (qres->apid && !qres->apqi) { + id = AP_QID_CARD(ap_queue->qid); + if (id == *qres->apid) + qres->reserved = true; + } else if (!qres->apid && qres->apqi) { + id = AP_QID_QUEUE(ap_queue->qid); + if (id == *qres->apqi) + qres->reserved = true; + } else { + return -EINVAL; + } + + return 0; +} + +/** + * vfio_ap_verify_queue_reserved + * + * @matrix_dev: a mediated matrix device + * @apid: an AP adapter ID + * @apqi: an AP queue index + * + * Verifies that the AP queue with @apid/@apqi is reserved by the VFIO AP device + * driver according to the following rules: + * + * - If both @apid and @apqi are not NULL, then there must be an AP queue + * device bound to the vfio_ap driver with the APQN identified by @apid and + * @apqi + * + * - If only @apid is not NULL, then there must be an AP queue device bound + * to the vfio_ap driver with an APQN containing @apid + * + * - If only @apqi is not NULL, then there must be an AP queue device bound + * to the vfio_ap driver with an APQN containing @apqi + * + * Returns 0 if the AP queue is reserved; otherwise, returns -EADDRNOTAVAIL. + */ +static int vfio_ap_verify_queue_reserved(unsigned long *apid, + unsigned long *apqi) +{ + int ret; + struct vfio_ap_queue_reserved qres; + + qres.apid = apid; + qres.apqi = apqi; + qres.reserved = false; + + ret = driver_for_each_device(matrix_dev.device.driver, NULL, &qres, + vfio_ap_has_queue); + if (ret) + return ret; + + if (qres.reserved) + return 0; + + return -EADDRNOTAVAIL; +} + +static int +vfio_ap_mdev_verify_queues_reserved_for_apid(struct ap_matrix_mdev *matrix_mdev, + unsigned long apid) +{ + int ret; + unsigned long apqi; + unsigned long nbits = matrix_mdev->matrix.aqm_max + 1; + + if (find_first_bit_inv(matrix_mdev->matrix.aqm, nbits) >= nbits) + return vfio_ap_verify_queue_reserved(&apid, NULL); + + for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm, nbits) { + ret = vfio_ap_verify_queue_reserved(&apid, &apqi); + if (ret) + return ret; + } + + return 0; +} + +/** + * vfio_ap_mdev_verify_no_sharing + * + * Verifies that the APQNs derived from the cross product of the AP adapter IDs + * and AP queue indexes comprising the AP matrix are not configured for another + * mediated device. AP queue sharing is not allowed. + * + * @kvm: the KVM guest + * @matrix: the AP matrix + * + * Returns 0 if the APQNs are not shared, otherwise; returns -EADDRINUSE. + */ +static int vfio_ap_mdev_verify_no_sharing(struct ap_matrix_mdev *matrix_mdev) +{ + int nbits; + struct ap_matrix_mdev *lstdev; + unsigned long apm[BITS_TO_LONGS(matrix_mdev->matrix.apm_max + 1)]; + unsigned long aqm[BITS_TO_LONGS(matrix_mdev->matrix.aqm_max + 1)]; + + list_for_each_entry(lstdev, &matrix_dev.mdev_list, list) { + if (matrix_mdev == lstdev) + continue; + + memset(apm, 0, sizeof(apm)); + memset(aqm, 0, sizeof(aqm)); + + /* + * We work on full longs, as we can only exclude the leftover + * bits in non-inverse order. The leftover is all zeros. + */ + nbits = sizeof(apm) * BITS_PER_BYTE; + if (!bitmap_and(apm, matrix_mdev->matrix.apm, + lstdev->matrix.apm, nbits)) + continue; + + nbits = sizeof(aqm) * BITS_PER_BYTE; + if (!bitmap_and(aqm, matrix_mdev->matrix.aqm, + lstdev->matrix.aqm, nbits)) + continue; + + return -EADDRINUSE; + } + + return 0; +} + +/** + * assign_adapter_store + * + * @dev: the matrix device + * @attr: a mediated matrix device attribute + * @buf: a buffer containing the adapter ID (APID) to be assigned + * @count: the number of bytes in @buf + * + * Parses the APID from @buf and assigns it to the mediated matrix device. + * + * Returns the number of bytes processed if the APID is valid; otherwise returns + * an error. + */ +static ssize_t assign_adapter_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret = 0; + unsigned long apid; + struct mdev_device *mdev = mdev_from_dev(dev); + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + unsigned long max_apid = matrix_mdev->matrix.apm_max; + + ret = kstrtoul(buf, 0, &apid); + if (ret) + return ret; + if (apid > max_apid) + return -EINVAL; + + /* Set the bit in the AP mask (APM) corresponding to the AP adapter + * number (APID). The bits in the mask, from most significant to least + * significant bit, correspond to APIDs 0-255. + */ + mutex_lock(&matrix_dev.lock); + + ret = vfio_ap_mdev_verify_queues_reserved_for_apid(matrix_mdev, apid); + if (ret) + goto done; + + set_bit_inv(apid, matrix_mdev->matrix.apm); + + ret = vfio_ap_mdev_verify_no_sharing(matrix_mdev); + if (ret) + goto share_err; + + ret = count; + goto done; + +share_err: + clear_bit_inv(apid, matrix_mdev->matrix.apm); +done: + mutex_unlock(&matrix_dev.lock); + + return ret; +} +static DEVICE_ATTR_WO(assign_adapter); + +/** + * unassign_adapter_store + * + * @dev: the matrix device + * @attr: a mediated matrix device attribute + * @buf: a buffer containing the adapter ID (APID) to be assigned + * @count: the number of bytes in @buf + * + * Parses the APID from @buf and unassigns it from the mediated matrix device. + * The APID must be a valid value + * + * Returns the number of bytes processed if the APID is valid; otherwise returns + * an error. + */ +static ssize_t unassign_adapter_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned long apid; + struct mdev_device *mdev = mdev_from_dev(dev); + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + + ret = kstrtoul(buf, 0, &apid); + if (ret) + return ret; + + if (apid > matrix_mdev->matrix.apm_max) + return -EINVAL; + + mutex_lock(&matrix_dev.lock); + clear_bit_inv((unsigned long)apid, matrix_mdev->matrix.apm); + mutex_unlock(&matrix_dev.lock); + + return count; +} +DEVICE_ATTR_WO(unassign_adapter); + +static struct attribute *vfio_ap_mdev_attrs[] = { + &dev_attr_assign_adapter.attr, + &dev_attr_unassign_adapter.attr, + NULL +}; + +static struct attribute_group vfio_ap_mdev_attr_group = { + .attrs = vfio_ap_mdev_attrs +}; + +static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { + &vfio_ap_mdev_attr_group, + NULL +}; + static const struct mdev_parent_ops vfio_ap_matrix_ops = { .owner = THIS_MODULE, .supported_type_groups = vfio_ap_mdev_type_groups, + .mdev_attr_groups = vfio_ap_mdev_attr_groups, .create = vfio_ap_mdev_create, .remove = vfio_ap_mdev_remove, };