On Thu, May 17, 2018 at 04:59:24PM +0800, Peter Xu wrote: [...]
> + /* Update local IOVA mapped ranges */ > + if (entry->perm) { > + if (mapped) { > + /* If it's exactly the same translation, skip */ > + if (!memcmp(mapped, &target, sizeof(target))) { > + trace_vtd_page_walk_one_skip_map(entry->iova, > entry->addr_mask, > + entry->translated_addr); > + return 0; > + } else { > + /* > + * Translation changed. This should not happen with > + * "intel_iommu=on,strict", but it can happen when > + * delayed flushing is used in guest IOMMU driver > + * (when without "strict") when page A is reused > + * before its previous unmap (the unmap can still be > + * queued in the delayed flushing queue). Now we do This comment is wrong. We can ignore above comments for now since as I explained in the other thread Linux IOVA deferred flushing won't free IOVA range until the unmap is flushed. But still, below comment is valid. Regards, > + * our best to remap. Note that there will be a small > + * window that we don't have map at all. But that's > + * the best effort we can do, and logically > + * well-behaved guests should not really using this > + * DMA region yet so we should be very safe. > + */ > + IOMMUAccessFlags cache_perm = entry->perm; > + int ret; > + > + /* Emulate an UNMAP */ > + entry->perm = IOMMU_NONE; > + trace_vtd_page_walk_one(info->domain_id, > + entry->iova, > + entry->translated_addr, > + entry->addr_mask, > + entry->perm); > + ret = hook_fn(entry, private); > + if (ret) { > + return ret; > + } > + /* Drop any existing mapping */ > + iova_tree_remove(as->iova_tree, &target); > + /* Recover the correct permission */ > + entry->perm = cache_perm; > + } > + } > + iova_tree_insert(as->iova_tree, &target); > + } else { > + if (!mapped) { > + /* Skip since we didn't map this range at all */ > + trace_vtd_page_walk_one_skip_unmap(entry->iova, > entry->addr_mask); > + return 0; > + } > + iova_tree_remove(as->iova_tree, &target); > + } > + > trace_vtd_page_walk_one(info->domain_id, entry->iova, > entry->translated_addr, entry->addr_mask, > entry->perm); -- Peter Xu