WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

Re: [Xen-devel] [2/3] [LINUX] gnttab: Add basic DMA tracking

To: Isaku Yamahata <yamahata@xxxxxxxxxxxxx>
Subject: Re: [Xen-devel] [2/3] [LINUX] gnttab: Add basic DMA tracking
From: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>
Date: Wed, 6 Jun 2007 18:37:36 +1000
Cc: Xen Development Mailing List <xen-devel@xxxxxxxxxxxxxxxxxxx>, Keir Fraser <keir@xxxxxxxxxxxxx>
Delivery-date: Wed, 06 Jun 2007 01:35:57 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
In-reply-to: <20070606061829.GD1872%yamahata@xxxxxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <20070529045509.GA1983@xxxxxxxxxxxxxxxxxxx> <20070529045528.GA2025@xxxxxxxxxxxxxxxxxxx> <20070606061829.GD1872%yamahata@xxxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mutt/1.5.9i
On Wed, Jun 06, 2007 at 03:18:29PM +0900, Isaku Yamahata wrote:
> 
> This patch treats maddr_t as same as dma_addr_t.

Thanks I'll look into this.
 
> > diff -r 3ef0510e44d0 linux-2.6-xen-sparse/arch/i386/kernel/pci-dma-xen.c
> > --- a/linux-2.6-xen-sparse/arch/i386/kernel/pci-dma-xen.c   Tue May 08 
> > 10:21:23 2007 +0100
> > +++ b/linux-2.6-xen-sparse/arch/i386/kernel/pci-dma-xen.c   Wed May 16 
> > 22:31:20 2007 +1000
>    [snip]
> > @@ -326,7 +335,8 @@ dma_map_single(struct device *dev, void 
> >     if (swiotlb) {
> >             dma = swiotlb_map_single(dev, ptr, size, direction);
> >     } else {
> > -           dma = virt_to_bus(ptr);
> > +           dma = gnttab_dma_map_page(virt_to_page(ptr)) +
> > +                 offset_in_page(ptr);
> >             IOMMU_BUG_ON(range_straddles_page_boundary(ptr, size));
> >             IOMMU_BUG_ON(address_needs_mapping(dev, dma));
> >     }
> > @@ -344,6 +354,8 @@ dma_unmap_single(struct device *dev, dma
> >             BUG();
> >     if (swiotlb)
> >             swiotlb_unmap_single(dev, dma_addr, size, direction);
> > +   else
> > +           gnttab_dma_unmap_page(dma_addr);
> >  }
> >  EXPORT_SYMBOL(dma_unmap_single);
> 
> Is it assumed that size <= PAGE_SIZE?
> Or should we iterate on the pointer with PAGE_SIZE?
> Am I missing anything else?

In this case it's a BUG if the entry crosses a page boundary.

> > diff -r 3ef0510e44d0 linux-2.6-xen-sparse/arch/i386/kernel/swiotlb.c
> > --- a/linux-2.6-xen-sparse/arch/i386/kernel/swiotlb.c       Tue May 08 
> > 10:21:23 2007 +0100
> > +++ b/linux-2.6-xen-sparse/arch/i386/kernel/swiotlb.c       Wed May 16 
> > 22:31:20 2007 +1000
>    ...
> > @@ -468,7 +467,8 @@ dma_addr_t
> >  dma_addr_t
> >  swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
> >  {
> > -   dma_addr_t dev_addr = virt_to_bus(ptr);
> > +   dma_addr_t dev_addr = gnttab_dma_map_page(virt_to_page(ptr)) +
> > +                         offset_in_page(ptr);
> >     void *map;
> >     struct phys_addr buffer;
> >  
> > @@ -486,6 +486,7 @@ swiotlb_map_single(struct device *hwdev,
> >     /*
> >      * Oh well, have to allocate and map a bounce buffer.
> >      */
> > +   gnttab_dma_unmap_page(dev_addr);
> >     buffer.page   = virt_to_page(ptr);
> >     buffer.offset = (unsigned long)ptr & ~PAGE_MASK;
> >     map = map_single(hwdev, buffer, size, dir);
> > @@ -513,6 +514,8 @@ swiotlb_unmap_single(struct device *hwde
> >     BUG_ON(dir == DMA_NONE);
> >     if (in_swiotlb_aperture(dev_addr))
> >             unmap_single(hwdev, bus_to_virt(dev_addr), size, dir);
> > +   else
> > +           gnttab_dma_unmap_page(dev_addr);
> >  }
> 
> Ditto.

It either crosses a page boundary, in which case we use the bounce
buffer, or it doesn't and this works fine.

> > +/*
> > + * Must not be called with IRQs off.  This should only be used on the
> > + * slow path.
> > + *
> > + * Copy a foreign granted page to local memory.
> > + */
> > +int gnttab_copy_grant_page(grant_ref_t ref, struct page **pagep)
> > +{
> > +   struct gnttab_unmap_and_replace unmap;
> > +   mmu_update_t mmu;
> > +   struct page *page;
> > +   struct page *new_page;
> > +   void *new_addr;
> > +   void *addr;
> > +   paddr_t pfn;
> > +   maddr_t mfn;
> > +   maddr_t new_mfn;
> > +   int err;
> > +
> > +   page = *pagep;
> > +   if (!get_page_unless_zero(page))
> > +           return -ENOENT;
> > +
> > +   err = -ENOMEM;
> > +   new_page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
> > +   if (!new_page)
> > +           goto out;
> > +
> > +   new_addr = page_address(new_page);
> > +   addr = page_address(page);
> > +   memcpy(new_addr, addr, PAGE_SIZE);
> > +
> > +   pfn = page_to_pfn(page);
> > +   mfn = pfn_to_mfn(pfn);
> > +   new_mfn = virt_to_mfn(new_addr);
> > +
> > +   if (!xen_feature(XENFEAT_auto_translated_physmap)) {
> > +           set_phys_to_machine(pfn, new_mfn);
> > +           set_phys_to_machine(page_to_pfn(new_page), INVALID_P2M_ENTRY);
> > +
> > +           mmu.ptr = (new_mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
> > +           mmu.val = pfn;
> > +           err = HYPERVISOR_mmu_update(&mmu, 1, NULL, DOMID_SELF);
> > +           BUG_ON(err);
> > +   }
> > +
> > +   gnttab_set_replace_op(&unmap, (unsigned long)addr,
> > +                         (unsigned long)new_addr, ref);
> > +
> > +   err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
> > +                                   &unmap, 1);
> > +   BUG_ON(err);
> > +   BUG_ON(unmap.status);
> > +
> > +   new_page->mapping = page->mapping;
> > +   new_page->index = page->index;
> > +   set_bit(PG_foreign, &new_page->flags);
> > +   *pagep = new_page;
> > +
> > +   SetPageForeign(page, gnttab_page_free);
> > +   page->mapping = NULL;
> > +
> > +   /*
> > +    * Ensure that there is a barrier between setting the p2m entry
> > +    * and checking the map count.  See gnttab_dma_map_page.
> > +    */
> > +   smp_mb();
> > +
> > +   /* Has the page been DMA-mapped? */
> > +   if (unlikely(page_mapped(page))) {
> > +           err = -EBUSY;
> > +           page->mapping = (void *)new_page;
> 
> While DMA might be going on. the grant table mapped page is unmapped here.
> Since the page isn't referenced by this backend domain from the xen VMM
> point of view, the front end domain can be destroyed. (e.g. by xm destroy)
> So the page can be freed and reused for other purpose even though
> DMA is still being processed.
> The new user of the page (probably another domain) can be upset.
> Is this true?

Good catch.  If the frontend freed the page we'd be in trouble.  I suppose
we need a better solution.

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@xxxxxxxxxxxxxxxxxxx>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel