Re: [PATCH v3 2/4] KVM: arm64: vgic-its: Clear DTE when MAPD unmaps a device

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 06 Nov 2024 08:30:33 +0000,
Jing Zhang <jingzhangos@xxxxxxxxxx> wrote:
> 
> From: Kunkun Jiang <jiangkunkun@xxxxxxxxxx>
> 
> vgic_its_save_device_tables will traverse its->device_list to
> save DTE for each device. vgic_its_restore_device_tables will
> traverse each entry of device table and check if it is valid.
> Restore if valid.
> 
> But when MAPD unmaps a device, it does not invalidate the
> corresponding DTE. In the scenario of continuous saves
> and restores, there may be a situation where a device's DTE
> is not saved but is restored. This is unreasonable and may
> cause restore to fail. This patch clears the corresponding
> DTE when MAPD unmaps a device.
> 
> Co-developed-by: Shusen Li <lishusen2@xxxxxxxxxx>
> Signed-off-by: Shusen Li <lishusen2@xxxxxxxxxx>
> Signed-off-by: Kunkun Jiang <jiangkunkun@xxxxxxxxxx>
> Signed-off-by: Jing Zhang <jingzhangos@xxxxxxxxxx>
> ---
>  arch/arm64/kvm/vgic/vgic-its.c | 14 ++++++++++++--
>  1 file changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
> index 2381bc5ce544..7c57c7c6fbff 100644
> --- a/arch/arm64/kvm/vgic/vgic-its.c
> +++ b/arch/arm64/kvm/vgic/vgic-its.c
> @@ -1140,8 +1140,9 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
>  	u8 num_eventid_bits = its_cmd_get_size(its_cmd);
>  	gpa_t itt_addr = its_cmd_get_ittaddr(its_cmd);
>  	struct its_device *device;
> +	gpa_t gpa;
>  
> -	if (!vgic_its_check_id(its, its->baser_device_table, device_id, NULL))
> +	if (!vgic_its_check_id(its, its->baser_device_table, device_id, &gpa))
>  		return E_ITS_MAPD_DEVICE_OOR;
>  
>  	if (valid && num_eventid_bits > VITS_TYPER_IDBITS)
> @@ -1161,8 +1162,17 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
>  	 * The spec does not say whether unmapping a not-mapped device
>  	 * is an error, so we are done in any case.
>  	 */
> -	if (!valid)
> +	if (!valid) {
> +		struct kvm *kvm = its->dev->kvm;
> +		int dte_esz = vgic_its_get_abi(its)->dte_esz;
> +		u64 val = 0;
> +
> +		if (KVM_BUG_ON(dte_esz != sizeof(val), kvm))
> +			return -EINVAL;

I find it pretty odd to bug only in that case, and the sprinkling of
these checks all over the place is horrible. I'm starting to wonder if
we shouldn't simply wrap vgic_write_guest() and co to do the checking.

> +
> +		vgic_write_guest_lock(kvm, gpa, &val, dte_esz);

I'm thinking of something like:

diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
index ba945ba78cc7d..d8e57aefcd3a5 100644
--- a/arch/arm64/kvm/vgic/vgic-its.c
+++ b/arch/arm64/kvm/vgic/vgic-its.c
@@ -1128,6 +1128,19 @@ static struct its_device *vgic_its_alloc_device(struct vgic_its *its,
 	return device;
 }
 
+
+#define its_write_entry_lock(i, g, valp, t)				\
+	({								\
+		struct kvm *__k = (i)->dev->kvm;			\
+		int __sz = vgic_its_get_abi(i)->t;			\
+		int __ret = 0;						\
+		if (KVM_BUG_ON(__sz != sizeof(*(valp)), __k))		\
+			__ret = -EINVAL;				\
+		else							\
+			vgic_write_guest_lock(__k, (g), (valp), __sz);	\
+		__ret;							\
+	})
+
 /*
  * MAPD maps or unmaps a device ID to Interrupt Translation Tables (ITTs).
  * Must be called with the its_lock mutex held.
@@ -1140,8 +1153,9 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
 	u8 num_eventid_bits = its_cmd_get_size(its_cmd);
 	gpa_t itt_addr = its_cmd_get_ittaddr(its_cmd);
 	struct its_device *device;
+	gpa_t gpa;
 
-	if (!vgic_its_check_id(its, its->baser_device_table, device_id, NULL))
+	if (!vgic_its_check_id(its, its->baser_device_table, device_id, &gpa))
 		return E_ITS_MAPD_DEVICE_OOR;
 
 	if (valid && num_eventid_bits > VITS_TYPER_IDBITS)
@@ -1161,8 +1175,10 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
 	 * The spec does not say whether unmapping a not-mapped device
 	 * is an error, so we are done in any case.
 	 */
-	if (!valid)
-		return 0;
+	if (!valid) {
+		u64 val = 0;
+		return its_write_entry_lock(its, gpa, &val, dte_esz);
+	}
 
 	device = vgic_its_alloc_device(its, device_id, itt_addr,
 				       num_eventid_bits);

which can be generalised everywhere (you can even extract the check
and move it to an out-of-line helper as required).

	M.

-- 
Without deviation from the norm, progress is not possible.




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux