Stefano Stabellini
2011-Sep-29 10:56 UTC
[Xen-devel] [PATCH v5 0/2] xen: modify kernel mappings corresponding to granted pages
Hi all, this is the fifth version of the patch "xen: modify kernel mappings corresponding to granted pages": changes to v4: - add many more comments to the code; - fix some code style issues; - use set_page_private/page_private macros; - compare with GNTST_general_error rather than -1; - BUG in case map->pages are highmem; Changes to v3: - move the xen_mc_entry call in m2p_remove_override after the xen_mc_flush call; - use false rather than 0 as a parameter to alloc_xenballooned_pages; - update the m2p_add_override call in blkback.c, following the new interface; - fix few code style issues. Changes to v2: - drop highmem support; - fold the multicall patch into the main patch; - add another patch to extend the alloc_xenballooned_pages interface with an highmem parameter that allows the caller to explicitly request for highmem or lowmem pages; - modify gntdev to use lowmem pages only thanks to the new alloc_xenballooned_pages interface. Shortlog and diffstat follow: Stefano Stabellini (2): xen: add an "highmem" parameter to alloc_xenballooned_pages xen: modify kernel mappings corresponding to granted pages arch/x86/include/asm/xen/page.h | 5 ++- arch/x86/xen/p2m.c | 79 ++++++++++++++++++++++++++++++----- drivers/block/xen-blkback/blkback.c | 2 +- drivers/xen/balloon.c | 12 ++++-- drivers/xen/gntdev.c | 34 ++++++++++++++- drivers/xen/grant-table.c | 6 +- include/xen/balloon.h | 5 +- include/xen/grant_table.h | 1 + 8 files changed, 120 insertions(+), 24 deletions(-) A git branch with the two patches on top of Konrad''s "Xen MMU fixes for 3.2" patch series (1316831299-4144-1-git-send-email-konrad.wilk@oracle.com) on top of Linux 3.1 rc4 is available here: git://xenbits.xen.org/people/sstabellini/linux-pvhvm.git 3.1-rc4-kernel_mappings_5 Cheers, Stefano _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
<stefano.stabellini@eu.citrix.com>
2011-Sep-29 10:57 UTC
[Xen-devel] [PATCH v5 1/2] xen: add an "highmem" parameter to alloc_xenballooned_pages
From: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Add an highmem parameter to alloc_xenballooned_pages, to allow callers to request lowmem or highmem pages. Fix the code style of free_xenballooned_pages'' prototype. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- drivers/xen/balloon.c | 12 ++++++++---- drivers/xen/gntdev.c | 2 +- include/xen/balloon.h | 5 +++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 5dfd8f8..cd8b470 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -501,20 +501,24 @@ EXPORT_SYMBOL_GPL(balloon_set_new_target); * alloc_xenballooned_pages - get pages that have been ballooned out * @nr_pages: Number of pages to get * @pages: pages returned + * @highmem: highmem or lowmem pages * @return 0 on success, error otherwise */ -int alloc_xenballooned_pages(int nr_pages, struct page** pages) +int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem) { int pgno = 0; struct page* page; mutex_lock(&balloon_mutex); while (pgno < nr_pages) { - page = balloon_retrieve(true); - if (page) { + page = balloon_retrieve(highmem); + if (page && PageHighMem(page) == highmem) { pages[pgno++] = page; } else { enum bp_state st; - st = decrease_reservation(nr_pages - pgno, GFP_HIGHUSER); + if (page) + balloon_append(page); + st = decrease_reservation(nr_pages - pgno, + highmem ? GFP_HIGHUSER : GFP_USER); if (st != BP_DONE) goto out_undo; } diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index f914b26..7b9b1d1 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -123,7 +123,7 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) NULL == add->pages) goto err; - if (alloc_xenballooned_pages(count, add->pages)) + if (alloc_xenballooned_pages(count, add->pages, false /* lowmem */)) goto err; for (i = 0; i < count; i++) { diff --git a/include/xen/balloon.h b/include/xen/balloon.h index 76f7538..d29c153 100644 --- a/include/xen/balloon.h +++ b/include/xen/balloon.h @@ -25,8 +25,9 @@ extern struct balloon_stats balloon_stats; void balloon_set_new_target(unsigned long target); -int alloc_xenballooned_pages(int nr_pages, struct page** pages); -void free_xenballooned_pages(int nr_pages, struct page** pages); +int alloc_xenballooned_pages(int nr_pages, struct page **pages, + bool highmem); +void free_xenballooned_pages(int nr_pages, struct page **pages); struct sys_device; #ifdef CONFIG_XEN_SELFBALLOONING -- 1.7.2.3 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
<stefano.stabellini@eu.citrix.com>
2011-Sep-29 10:57 UTC
[Xen-devel] [PATCH v5 2/2] xen: modify kernel mappings corresponding to granted pages
From: Stefano Stabellini <stefano.stabellini@eu.citrix.com> If we want to use granted pages for AIO, changing the mappings of a user vma and the corresponding p2m is not enough, we also need to update the kernel mappings accordingly. Currently this is only needed for pages that are created for user usages through /dev/xen/gntdev. As in, pages that have been in use by the kernel and use the P2M will not need this special mapping. However there are no guarantees that in the future the kernel won''t start accessing pages through the 1:1 even for internal usage. In order to avoid the complexity of dealing with highmem, we allocated the pages lowmem. We issue a HYPERVISOR_grant_table_op right away in m2p_add_override and we remove the mappings using another HYPERVISOR_grant_table_op in m2p_remove_override. Considering that m2p_add_override and m2p_remove_override are called once per page we use multicalls and hypercall batching. Use the kmap_op pointer directly as argument to do the mapping as it is guaranteed to be present up until the unmapping is done. Before issuing any unmapping multicalls, we need to make sure that the mapping has already being done, because we need the kmap->handle to be set correctly. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- arch/x86/include/asm/xen/page.h | 5 ++- arch/x86/xen/p2m.c | 79 ++++++++++++++++++++++++++++++----- drivers/block/xen-blkback/blkback.c | 2 +- drivers/xen/gntdev.c | 32 ++++++++++++++- drivers/xen/grant-table.c | 6 +- include/xen/grant_table.h | 1 + 6 files changed, 108 insertions(+), 17 deletions(-) diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index e1dc8e6..37d3185 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -12,6 +12,7 @@ #include <asm/pgtable.h> #include <xen/interface/xen.h> +#include <xen/grant_table.h> #include <xen/features.h> /* Xen machine address */ @@ -31,8 +32,10 @@ typedef struct xpaddr { #define INVALID_P2M_ENTRY (~0UL) #define FOREIGN_FRAME_BIT (1UL<<(BITS_PER_LONG-1)) #define IDENTITY_FRAME_BIT (1UL<<(BITS_PER_LONG-2)) +#define GRANT_FRAME_BIT (1UL<<(BITS_PER_LONG-3)) #define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT) #define IDENTITY_FRAME(m) ((m) | IDENTITY_FRAME_BIT) +#define GRANT_FRAME(m) ((m) | GRANT_FRAME_BIT) /* Maximum amount of memory we can handle in a domain in pages */ #define MAX_DOMAIN_PAGES \ @@ -48,7 +51,7 @@ extern unsigned long set_phys_range_identity(unsigned long pfn_s, unsigned long pfn_e); extern int m2p_add_override(unsigned long mfn, struct page *page, - bool clear_pte); + struct gnttab_map_grant_ref *kmap_op); extern int m2p_remove_override(struct page *page, bool clear_pte); 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 6e56b65..5857ef0 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -161,7 +161,9 @@ #include <asm/xen/page.h> #include <asm/xen/hypercall.h> #include <asm/xen/hypervisor.h> +#include <xen/grant_table.h> +#include "multicalls.h" #include "xen-ops.h" static void __init m2p_override_init(void); @@ -676,7 +678,8 @@ static unsigned long mfn_hash(unsigned long mfn) } /* Add an MFN override for a particular page */ -int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte) +int m2p_add_override(unsigned long mfn, struct page *page, + struct gnttab_map_grant_ref *kmap_op) { unsigned long flags; unsigned long pfn; @@ -700,9 +703,21 @@ int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte) if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) return -ENOMEM; - if (clear_pte && !PageHighMem(page)) - /* Just zap old mapping for now */ - pte_clear(&init_mm, address, ptep); + if (kmap_op != NULL) { + if (!PageHighMem(page)) { + struct multicall_space mcs + xen_mc_entry(sizeof(*kmap_op)); + + MULTI_grant_table_op(mcs.mc, + GNTTABOP_map_grant_ref, kmap_op, 1); + + xen_mc_issue(PARAVIRT_LAZY_MMU); + } + set_page_private(page, page_private(page) | GRANT_FRAME_BIT); + /* 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)]); spin_unlock_irqrestore(&m2p_override_lock, flags); @@ -736,14 +751,56 @@ int m2p_remove_override(struct page *page, bool clear_pte) spin_lock_irqsave(&m2p_override_lock, flags); list_del(&page->lru); spin_unlock_irqrestore(&m2p_override_lock, flags); - set_phys_to_machine(pfn, page->index); WARN_ON(!PagePrivate(page)); ClearPagePrivate(page); - if (clear_pte && !PageHighMem(page)) - set_pte_at(&init_mm, address, ptep, - pfn_pte(pfn, PAGE_KERNEL)); - /* No tlb flush necessary because the caller already - * left the pte unmapped. */ + + 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); + if (!PageHighMem(page)) { + struct multicall_space mcs; + struct gnttab_unmap_grant_ref *unmap_op; + + /* + * It might be that we queued all the m2p grant table + * hypercalls in a multicall, then m2p_remove_override + * get called before the multicall has actually been + * issued. In this case handle is going to -1 because + * it hasn''t been modified yet. + */ + if (map_op->handle == -1) + xen_mc_flush(); + /* + * Now if map_op->handle is negative it means that the + * hypercall actually returned an error. + */ + if (map_op->handle == GNTST_general_error) { + printk(KERN_WARNING "m2p_remove_override: " + "pfn %lx mfn %lx, failed to modify kernel mappings", + pfn, mfn); + return -1; + } + + 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->dev_bus_addr = 0; + + MULTI_grant_table_op(mcs.mc, + GNTTABOP_unmap_grant_ref, unmap_op, 1); + + xen_mc_issue(PARAVIRT_LAZY_MMU); + + set_pte_at(&init_mm, address, ptep, + pfn_pte(pfn, PAGE_KERNEL)); + __flush_tlb_single(address); + map_op->host_addr = 0; + } + } else + set_phys_to_machine(pfn, page->index); return 0; } @@ -760,7 +817,7 @@ struct page *m2p_find_override(unsigned long mfn) spin_lock_irqsave(&m2p_override_lock, flags); list_for_each_entry(p, bucket, lru) { - if (page_private(p) == mfn) { + if ((page_private(p) & (~GRANT_FRAME_BIT)) == mfn) { ret = p; break; } diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 2330a9a..1540792 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -396,7 +396,7 @@ static int xen_blkbk_map(struct blkif_request *req, continue; ret = m2p_add_override(PFN_DOWN(map[i].dev_bus_addr), - blkbk->pending_page(pending_req, i), false); + blkbk->pending_page(pending_req, i), NULL); if (ret) { pr_alert(DRV_PFX "Failed to install M2P override for %lx (ret: %d)\n", (unsigned long)map[i].dev_bus_addr, ret); diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 7b9b1d1..3e3603f 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -83,6 +83,7 @@ struct grant_map { struct ioctl_gntdev_grant_ref *grants; struct gnttab_map_grant_ref *map_ops; struct gnttab_unmap_grant_ref *unmap_ops; + struct gnttab_map_grant_ref *kmap_ops; struct page **pages; }; @@ -116,10 +117,12 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) add->grants = kzalloc(sizeof(add->grants[0]) * count, GFP_KERNEL); add->map_ops = kzalloc(sizeof(add->map_ops[0]) * count, GFP_KERNEL); add->unmap_ops = kzalloc(sizeof(add->unmap_ops[0]) * count, GFP_KERNEL); + add->kmap_ops = kzalloc(sizeof(add->kmap_ops[0]) * count, GFP_KERNEL); add->pages = kzalloc(sizeof(add->pages[0]) * count, GFP_KERNEL); if (NULL == add->grants || NULL == add->map_ops || NULL == add->unmap_ops || + NULL == add->kmap_ops || NULL == add->pages) goto err; @@ -129,6 +132,7 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) for (i = 0; i < count; i++) { add->map_ops[i].handle = -1; add->unmap_ops[i].handle = -1; + add->kmap_ops[i].handle = -1; } add->index = 0; @@ -142,6 +146,7 @@ err: kfree(add->grants); kfree(add->map_ops); kfree(add->unmap_ops); + kfree(add->kmap_ops); kfree(add); return NULL; } @@ -243,10 +248,35 @@ static int map_grant_pages(struct grant_map *map) gnttab_set_unmap_op(&map->unmap_ops[i], addr, map->flags, -1 /* handle */); } + } else { + /* + * Setup the map_ops corresponding to the pte entries pointing + * to the kernel linear addresses of the struct pages. + * These ptes are completely different from the user ptes dealt + * with find_grant_ptes. + */ + for (i = 0; i < map->count; i++) { + unsigned level; + unsigned long address = (unsigned long) + pfn_to_kaddr(page_to_pfn(map->pages[i])); + pte_t *ptep; + u64 pte_maddr = 0; + BUG_ON(PageHighMem(map->pages[i])); + + ptep = lookup_address(address, &level); + pte_maddr = arbitrary_virt_to_machine(ptep).maddr; + gnttab_set_map_op(&map->kmap_ops[i], pte_maddr, + map->flags | + GNTMAP_host_map | + GNTMAP_contains_pte, + map->grants[i].ref, + map->grants[i].domid); + } } pr_debug("map %d+%d\n", map->index, map->count); - err = gnttab_map_refs(map->map_ops, map->pages, map->count); + err = gnttab_map_refs(map->map_ops, use_ptemod ? map->kmap_ops : NULL, + map->pages, map->count); if (err) return err; diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 4f44b34..8c71ab8 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -448,7 +448,8 @@ unsigned int gnttab_max_grant_frames(void) EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, - struct page **pages, unsigned int count) + struct gnttab_map_grant_ref *kmap_ops, + struct page **pages, unsigned int count) { int i, ret; pte_t *pte; @@ -488,8 +489,7 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, */ return -EOPNOTSUPP; } - ret = m2p_add_override(mfn, pages[i], - map_ops[i].flags & GNTMAP_contains_pte); + ret = m2p_add_override(mfn, pages[i], &kmap_ops[i]); if (ret) return ret; } diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h index b1fab6b..6b99bfb 100644 --- a/include/xen/grant_table.h +++ b/include/xen/grant_table.h @@ -156,6 +156,7 @@ unsigned int gnttab_max_grant_frames(void); #define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr)) 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); -- 1.7.2.3 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Konrad Rzeszutek Wilk
2011-Sep-29 13:55 UTC
Re: [Xen-devel] [PATCH v5 2/2] xen: modify kernel mappings corresponding to granted pages
> /* Xen machine address */ > @@ -31,8 +32,10 @@ typedef struct xpaddr { > #define INVALID_P2M_ENTRY (~0UL) > #define FOREIGN_FRAME_BIT (1UL<<(BITS_PER_LONG-1)) > #define IDENTITY_FRAME_BIT (1UL<<(BITS_PER_LONG-2)) > +#define GRANT_FRAME_BIT (1UL<<(BITS_PER_LONG-3))I am going to change that to (BITS_PER_LONG-1) as we aren''t using the P2M. (and add that comment in the file). And both patches are now in 3.2 queue. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2011-Sep-29 13:58 UTC
Re: [Xen-devel] [PATCH v5 2/2] xen: modify kernel mappings corresponding to granted pages
On Thu, 29 Sep 2011, Konrad Rzeszutek Wilk wrote:> > /* Xen machine address */ > > @@ -31,8 +32,10 @@ typedef struct xpaddr { > > #define INVALID_P2M_ENTRY (~0UL) > > #define FOREIGN_FRAME_BIT (1UL<<(BITS_PER_LONG-1)) > > #define IDENTITY_FRAME_BIT (1UL<<(BITS_PER_LONG-2)) > > +#define GRANT_FRAME_BIT (1UL<<(BITS_PER_LONG-3)) > > I am going to change that to (BITS_PER_LONG-1) as we aren''t > using the P2M. (and add that comment in the file). > > And both patches are now in 3.2 queue.OK, thanks. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2011-Sep-29 14:18 UTC
Re: [Xen-devel] [PATCH v5 2/2] xen: modify kernel mappings corresponding to granted pages
On Thu, 2011-09-29 at 14:55 +0100, Konrad Rzeszutek Wilk wrote:> > /* Xen machine address */ > > @@ -31,8 +32,10 @@ typedef struct xpaddr { > > #define INVALID_P2M_ENTRY (~0UL) > > #define FOREIGN_FRAME_BIT (1UL<<(BITS_PER_LONG-1)) > > #define IDENTITY_FRAME_BIT (1UL<<(BITS_PER_LONG-2)) > > +#define GRANT_FRAME_BIT (1UL<<(BITS_PER_LONG-3)) > > I am going to change that to (BITS_PER_LONG-1) as we aren''t > using the P2M. (and add that comment in the file).You should also move it away from/out of the "/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/" section, otherwise it''s just confusing. The associated GRANT_FRAME macro seems to be unused. But what is that bit in page->private actually used for? This patch adds it in m2p_add_override and masks it off in m2p_find_override, but doesn''t otherwise appear to use it. Ian. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2011-Sep-29 14:53 UTC
Re: [Xen-devel] [PATCH v5 2/2] xen: modify kernel mappings corresponding to granted pages
On Thu, 29 Sep 2011, Ian Campbell wrote:> On Thu, 2011-09-29 at 14:55 +0100, Konrad Rzeszutek Wilk wrote: > > > /* Xen machine address */ > > > @@ -31,8 +32,10 @@ typedef struct xpaddr { > > > #define INVALID_P2M_ENTRY (~0UL) > > > #define FOREIGN_FRAME_BIT (1UL<<(BITS_PER_LONG-1)) > > > #define IDENTITY_FRAME_BIT (1UL<<(BITS_PER_LONG-2)) > > > +#define GRANT_FRAME_BIT (1UL<<(BITS_PER_LONG-3)) > > > > I am going to change that to (BITS_PER_LONG-1) as we aren''t > > using the P2M. (and add that comment in the file). > > You should also move it away from/out of the "/**** MACHINE <-> PHYSICAL > CONVERSION MACROS ****/" section, otherwise it''s just confusing. > > The associated GRANT_FRAME macro seems to be unused. > > But what is that bit in page->private actually used for? This patch adds > it in m2p_add_override and masks it off in m2p_find_override, but > doesn''t otherwise appear to use it.It was needed by the previous version that was capable of handling highmem pages, it is not required anymore. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel