[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] dom0 linux 3.6.0-rc4, crash due to ballooning althoug dom0_mem=X, max:X set



Tuesday, September 11, 2012, 6:02:47 PM, you wrote:

> On Wed, 5 Sep 2012, Konrad Rzeszutek Wilk wrote:
>> On Tue, Sep 04, 2012 at 04:27:20PM -0400, Robert Phillips wrote:
>> > Ben,
>> > 
>> > You have asked me to provide the rationale behind the gnttab_old_mfn 
>> > patch, which you emailed to Sander earlier today. 
>> > Here are my findings.
>> > 
>> > I found that xen_blkbk_map() in drivers/block/xen-blkback/blkback.c has 
>> > changed from our previous version.  It now calls gnttab_map_refs() in 
>> > drivers/xen/grant-table.c.
>> > 
>> > That function first calls 
>> > HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, ... ) and then calls 
>> > m2p_add_override() in p2m.c
>> 
>> And HYPERVISOR_grant_table_op .. would populate map_ops[i].bus_addr with the 
>> machine address..
>> 
>> > which is where I made my change.
>> > 
>> > The unpatched code was saving the pfn's old mfn in kmap_op->dev_bus_addr.  
>> > 
>> > kmap_op is of type struct gnttab_map_grant_ref.  That data type is used to 
>> > record grant table mappings so later they can be unmapped correctly.
>> 
>> Right, but the blkback makes a distinction by passing NULL as kmap_op, which 
>> means it should
>> use the old mechanism. Meaning that once the hypercall is done, the 
>> map_ops[i].bus_addr is not
>> used anymore..
>> 
>> > 
>> > The problem with saving the old mfn in kmap_op->dev_bus_addr is that it is 
>> > later overwritten by __gnttab_map_grant_ref() in xen/common/grant_table.c
>> 
>> Uh, so the problem of saving the old mfn in dev_bus_addr has been there for 
>> a long long time then?
>> Even before this patch set?

> I think that Robert identified the real problem: dev_bus_addr shouldn't
> have been used here. However the bug only shows up if we are batching
> the grant table operations, that we started doing since
> f62805f1f30a40e354bd036b4cb799863a39be4b.
> That's why Sander's bisection found that
> f62805f1f30a40e354bd036b4cb799863a39be4b is the culprit.

> However the fix is incorrect because it is modifying a struct that is
> part of the Xen ABI.
> I am appending an alternative fix that doesn't need any changes to
> public headers.

> Sander, could you please let me know if it fixes the problem for you?

It does !

Tested-By: Sander Eikelenboom <linux@xxxxxxxxxxxxxx>

> ---


> diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
> index 93971e8..472b9b7 100644
> --- a/arch/x86/include/asm/xen/page.h
> +++ b/arch/x86/include/asm/xen/page.h
> @@ -51,7 +51,8 @@ extern unsigned long set_phys_range_identity(unsigned long 
> pfn_s,
>  
>  extern int m2p_add_override(unsigned long mfn, struct page *page,
>                             struct gnttab_map_grant_ref *kmap_op);
> -extern int m2p_remove_override(struct page *page, bool clear_pte);
> +extern int m2p_remove_override(struct page *page,
> +                               struct gnttab_map_grant_ref *kmap_op);
>  extern struct page *m2p_find_override(unsigned long mfn);
>  extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long 
> pfn);
>  
> diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
> index 64effdc..2825594 100644
> --- a/arch/x86/xen/p2m.c
> +++ b/arch/x86/xen/p2m.c
> @@ -734,9 +734,6 @@ int m2p_add_override(unsigned long mfn, struct page *page,
>  
>                         xen_mc_issue(PARAVIRT_LAZY_MMU);
>                 }
> -               /* let's use dev_bus_addr to record the old mfn instead */
> -               kmap_op->dev_bus_addr = page->index;
> -               page->index = (unsigned long) kmap_op;
>         }
>         spin_lock_irqsave(&m2p_override_lock, flags);
>         list_add(&page->lru,  &m2p_overrides[mfn_hash(mfn)]);
> @@ -763,7 +760,8 @@ int m2p_add_override(unsigned long mfn, struct page *page,
>         return 0;
>  }
>  EXPORT_SYMBOL_GPL(m2p_add_override);
> -int m2p_remove_override(struct page *page, bool clear_pte)
> +int m2p_remove_override(struct page *page,
> +               struct gnttab_map_grant_ref *kmap_op)
>  {
>         unsigned long flags;
>         unsigned long mfn;
> @@ -793,10 +791,8 @@ int m2p_remove_override(struct page *page, bool 
> clear_pte)
>         WARN_ON(!PagePrivate(page));
>         ClearPagePrivate(page);
>  
> -       if (clear_pte) {
> -               struct gnttab_map_grant_ref *map_op =
> -                       (struct gnttab_map_grant_ref *) page->index;
> -               set_phys_to_machine(pfn, map_op->dev_bus_addr);
> +       set_phys_to_machine(pfn, page->index);
> +       if (kmap_op != NULL) {
>                 if (!PageHighMem(page)) {
>                         struct multicall_space mcs;
>                         struct gnttab_unmap_grant_ref *unmap_op;
> @@ -808,13 +804,13 @@ int m2p_remove_override(struct page *page, bool 
> clear_pte)
>                          * issued. In this case handle is going to -1 because
>                          * it hasn't been modified yet.
>                          */
> -                       if (map_op->handle == -1)
> +                       if (kmap_op->handle == -1)
>                                 xen_mc_flush();
>                         /*
> -                        * Now if map_op->handle is negative it means that the
> +                        * Now if kmap_op->handle is negative it means that 
> the
>                          * hypercall actually returned an error.
>                          */
> -                       if (map_op->handle == GNTST_general_error) {
> +                       if (kmap_op->handle == GNTST_general_error) {
>                                 printk(KERN_WARNING "m2p_remove_override: "
>                                                 "pfn %lx mfn %lx, failed to 
> modify kernel mappings",
>                                                 pfn, mfn);
> @@ -824,8 +820,8 @@ int m2p_remove_override(struct page *page, bool clear_pte)
>                         mcs = xen_mc_entry(
>                                         sizeof(struct 
> gnttab_unmap_grant_ref));
>                         unmap_op = mcs.args;
> -                       unmap_op->host_addr = map_op->host_addr;
> -                       unmap_op->handle = map_op->handle;
> +                       unmap_op->host_addr = kmap_op->host_addr;
> +                       unmap_op->handle = kmap_op->handle;
>                         unmap_op->dev_bus_addr = 0;
>  
>                         MULTI_grant_table_op(mcs.mc,
> @@ -836,10 +832,9 @@ int m2p_remove_override(struct page *page, bool 
> clear_pte)
>                         set_pte_at(&init_mm, address, ptep,
>                                         pfn_pte(pfn, PAGE_KERNEL));
>                         __flush_tlb_single(address);
> -                       map_op->host_addr = 0;
> +                       kmap_op->host_addr = 0;
>                 }
> -       } else
> -               set_phys_to_machine(pfn, page->index);
> +       }
>  
>         /* p2m(m2p(mfn)) == FOREIGN_FRAME(mfn): the mfn is already present
>          * somewhere in this domain, even before being added to the
> diff --git a/drivers/block/xen-blkback/blkback.c 
> b/drivers/block/xen-blkback/blkback.c
> index 73f196c..c6decb9 100644
> --- a/drivers/block/xen-blkback/blkback.c
> +++ b/drivers/block/xen-blkback/blkback.c
> @@ -337,7 +337,7 @@ static void xen_blkbk_unmap(struct pending_req *req)
>                 invcount++;
>         }
>  
> -       ret = gnttab_unmap_refs(unmap, pages, invcount, false);
> +       ret = gnttab_unmap_refs(unmap, NULL, pages, invcount);
>         BUG_ON(ret);
>  }
>  
> diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
> index 1ffd03b..7f12416 100644
> --- a/drivers/xen/gntdev.c
> +++ b/drivers/xen/gntdev.c
> @@ -314,8 +314,9 @@ static int __unmap_grant_pages(struct grant_map *map, int 
> offset, int pages)
>                 }
>         }
>  
> -       err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages + offset,
> -                               pages, true);
> +       err = gnttab_unmap_refs(map->unmap_ops + offset,
> +                       use_ptemod ? map->kmap_ops + offset : NULL, 
> map->pages + offset,
> +                       pages);
>         if (err)
>                 return err;
>  
> diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
> index 0bfc1ef..0067266 100644
> --- a/drivers/xen/grant-table.c
> +++ b/drivers/xen/grant-table.c
> @@ -870,7 +870,8 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
>  EXPORT_SYMBOL_GPL(gnttab_map_refs);
>  
>  int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
> -                     struct page **pages, unsigned int count, bool clear_pte)
> +                     struct gnttab_map_grant_ref *kmap_ops,
> +                     struct page **pages, unsigned int count)
>  {
>         int i, ret;
>         bool lazy = false;
> @@ -888,7 +889,8 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref 
> *unmap_ops,
>         }
>  
>         for (i = 0; i < count; i++) {
> -               ret = m2p_remove_override(pages[i], clear_pte);
> +               ret = m2p_remove_override(pages[i], kmap_ops ?
> +                                      &kmap_ops[i] : NULL);
>                 if (ret)
>                         return ret;
>         }
> diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h
> index 11e27c3..f19fff8 100644
> --- a/include/xen/grant_table.h
> +++ b/include/xen/grant_table.h
> @@ -187,6 +187,7 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
>                     struct gnttab_map_grant_ref *kmap_ops,
>                     struct page **pages, unsigned int count);
>  int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
> -                     struct page **pages, unsigned int count, bool 
> clear_pte);
> +                     struct gnttab_map_grant_ref *kunmap_ops,
> +                     struct page **pages, unsigned int count);
>  
>  #endif /* __ASM_GNTTAB_H__ */



_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.