bool dirty_tracking = flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
        bool nested_parent = flags & IOMMU_HWPT_ALLOC_NEST_PARENT;
        struct intel_iommu *iommu = info->iommu;
+       struct dmar_domain *dmar_domain;
        struct iommu_domain *domain;
 
        /* Must be NESTING domain */
        if (!domain)
                return ERR_PTR(-ENOMEM);
 
-       if (nested_parent)
-               to_dmar_domain(domain)->nested_parent = true;
+       dmar_domain = to_dmar_domain(domain);
+
+       if (nested_parent) {
+               dmar_domain->nested_parent = true;
+               INIT_LIST_HEAD(&dmar_domain->s1_domains);
+               spin_lock_init(&dmar_domain->s1_lock);
+       }
 
        if (dirty_tracking) {
-               if (to_dmar_domain(domain)->use_first_level) {
+               if (dmar_domain->use_first_level) {
                        iommu_domain_free(domain);
                        return ERR_PTR(-EOPNOTSUPP);
                }
 
 static void intel_iommu_domain_free(struct iommu_domain *domain)
 {
+       struct dmar_domain *dmar_domain = to_dmar_domain(domain);
+
+       WARN_ON(dmar_domain->nested_parent &&
+               !list_empty(&dmar_domain->s1_domains));
        if (domain != &si_domain->domain)
-               domain_exit(to_dmar_domain(domain));
+               domain_exit(dmar_domain);
 }
 
 int prepare_domain_attach_device(struct iommu_domain *domain,
 
                        int             agaw;
                        /* maximum mapped address */
                        u64             max_addr;
+                       /* Protect the s1_domains list */
+                       spinlock_t      s1_lock;
+                       /* Track s1_domains nested on this domain */
+                       struct list_head s1_domains;
                };
 
                /* Nested user domain */
                        unsigned long s1_pgtbl;
                        /* page table attributes */
                        struct iommu_hwpt_vtd_s1 s1_cfg;
+                       /* link to parent domain siblings */
+                       struct list_head s2_link;
                };
        };
 
 
 
 static void intel_nested_domain_free(struct iommu_domain *domain)
 {
-       kfree(to_dmar_domain(domain));
+       struct dmar_domain *dmar_domain = to_dmar_domain(domain);
+       struct dmar_domain *s2_domain = dmar_domain->s2_domain;
+
+       spin_lock(&s2_domain->s1_lock);
+       list_del(&dmar_domain->s2_link);
+       spin_unlock(&s2_domain->s1_lock);
+       kfree(dmar_domain);
 }
 
 static void nested_flush_dev_iotlb(struct dmar_domain *domain, u64 addr,
        spin_lock_init(&domain->lock);
        xa_init(&domain->iommu_array);
 
+       spin_lock(&s2_domain->s1_lock);
+       list_add(&domain->s2_link, &s2_domain->s1_domains);
+       spin_unlock(&s2_domain->s1_lock);
+
        return &domain->domain;
 }