s390/vfio-ap: replace open coded locks for VFIO_GROUP_NOTIFY_SET_KVM notification
It was pointed out during an unrelated patch review that locks should not be open coded - i.e., writing the algorithm of a standard lock in a function instead of using a lock from the standard library. The setting and testing of a busy flag and sleeping on a wait_event is the same thing a lock does. The open coded locks are invisible to lockdep, so potential locking problems are not detected. This patch removes the open coded locks used during VFIO_GROUP_NOTIFY_SET_KVM notification. The busy flag and wait queue were introduced to resolve a possible circular locking dependency reported by lockdep when starting a secure execution guest configured with AP adapters and domains. Reversing the order in which the kvm->lock mutex and matrix_dev->lock mutex are locked resolves the issue reported by lockdep, thus enabling the removal of the open coded locks. Signed-off-by: Tony Krowiak <akrowiak@linux.ibm.com> Acked-by: Halil Pasic <pasic@linux.ibm.com> Link: https://lore.kernel.org/r/20210823212047.1476436-3-akrowiak@linux.ibm.com Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
parent
1e753732bd
commit
86956e7076
@ -2559,12 +2559,26 @@ static void kvm_s390_set_crycb_format(struct kvm *kvm)
|
|||||||
kvm->arch.crypto.crycbd |= CRYCB_FORMAT1;
|
kvm->arch.crypto.crycbd |= CRYCB_FORMAT1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kvm_arch_crypto_set_masks
|
||||||
|
*
|
||||||
|
* @kvm: pointer to the target guest's KVM struct containing the crypto masks
|
||||||
|
* to be set.
|
||||||
|
* @apm: the mask identifying the accessible AP adapters
|
||||||
|
* @aqm: the mask identifying the accessible AP domains
|
||||||
|
* @adm: the mask identifying the accessible AP control domains
|
||||||
|
*
|
||||||
|
* Set the masks that identify the adapters, domains and control domains to
|
||||||
|
* which the KVM guest is granted access.
|
||||||
|
*
|
||||||
|
* Note: The kvm->lock mutex must be locked by the caller before invoking this
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
void kvm_arch_crypto_set_masks(struct kvm *kvm, unsigned long *apm,
|
void kvm_arch_crypto_set_masks(struct kvm *kvm, unsigned long *apm,
|
||||||
unsigned long *aqm, unsigned long *adm)
|
unsigned long *aqm, unsigned long *adm)
|
||||||
{
|
{
|
||||||
struct kvm_s390_crypto_cb *crycb = kvm->arch.crypto.crycb;
|
struct kvm_s390_crypto_cb *crycb = kvm->arch.crypto.crycb;
|
||||||
|
|
||||||
mutex_lock(&kvm->lock);
|
|
||||||
kvm_s390_vcpu_block_all(kvm);
|
kvm_s390_vcpu_block_all(kvm);
|
||||||
|
|
||||||
switch (kvm->arch.crypto.crycbd & CRYCB_FORMAT_MASK) {
|
switch (kvm->arch.crypto.crycbd & CRYCB_FORMAT_MASK) {
|
||||||
@ -2595,13 +2609,23 @@ void kvm_arch_crypto_set_masks(struct kvm *kvm, unsigned long *apm,
|
|||||||
/* recreate the shadow crycb for each vcpu */
|
/* recreate the shadow crycb for each vcpu */
|
||||||
kvm_s390_sync_request_broadcast(kvm, KVM_REQ_VSIE_RESTART);
|
kvm_s390_sync_request_broadcast(kvm, KVM_REQ_VSIE_RESTART);
|
||||||
kvm_s390_vcpu_unblock_all(kvm);
|
kvm_s390_vcpu_unblock_all(kvm);
|
||||||
mutex_unlock(&kvm->lock);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(kvm_arch_crypto_set_masks);
|
EXPORT_SYMBOL_GPL(kvm_arch_crypto_set_masks);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kvm_arch_crypto_clear_masks
|
||||||
|
*
|
||||||
|
* @kvm: pointer to the target guest's KVM struct containing the crypto masks
|
||||||
|
* to be cleared.
|
||||||
|
*
|
||||||
|
* Clear the masks that identify the adapters, domains and control domains to
|
||||||
|
* which the KVM guest is granted access.
|
||||||
|
*
|
||||||
|
* Note: The kvm->lock mutex must be locked by the caller before invoking this
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
void kvm_arch_crypto_clear_masks(struct kvm *kvm)
|
void kvm_arch_crypto_clear_masks(struct kvm *kvm)
|
||||||
{
|
{
|
||||||
mutex_lock(&kvm->lock);
|
|
||||||
kvm_s390_vcpu_block_all(kvm);
|
kvm_s390_vcpu_block_all(kvm);
|
||||||
|
|
||||||
memset(&kvm->arch.crypto.crycb->apcb0, 0,
|
memset(&kvm->arch.crypto.crycb->apcb0, 0,
|
||||||
@ -2613,7 +2637,6 @@ void kvm_arch_crypto_clear_masks(struct kvm *kvm)
|
|||||||
/* recreate the shadow crycb for each vcpu */
|
/* recreate the shadow crycb for each vcpu */
|
||||||
kvm_s390_sync_request_broadcast(kvm, KVM_REQ_VSIE_RESTART);
|
kvm_s390_sync_request_broadcast(kvm, KVM_REQ_VSIE_RESTART);
|
||||||
kvm_s390_vcpu_unblock_all(kvm);
|
kvm_s390_vcpu_unblock_all(kvm);
|
||||||
mutex_unlock(&kvm->lock);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(kvm_arch_crypto_clear_masks);
|
EXPORT_SYMBOL_GPL(kvm_arch_crypto_clear_masks);
|
||||||
|
|
||||||
|
@ -294,15 +294,6 @@ static int handle_pqap(struct kvm_vcpu *vcpu)
|
|||||||
matrix_mdev = container_of(vcpu->kvm->arch.crypto.pqap_hook,
|
matrix_mdev = container_of(vcpu->kvm->arch.crypto.pqap_hook,
|
||||||
struct ap_matrix_mdev, pqap_hook);
|
struct ap_matrix_mdev, pqap_hook);
|
||||||
|
|
||||||
/*
|
|
||||||
* If the KVM pointer is in the process of being set, wait until the
|
|
||||||
* process has completed.
|
|
||||||
*/
|
|
||||||
wait_event_cmd(matrix_mdev->wait_for_kvm,
|
|
||||||
!matrix_mdev->kvm_busy,
|
|
||||||
mutex_unlock(&matrix_dev->lock),
|
|
||||||
mutex_lock(&matrix_dev->lock));
|
|
||||||
|
|
||||||
/* If the there is no guest using the mdev, there is nothing to do */
|
/* If the there is no guest using the mdev, there is nothing to do */
|
||||||
if (!matrix_mdev->kvm)
|
if (!matrix_mdev->kvm)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
@ -350,7 +341,6 @@ static int vfio_ap_mdev_create(struct mdev_device *mdev)
|
|||||||
|
|
||||||
matrix_mdev->mdev = mdev;
|
matrix_mdev->mdev = mdev;
|
||||||
vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->matrix);
|
vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->matrix);
|
||||||
init_waitqueue_head(&matrix_mdev->wait_for_kvm);
|
|
||||||
mdev_set_drvdata(mdev, matrix_mdev);
|
mdev_set_drvdata(mdev, matrix_mdev);
|
||||||
matrix_mdev->pqap_hook = handle_pqap;
|
matrix_mdev->pqap_hook = handle_pqap;
|
||||||
mutex_lock(&matrix_dev->lock);
|
mutex_lock(&matrix_dev->lock);
|
||||||
@ -619,11 +609,8 @@ static ssize_t assign_adapter_store(struct device *dev,
|
|||||||
|
|
||||||
mutex_lock(&matrix_dev->lock);
|
mutex_lock(&matrix_dev->lock);
|
||||||
|
|
||||||
/*
|
/* If the KVM guest is running, disallow assignment of adapter */
|
||||||
* If the KVM pointer is in flux or the guest is running, disallow
|
if (matrix_mdev->kvm) {
|
||||||
* un-assignment of adapter
|
|
||||||
*/
|
|
||||||
if (matrix_mdev->kvm_busy || matrix_mdev->kvm) {
|
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -692,11 +679,8 @@ static ssize_t unassign_adapter_store(struct device *dev,
|
|||||||
|
|
||||||
mutex_lock(&matrix_dev->lock);
|
mutex_lock(&matrix_dev->lock);
|
||||||
|
|
||||||
/*
|
/* If the KVM guest is running, disallow unassignment of adapter */
|
||||||
* If the KVM pointer is in flux or the guest is running, disallow
|
if (matrix_mdev->kvm) {
|
||||||
* un-assignment of adapter
|
|
||||||
*/
|
|
||||||
if (matrix_mdev->kvm_busy || matrix_mdev->kvm) {
|
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -782,11 +766,8 @@ static ssize_t assign_domain_store(struct device *dev,
|
|||||||
|
|
||||||
mutex_lock(&matrix_dev->lock);
|
mutex_lock(&matrix_dev->lock);
|
||||||
|
|
||||||
/*
|
/* If the KVM guest is running, disallow assignment of domain */
|
||||||
* If the KVM pointer is in flux or the guest is running, disallow
|
if (matrix_mdev->kvm) {
|
||||||
* assignment of domain
|
|
||||||
*/
|
|
||||||
if (matrix_mdev->kvm_busy || matrix_mdev->kvm) {
|
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -850,11 +831,8 @@ static ssize_t unassign_domain_store(struct device *dev,
|
|||||||
|
|
||||||
mutex_lock(&matrix_dev->lock);
|
mutex_lock(&matrix_dev->lock);
|
||||||
|
|
||||||
/*
|
/* If the KVM guest is running, disallow unassignment of domain */
|
||||||
* If the KVM pointer is in flux or the guest is running, disallow
|
if (matrix_mdev->kvm) {
|
||||||
* un-assignment of domain
|
|
||||||
*/
|
|
||||||
if (matrix_mdev->kvm_busy || matrix_mdev->kvm) {
|
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -904,11 +882,8 @@ static ssize_t assign_control_domain_store(struct device *dev,
|
|||||||
|
|
||||||
mutex_lock(&matrix_dev->lock);
|
mutex_lock(&matrix_dev->lock);
|
||||||
|
|
||||||
/*
|
/* If the KVM guest is running, disallow assignment of control domain */
|
||||||
* If the KVM pointer is in flux or the guest is running, disallow
|
if (matrix_mdev->kvm) {
|
||||||
* assignment of control domain.
|
|
||||||
*/
|
|
||||||
if (matrix_mdev->kvm_busy || matrix_mdev->kvm) {
|
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -963,11 +938,8 @@ static ssize_t unassign_control_domain_store(struct device *dev,
|
|||||||
|
|
||||||
mutex_lock(&matrix_dev->lock);
|
mutex_lock(&matrix_dev->lock);
|
||||||
|
|
||||||
/*
|
/* If a KVM guest is running, disallow unassignment of control domain */
|
||||||
* If the KVM pointer is in flux or the guest is running, disallow
|
if (matrix_mdev->kvm) {
|
||||||
* un-assignment of control domain.
|
|
||||||
*/
|
|
||||||
if (matrix_mdev->kvm_busy || matrix_mdev->kvm) {
|
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -1108,28 +1080,30 @@ static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev,
|
|||||||
struct ap_matrix_mdev *m;
|
struct ap_matrix_mdev *m;
|
||||||
|
|
||||||
if (kvm->arch.crypto.crycbd) {
|
if (kvm->arch.crypto.crycbd) {
|
||||||
|
down_write(&kvm->arch.crypto.pqap_hook_rwsem);
|
||||||
|
kvm->arch.crypto.pqap_hook = &matrix_mdev->pqap_hook;
|
||||||
|
up_write(&kvm->arch.crypto.pqap_hook_rwsem);
|
||||||
|
|
||||||
|
mutex_lock(&kvm->lock);
|
||||||
|
mutex_lock(&matrix_dev->lock);
|
||||||
|
|
||||||
list_for_each_entry(m, &matrix_dev->mdev_list, node) {
|
list_for_each_entry(m, &matrix_dev->mdev_list, node) {
|
||||||
if (m != matrix_mdev && m->kvm == kvm)
|
if (m != matrix_mdev && m->kvm == kvm) {
|
||||||
|
mutex_unlock(&kvm->lock);
|
||||||
|
mutex_unlock(&matrix_dev->lock);
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kvm_get_kvm(kvm);
|
kvm_get_kvm(kvm);
|
||||||
matrix_mdev->kvm = kvm;
|
matrix_mdev->kvm = kvm;
|
||||||
matrix_mdev->kvm_busy = true;
|
|
||||||
mutex_unlock(&matrix_dev->lock);
|
|
||||||
|
|
||||||
down_write(&matrix_mdev->kvm->arch.crypto.pqap_hook_rwsem);
|
|
||||||
kvm->arch.crypto.pqap_hook = &matrix_mdev->pqap_hook;
|
|
||||||
up_write(&matrix_mdev->kvm->arch.crypto.pqap_hook_rwsem);
|
|
||||||
|
|
||||||
kvm_arch_crypto_set_masks(kvm,
|
kvm_arch_crypto_set_masks(kvm,
|
||||||
matrix_mdev->matrix.apm,
|
matrix_mdev->matrix.apm,
|
||||||
matrix_mdev->matrix.aqm,
|
matrix_mdev->matrix.aqm,
|
||||||
matrix_mdev->matrix.adm);
|
matrix_mdev->matrix.adm);
|
||||||
|
|
||||||
mutex_lock(&matrix_dev->lock);
|
mutex_unlock(&kvm->lock);
|
||||||
matrix_mdev->kvm_busy = false;
|
mutex_unlock(&matrix_dev->lock);
|
||||||
wake_up_all(&matrix_mdev->wait_for_kvm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1179,35 +1153,24 @@ static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb,
|
|||||||
* done under the @matrix_mdev->lock.
|
* done under the @matrix_mdev->lock.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void vfio_ap_mdev_unset_kvm(struct ap_matrix_mdev *matrix_mdev)
|
static void vfio_ap_mdev_unset_kvm(struct ap_matrix_mdev *matrix_mdev,
|
||||||
|
struct kvm *kvm)
|
||||||
{
|
{
|
||||||
/*
|
if (kvm && kvm->arch.crypto.crycbd) {
|
||||||
* If the KVM pointer is in the process of being set, wait until the
|
down_write(&kvm->arch.crypto.pqap_hook_rwsem);
|
||||||
* process has completed.
|
kvm->arch.crypto.pqap_hook = NULL;
|
||||||
*/
|
up_write(&kvm->arch.crypto.pqap_hook_rwsem);
|
||||||
wait_event_cmd(matrix_mdev->wait_for_kvm,
|
|
||||||
!matrix_mdev->kvm_busy,
|
|
||||||
mutex_unlock(&matrix_dev->lock),
|
|
||||||
mutex_lock(&matrix_dev->lock));
|
|
||||||
|
|
||||||
if (matrix_mdev->kvm) {
|
|
||||||
matrix_mdev->kvm_busy = true;
|
|
||||||
mutex_unlock(&matrix_dev->lock);
|
|
||||||
|
|
||||||
if (matrix_mdev->kvm->arch.crypto.crycbd) {
|
|
||||||
down_write(&matrix_mdev->kvm->arch.crypto.pqap_hook_rwsem);
|
|
||||||
matrix_mdev->kvm->arch.crypto.pqap_hook = NULL;
|
|
||||||
up_write(&matrix_mdev->kvm->arch.crypto.pqap_hook_rwsem);
|
|
||||||
|
|
||||||
kvm_arch_crypto_clear_masks(matrix_mdev->kvm);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
mutex_lock(&kvm->lock);
|
||||||
mutex_lock(&matrix_dev->lock);
|
mutex_lock(&matrix_dev->lock);
|
||||||
|
|
||||||
|
kvm_arch_crypto_clear_masks(kvm);
|
||||||
vfio_ap_mdev_reset_queues(matrix_mdev->mdev);
|
vfio_ap_mdev_reset_queues(matrix_mdev->mdev);
|
||||||
kvm_put_kvm(matrix_mdev->kvm);
|
kvm_put_kvm(kvm);
|
||||||
matrix_mdev->kvm = NULL;
|
matrix_mdev->kvm = NULL;
|
||||||
matrix_mdev->kvm_busy = false;
|
|
||||||
wake_up_all(&matrix_mdev->wait_for_kvm);
|
mutex_unlock(&kvm->lock);
|
||||||
|
mutex_unlock(&matrix_dev->lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1220,16 +1183,13 @@ static int vfio_ap_mdev_group_notifier(struct notifier_block *nb,
|
|||||||
if (action != VFIO_GROUP_NOTIFY_SET_KVM)
|
if (action != VFIO_GROUP_NOTIFY_SET_KVM)
|
||||||
return NOTIFY_OK;
|
return NOTIFY_OK;
|
||||||
|
|
||||||
mutex_lock(&matrix_dev->lock);
|
|
||||||
matrix_mdev = container_of(nb, struct ap_matrix_mdev, group_notifier);
|
matrix_mdev = container_of(nb, struct ap_matrix_mdev, group_notifier);
|
||||||
|
|
||||||
if (!data)
|
if (!data)
|
||||||
vfio_ap_mdev_unset_kvm(matrix_mdev);
|
vfio_ap_mdev_unset_kvm(matrix_mdev, matrix_mdev->kvm);
|
||||||
else if (vfio_ap_mdev_set_kvm(matrix_mdev, data))
|
else if (vfio_ap_mdev_set_kvm(matrix_mdev, data))
|
||||||
notify_rc = NOTIFY_DONE;
|
notify_rc = NOTIFY_DONE;
|
||||||
|
|
||||||
mutex_unlock(&matrix_dev->lock);
|
|
||||||
|
|
||||||
return notify_rc;
|
return notify_rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1363,14 +1323,11 @@ static void vfio_ap_mdev_close_device(struct mdev_device *mdev)
|
|||||||
{
|
{
|
||||||
struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
|
struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
|
||||||
|
|
||||||
mutex_lock(&matrix_dev->lock);
|
|
||||||
vfio_ap_mdev_unset_kvm(matrix_mdev);
|
|
||||||
mutex_unlock(&matrix_dev->lock);
|
|
||||||
|
|
||||||
vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
|
vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
|
||||||
&matrix_mdev->iommu_notifier);
|
&matrix_mdev->iommu_notifier);
|
||||||
vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
|
vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
|
||||||
&matrix_mdev->group_notifier);
|
&matrix_mdev->group_notifier);
|
||||||
|
vfio_ap_mdev_unset_kvm(matrix_mdev, matrix_mdev->kvm);
|
||||||
module_put(THIS_MODULE);
|
module_put(THIS_MODULE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1412,15 +1369,6 @@ static ssize_t vfio_ap_mdev_ioctl(struct mdev_device *mdev,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If the KVM pointer is in the process of being set, wait until
|
|
||||||
* the process has completed.
|
|
||||||
*/
|
|
||||||
wait_event_cmd(matrix_mdev->wait_for_kvm,
|
|
||||||
!matrix_mdev->kvm_busy,
|
|
||||||
mutex_unlock(&matrix_dev->lock),
|
|
||||||
mutex_lock(&matrix_dev->lock));
|
|
||||||
|
|
||||||
ret = vfio_ap_mdev_reset_queues(mdev);
|
ret = vfio_ap_mdev_reset_queues(mdev);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -83,8 +83,6 @@ struct ap_matrix_mdev {
|
|||||||
struct ap_matrix matrix;
|
struct ap_matrix matrix;
|
||||||
struct notifier_block group_notifier;
|
struct notifier_block group_notifier;
|
||||||
struct notifier_block iommu_notifier;
|
struct notifier_block iommu_notifier;
|
||||||
bool kvm_busy;
|
|
||||||
wait_queue_head_t wait_for_kvm;
|
|
||||||
struct kvm *kvm;
|
struct kvm *kvm;
|
||||||
crypto_hook pqap_hook;
|
crypto_hook pqap_hook;
|
||||||
struct mdev_device *mdev;
|
struct mdev_device *mdev;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user