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