[rc,8/8] iommu/vt-d: Add missing dirty tracking set for parent domain

Message ID 20240208082307.15759-9-yi.l.liu@intel.com
State New
Headers
Series Add missing cache flush and dirty tracking set for nested parent domain |

Commit Message

Yi Liu Feb. 8, 2024, 8:23 a.m. UTC
  Setting dirty tracking for a s2 domain requires to loop all the related
devices and set the dirty tracking enable bit in the PASID table entry.
This includes the devices that are attached to the nested domains of a
s2 domain if this s2 domain is used as parent. However, the existing dirty
tracking set only loops s2 domain's own devices. It will miss dirty page
logs in the parent domain.

Now, the parent domain tracks the nested domains, so it can loop the
nested domains and the devices attached to the nested domains to ensure
dirty tracking on the parent is set completely.

Fixes: b41e38e22539 ("iommu/vt-d: Add nested domain allocation")
Signed-off-by: Yi Sun <yi.y.sun@linux.intel.com>
Signed-off-by: Yi Liu <yi.l.liu@intel.com>
---
 drivers/iommu/intel/iommu.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)
  

Comments

Tian, Kevin Feb. 8, 2024, 8:53 a.m. UTC | #1
> From: Liu, Yi L <yi.l.liu@intel.com>
> Sent: Thursday, February 8, 2024 4:23 PM
> 
> @@ -4760,6 +4790,12 @@ static int intel_iommu_set_dirty_tracking(struct
> iommu_domain *domain,
>  	if (ret)
>  		goto err_unwind;
> 
> +	if (dmar_domain->nested_parent) {
> +		ret = parent_domain_set_dirty_tracking(dmar_domain,
> enable);
> +		if (ret)
> +			goto err_unwind;
> +	}
> +

there also lack of setting dirty tracking when a device is attached to the
nested domain while the parent already has dirty-tracking enabled.

but looks even w/o nesting this is missed in the attach path.

could be fixed separately. so for this one:

Reviewed-by: Kevin Tian <kevin.tian@intel.com>
  
Yi Liu Feb. 8, 2024, 9:23 a.m. UTC | #2
On 2024/2/8 16:53, Tian, Kevin wrote:
>> From: Liu, Yi L <yi.l.liu@intel.com>
>> Sent: Thursday, February 8, 2024 4:23 PM
>>
>> @@ -4760,6 +4790,12 @@ static int intel_iommu_set_dirty_tracking(struct
>> iommu_domain *domain,
>>   	if (ret)
>>   		goto err_unwind;
>>
>> +	if (dmar_domain->nested_parent) {
>> +		ret = parent_domain_set_dirty_tracking(dmar_domain,
>> enable);
>> +		if (ret)
>> +			goto err_unwind;
>> +	}
>> +
> 
> there also lack of setting dirty tracking when a device is attached to the
> nested domain while the parent already has dirty-tracking enabled.
> 
> but looks even w/o nesting this is missed in the attach path.
> 
> could be fixed separately. so for this one:

it's fixed here. 
https://lore.kernel.org/linux-iommu/20240208091414.28133-1-yi.l.liu@intel.com/

> Reviewed-by: Kevin Tian <kevin.tian@intel.com>
  

Patch

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 7636d3f03905..b4101712a0c3 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4746,6 +4746,36 @@  device_set_dirty_tracking(struct list_head *devices, bool enable)
 	return ret;
 }
 
+static int
+parent_domain_set_dirty_tracking(struct dmar_domain *domain,
+				 bool enable)
+{
+	struct dmar_domain *s1_domain;
+	unsigned long flags;
+	int ret;
+
+	spin_lock(&domain->s1_lock);
+	list_for_each_entry(s1_domain, &domain->s1_domains, s2_link) {
+		spin_lock_irqsave(&s1_domain->lock, flags);
+		ret = device_set_dirty_tracking(&s1_domain->devices, enable);
+		spin_unlock_irqrestore(&s1_domain->lock, flags);
+		if (ret)
+			goto err_unwind;
+	}
+	spin_unlock(&domain->s1_lock);
+	return 0;
+
+err_unwind:
+	list_for_each_entry(s1_domain, &domain->s1_domains, s2_link) {
+		spin_lock_irqsave(&s1_domain->lock, flags);
+		device_set_dirty_tracking(&s1_domain->devices,
+					  domain->dirty_tracking);
+		spin_unlock_irqrestore(&s1_domain->lock, flags);
+	}
+	spin_unlock(&domain->s1_lock);
+	return ret;
+}
+
 static int intel_iommu_set_dirty_tracking(struct iommu_domain *domain,
 					  bool enable)
 {
@@ -4760,6 +4790,12 @@  static int intel_iommu_set_dirty_tracking(struct iommu_domain *domain,
 	if (ret)
 		goto err_unwind;
 
+	if (dmar_domain->nested_parent) {
+		ret = parent_domain_set_dirty_tracking(dmar_domain, enable);
+		if (ret)
+			goto err_unwind;
+	}
+
 	dmar_domain->dirty_tracking = enable;
 out_unlock:
 	spin_unlock(&dmar_domain->lock);