]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'for-linus-20151021' of git://git.infradead.org/intel-iommu
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 21 Oct 2015 21:32:48 +0000 (06:32 +0900)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 21 Oct 2015 21:32:48 +0000 (06:32 +0900)
Pull intel-iommu bugfix from David Woodhouse:
 "This contains a single fix, for when the IOMMU API is used to overlay
  an existing mapping comprised of 4KiB pages, with a mapping that can
  use superpages.

  For the *first* superpage in the new mapping, we were correctly¹
  freeing the old bottom-level page table page and clearing the link to
  it, before installing the superpage.  For subsequent superpages,
  however, we weren't.  This causes a memory leak, and a warning about
  setting a PTE which is already set.

  ¹ Well, not *entirely* correctly.  We just free the page table pages
    right there and then, which is wrong.  In fact they should only be
    freed *after* the IOTLB is flushed so we know the hardware will no
    longer be looking at them....  and in fact I note that the IOTLB
    flush is completely missing from the intel_iommu_map() code path,
    although it needs to be there if it's permitted to overwrite
    existing mappings.

    Fixing those is somewhat more intrusive though, and will probably
    need to wait for 4.4 at this point"

* tag 'for-linus-20151021' of git://git.infradead.org/intel-iommu:
  iommu/vt-d: fix range computation when making room for large pages

1  2 
drivers/iommu/intel-iommu.c

index 35365f046923db7df50f43f318310711e7fd5e31,df53855a5f3ebd4cf640ca2f814f3ab2f252b5e9..d65cf42399e8e5aa0f856a1ab6869c041adc0c48
@@@ -2115,15 -2115,19 +2115,19 @@@ static int __domain_mapping(struct dmar
                                return -ENOMEM;
                        /* It is large page*/
                        if (largepage_lvl > 1) {
+                               unsigned long nr_superpages, end_pfn;
                                pteval |= DMA_PTE_LARGE_PAGE;
                                lvl_pages = lvl_to_nr_pages(largepage_lvl);
+                               nr_superpages = sg_res / lvl_pages;
+                               end_pfn = iov_pfn + nr_superpages * lvl_pages - 1;
                                /*
                                 * Ensure that old small page tables are
-                                * removed to make room for superpage,
-                                * if they exist.
+                                * removed to make room for superpage(s).
                                 */
-                               dma_pte_free_pagetable(domain, iov_pfn,
-                                                      iov_pfn + lvl_pages - 1);
+                               dma_pte_free_pagetable(domain, iov_pfn, end_pfn);
                        } else {
                                pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
                        }
@@@ -2301,7 -2305,6 +2305,7 @@@ static struct dmar_domain *dmar_insert_
  
        if (ret) {
                spin_unlock_irqrestore(&device_domain_lock, flags);
 +              free_devinfo_mem(info);
                return NULL;
        }