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-changelog

[Xen-changelog] [xen-unstable] Dynamic grant-table sizing.

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] Dynamic grant-table sizing.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 16 Feb 2007 12:15:13 -0800
Delivery-date: Fri, 16 Feb 2007 12:15:36 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1171536852 0
# Node ID 70f05d642a2e1c0a688e17e39e622e930998e60b
# Parent  047b3e9f90325eac9a84d840ed27dcb2c8691f5a
Dynamic grant-table sizing.
Signed-off-by: Christopher CLark <christopher.clark@xxxxxxxxxxxx>
Signed-off-by: Andrei Petrov <andrei.petrov@xxxxxxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 linux-2.6-xen-sparse/drivers/xen/core/gnttab.c |  251 ++++++++++--
 linux-2.6-xen-sparse/include/xen/gnttab.h      |   13 
 xen/arch/ia64/xen/mm.c                         |    4 
 xen/arch/x86/mm.c                              |   12 
 xen/common/compat/grant_table.c                |    3 
 xen/common/grant_table.c                       |  501 +++++++++++++++++++------
 xen/include/asm-ia64/grant_table.h             |    2 
 xen/include/asm-powerpc/grant_table.h          |    2 
 xen/include/asm-x86/grant_table.h              |    6 
 xen/include/public/grant_table.h               |   19 
 xen/include/xen/grant_table.h                  |   38 +
 11 files changed, 657 insertions(+), 194 deletions(-)

diff -r 047b3e9f9032 -r 70f05d642a2e 
linux-2.6-xen-sparse/drivers/xen/core/gnttab.c
--- a/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c    Thu Feb 15 10:34:21 
2007 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c    Thu Feb 15 10:54:12 
2007 +0000
@@ -3,7 +3,7 @@
  *
  * Granting foreign access to our memory reservation.
  *
- * Copyright (c) 2005, Christopher Clark
+ * Copyright (c) 2005-2006, Christopher Clark
  * Copyright (c) 2004-2005, K A Fraser
  *
  * This program is free software; you can redistribute it and/or
@@ -35,7 +35,6 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/vmalloc.h>
 #include <xen/interface/xen.h>
 #include <xen/gnttab.h>
 #include <asm/pgtable.h>
@@ -43,6 +42,7 @@
 #include <asm/synch_bitops.h>
 #include <asm/io.h>
 #include <xen/interface/memory.h>
+#include <xen/driver_util.h>
 
 #ifdef HAVE_XEN_PLATFORM_COMPAT_H
 #include <xen/platform-compat.h>
@@ -50,37 +50,51 @@
 
 /* External tools reserve first few grant table entries. */
 #define NR_RESERVED_ENTRIES 8
-
-#define NR_GRANT_ENTRIES \
-       (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(struct grant_entry))
-#define GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1)
-
-static grant_ref_t gnttab_list[NR_GRANT_ENTRIES];
+#define GNTTAB_LIST_END 0xffffffff
+#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(grant_entry_t))
+
+static grant_ref_t **gnttab_list;
+static unsigned int nr_grant_frames;
+static unsigned int boot_max_nr_grant_frames;
 static int gnttab_free_count;
 static grant_ref_t gnttab_free_head;
 static DEFINE_SPINLOCK(gnttab_list_lock);
 
 static struct grant_entry *shared;
+#ifndef CONFIG_XEN
+static unsigned long resume_frames;
+#endif
 
 static struct gnttab_free_callback *gnttab_free_callback_list;
 
+static int gnttab_expand(unsigned int req_entries);
+
+#define RPP (PAGE_SIZE / sizeof(grant_ref_t))
+#define gnttab_entry(entry) (gnttab_list[(entry) / RPP][(entry) % RPP])
+
 static int get_free_entries(int count)
 {
        unsigned long flags;
-       int ref;
+       int ref, rc;
        grant_ref_t head;
+
        spin_lock_irqsave(&gnttab_list_lock, flags);
-       if (gnttab_free_count < count) {
+
+       if ((gnttab_free_count < count) &&
+           ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
                spin_unlock_irqrestore(&gnttab_list_lock, flags);
-               return -1;
-       }
+               return rc;
+       }
+
        ref = head = gnttab_free_head;
        gnttab_free_count -= count;
        while (count-- > 1)
-               head = gnttab_list[head];
-       gnttab_free_head = gnttab_list[head];
-       gnttab_list[head] = GNTTAB_LIST_END;
+               head = gnttab_entry(head);
+       gnttab_free_head = gnttab_entry(head);
+       gnttab_entry(head) = GNTTAB_LIST_END;
+
        spin_unlock_irqrestore(&gnttab_list_lock, flags);
+
        return ref;
 }
 
@@ -116,7 +130,7 @@ static void put_free_entry(grant_ref_t r
 {
        unsigned long flags;
        spin_lock_irqsave(&gnttab_list_lock, flags);
-       gnttab_list[ref] = gnttab_free_head;
+       gnttab_entry(ref) = gnttab_free_head;
        gnttab_free_head = ref;
        gnttab_free_count++;
        check_free_callbacks();
@@ -132,7 +146,7 @@ int gnttab_grant_foreign_access(domid_t 
 {
        int ref;
 
-       if (unlikely((ref = get_free_entry()) == -1))
+       if (unlikely((ref = get_free_entry()) < 0))
                return -ENOSPC;
 
        shared[ref].frame = frame;
@@ -202,7 +216,7 @@ int gnttab_grant_foreign_transfer(domid_
 {
        int ref;
 
-       if (unlikely((ref = get_free_entry()) == -1))
+       if (unlikely((ref = get_free_entry()) < 0))
                return -ENOSPC;
        gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
 
@@ -273,11 +287,11 @@ void gnttab_free_grant_references(grant_
                return;
        spin_lock_irqsave(&gnttab_list_lock, flags);
        ref = head;
-       while (gnttab_list[ref] != GNTTAB_LIST_END) {
-               ref = gnttab_list[ref];
+       while (gnttab_entry(ref) != GNTTAB_LIST_END) {
+               ref = gnttab_entry(ref);
                count++;
        }
-       gnttab_list[ref] = gnttab_free_head;
+       gnttab_entry(ref) = gnttab_free_head;
        gnttab_free_head = head;
        gnttab_free_count += count;
        check_free_callbacks();
@@ -289,7 +303,7 @@ int gnttab_alloc_grant_references(u16 co
 {
        int h = get_free_entries(count);
 
-       if (h == -1)
+       if (h < 0)
                return -ENOSPC;
 
        *head = h;
@@ -309,7 +323,7 @@ int gnttab_claim_grant_reference(grant_r
        grant_ref_t g = *private_head;
        if (unlikely(g == GNTTAB_LIST_END))
                return -ENOSPC;
-       *private_head = gnttab_list[g];
+       *private_head = gnttab_entry(g);
        return g;
 }
 EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
@@ -317,7 +331,7 @@ void gnttab_release_grant_reference(gran
 void gnttab_release_grant_reference(grant_ref_t *private_head,
                                    grant_ref_t release)
 {
-       gnttab_list[release] = *private_head;
+       gnttab_entry(release) = *private_head;
        *private_head = release;
 }
 EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
@@ -356,6 +370,64 @@ void gnttab_cancel_free_callback(struct 
 }
 EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
 
+static int grow_gnttab_list(unsigned int more_frames)
+{
+       unsigned int new_nr_grant_frames, extra_entries, i;
+
+       new_nr_grant_frames = nr_grant_frames + more_frames;
+       extra_entries       = more_frames * GREFS_PER_GRANT_FRAME;
+
+       for (i = nr_grant_frames; i < new_nr_grant_frames; i++)
+       {
+               gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
+               if (!gnttab_list[i])
+                       goto grow_nomem;
+       }
+
+
+       for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+            i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
+               gnttab_entry(i) = i + 1;
+
+       gnttab_entry(i) = gnttab_free_head;
+       gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+       gnttab_free_count += extra_entries;
+
+       nr_grant_frames = new_nr_grant_frames;
+
+       check_free_callbacks();
+
+       return 0;
+       
+grow_nomem:
+       for ( ; i >= nr_grant_frames; i--)
+               free_page((unsigned long) gnttab_list[i]);
+       return -ENOMEM;
+}
+
+static unsigned int __max_nr_grant_frames(void)
+{
+       struct gnttab_query_size query;
+       int rc;
+
+       query.dom = DOMID_SELF;
+
+       rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
+       if ((rc < 0) || (query.status != GNTST_okay))
+               return 4; /* Legacy max supported number of frames */
+
+       return query.max_nr_frames;
+}
+
+static inline unsigned int max_nr_grant_frames(void)
+{
+       unsigned int xen_max = __max_nr_grant_frames();
+
+       if (xen_max > boot_max_nr_grant_frames)
+               return boot_max_nr_grant_frames;
+       return xen_max;
+}
+
 #ifdef CONFIG_XEN
 
 #ifndef __ia64__
@@ -378,49 +450,62 @@ static int unmap_pte_fn(pte_t *pte, stru
 }
 #endif
 
-int gnttab_resume(void)
+static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
 {
        struct gnttab_setup_table setup;
-       unsigned long frames[NR_GRANT_FRAMES];
+       unsigned long *frames;
+       unsigned int nr_gframes = end_idx + 1;
        int rc;
-#ifndef __ia64__
-       void *pframes = frames;
-       struct vm_struct *area;
-#endif
+
+       frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
+       if (!frames)
+               return -ENOMEM;
 
        setup.dom        = DOMID_SELF;
-       setup.nr_frames  = NR_GRANT_FRAMES;
+       setup.nr_frames  = nr_gframes;
        set_xen_guest_handle(setup.frame_list, frames);
 
        rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
-       if (rc == -ENOSYS)
+       if (rc == -ENOSYS) {
+               kfree(frames);
                return -ENOSYS;
+       }
 
        BUG_ON(rc || setup.status);
 
 #ifndef __ia64__
        if (shared == NULL) {
-               area = get_vm_area(PAGE_SIZE * NR_GRANT_FRAMES, VM_IOREMAP);
+               struct vm_struct *area;
+               area = alloc_vm_area(PAGE_SIZE * max_nr_grant_frames());
                BUG_ON(area == NULL);
                shared = area->addr;
        }
        rc = apply_to_page_range(&init_mm, (unsigned long)shared,
-                                PAGE_SIZE * NR_GRANT_FRAMES,
-                                map_pte_fn, &pframes);
+                                PAGE_SIZE * nr_gframes,
+                                map_pte_fn, &frames);
        BUG_ON(rc);
+        frames -= nr_gframes; /* adjust after map_pte_fn() */
 #else
        shared = __va(frames[0] << PAGE_SHIFT);
-       printk("grant table at %p\n", shared);
 #endif
 
-       return 0;
+       kfree(frames);
+
+       return 0;
+}
+
+int gnttab_resume(void)
+{
+       if (max_nr_grant_frames() < nr_grant_frames)
+               return -ENOSYS;
+       return gnttab_map(0, nr_grant_frames - 1);
 }
 
 int gnttab_suspend(void)
 {
 #ifndef __ia64__
        apply_to_page_range(&init_mm, (unsigned long)shared,
-                           PAGE_SIZE * NR_GRANT_FRAMES,
+                           PAGE_SIZE * nr_grant_frames,
                            unmap_pte_fn, NULL);
 #endif
        return 0;
@@ -430,24 +515,39 @@ int gnttab_suspend(void)
 
 #include <platform-pci.h>
 
-int gnttab_resume(void)
-{
-       unsigned long frames;
+static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
+{
        struct xen_add_to_physmap xatp;
        unsigned int i;
 
-       frames = alloc_xen_mmio(PAGE_SIZE * NR_GRANT_FRAMES);
-
-       for (i = 0; i < NR_GRANT_FRAMES; i++) {
+       /* Loop backwards, so that the first hypercall has the largest index,
+        * ensuring that the table will grow only once.
+        */
+       for (i = end_idx; i >= start_idx; i--) {
                xatp.domid = DOMID_SELF;
                xatp.idx = i;
                xatp.space = XENMAPSPACE_grant_table;
-               xatp.gpfn = (frames >> PAGE_SHIFT) + i;
+               xatp.gpfn = (resume_frames >> PAGE_SHIFT) + i;
                if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
                        BUG();
        }
-
-       shared = ioremap(frames, PAGE_SIZE * NR_GRANT_FRAMES);
+}
+
+int gnttab_resume(void)
+{
+       struct xen_add_to_physmap xatp;
+       unsigned int i, max_nr_gframes, nr_gframes;
+
+       nr_gframes = nr_grant_frames;
+       max_nr_gframes = max_nr_grant_frames();
+       if (max_nr_gframes < nr_gframes)
+               return -ENOSYS;
+
+       resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes);
+
+       gnttab_map(0, nr_gframes - 1);
+
+       shared = ioremap(resume_frames, PAGE_SIZE * max_nr_gframes);
        if (shared == NULL) {
                printk("error to ioremap gnttab share frames\n");
                return -1;
@@ -459,28 +559,79 @@ int gnttab_suspend(void)
 int gnttab_suspend(void)
 {
        iounmap(shared);
+       resume_frames = 0;
        return 0;
 }
 
 #endif /* !CONFIG_XEN */
 
+static int gnttab_expand(unsigned int req_entries)
+{
+       int rc;
+       unsigned int cur, extra;
+
+       cur = nr_grant_frames;
+       extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) /
+                GREFS_PER_GRANT_FRAME);
+       if (cur + extra > max_nr_grant_frames())
+               return -ENOSPC;
+
+       if ((rc = gnttab_map(cur, cur + extra - 1)) == 0)
+               rc = grow_gnttab_list(extra);
+
+       return rc;
+}
+
 int __devinit gnttab_init(void)
 {
        int i;
+       unsigned int max_nr_glist_frames;
+       unsigned int nr_init_grefs;
 
        if (!is_running_on_xen())
                return -ENODEV;
 
+       nr_grant_frames = 1;
+       boot_max_nr_grant_frames = __max_nr_grant_frames();
+
+       /* Determine the maximum number of frames required for the
+        * grant reference free list on the current hypervisor.
+        */
+       max_nr_glist_frames = (boot_max_nr_grant_frames *
+                              GREFS_PER_GRANT_FRAME /
+                              (PAGE_SIZE / sizeof(grant_ref_t)));
+
+       gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
+                             GFP_KERNEL);
+       if (gnttab_list == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < nr_grant_frames; i++) {
+               gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
+               if (gnttab_list[i] == NULL)
+                       goto ini_nomem;
+       }
+
        if (gnttab_resume() < 0)
                return -ENODEV;
 
-       for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++)
-               gnttab_list[i] = i + 1;
-       gnttab_free_count = NR_GRANT_ENTRIES - NR_RESERVED_ENTRIES;
+       nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME;
+
+       for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
+               gnttab_entry(i) = i + 1;
+
+       gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
+       gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
        gnttab_free_head  = NR_RESERVED_ENTRIES;
 
        printk("Grant table initialized\n");
        return 0;
+
+ ini_nomem:
+       for (i--; i >= 0; i--)
+               free_page((unsigned long)gnttab_list[i]);
+       kfree(gnttab_list);
+       return -ENOMEM;
 }
 
 #ifdef CONFIG_XEN
diff -r 047b3e9f9032 -r 70f05d642a2e linux-2.6-xen-sparse/include/xen/gnttab.h
--- a/linux-2.6-xen-sparse/include/xen/gnttab.h Thu Feb 15 10:34:21 2007 +0000
+++ b/linux-2.6-xen-sparse/include/xen/gnttab.h Thu Feb 15 10:54:12 2007 +0000
@@ -42,13 +42,6 @@
 #include <asm/maddr.h> /* maddr_t */
 #include <xen/interface/grant_table.h>
 #include <xen/features.h>
-
-/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */
-#ifdef __ia64__
-#define NR_GRANT_FRAMES 1
-#else
-#define NR_GRANT_FRAMES 4
-#endif
 
 struct gnttab_free_callback {
        struct gnttab_free_callback *next;
@@ -109,12 +102,6 @@ void gnttab_grant_foreign_transfer_ref(g
 void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid,
                                       unsigned long pfn);
 
-#ifdef __ia64__
-#define gnttab_map_vaddr(map) __va(map.dev_bus_addr)
-#else
-#define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr))
-#endif
-
 int gnttab_suspend(void);
 int gnttab_resume(void);
 
diff -r 047b3e9f9032 -r 70f05d642a2e xen/arch/ia64/xen/mm.c
--- a/xen/arch/ia64/xen/mm.c    Thu Feb 15 10:34:21 2007 +0000
+++ b/xen/arch/ia64/xen/mm.c    Thu Feb 15 10:54:12 2007 +0000
@@ -2077,8 +2077,10 @@ arch_memory_op(int op, XEN_GUEST_HANDLE(
                 mfn = virt_to_mfn(d->shared_info);
             break;
         case XENMAPSPACE_grant_table:
-            if (xatp.idx < NR_GRANT_FRAMES)
+            spin_lock(d->grant_table->lock);
+            if ( xatp.idx < nr_grant_frames(d->grant_table) )
                 mfn = virt_to_mfn(d->grant_table->shared) + xatp.idx;
+            spin_unlock(d->grant_table->lock);
             break;
         default:
             break;
diff -r 047b3e9f9032 -r 70f05d642a2e xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Thu Feb 15 10:34:21 2007 +0000
+++ b/xen/arch/x86/mm.c Thu Feb 15 10:54:12 2007 +0000
@@ -2971,8 +2971,16 @@ long arch_memory_op(int op, XEN_GUEST_HA
                 mfn = virt_to_mfn(d->shared_info);
             break;
         case XENMAPSPACE_grant_table:
-            if ( xatp.idx < NR_GRANT_FRAMES )
-                mfn = virt_to_mfn(d->grant_table->shared) + xatp.idx;
+            spin_lock(&d->grant_table->lock);
+
+            if ( (xatp.idx >= nr_grant_frames(d->grant_table)) &&
+                 (xatp.idx < max_nr_grant_frames) )
+                gnttab_grow_table(d, xatp.idx + 1);
+
+            if ( xatp.idx < nr_grant_frames(d->grant_table) )
+                mfn = virt_to_mfn(d->grant_table->shared[xatp.idx]);
+
+            spin_unlock(&d->grant_table->lock);
             break;
         default:
             break;
diff -r 047b3e9f9032 -r 70f05d642a2e xen/common/compat/grant_table.c
--- a/xen/common/compat/grant_table.c   Thu Feb 15 10:34:21 2007 +0000
+++ b/xen/common/compat/grant_table.c   Thu Feb 15 10:54:12 2007 +0000
@@ -101,7 +101,7 @@ int compat_grant_table_op(unsigned int c
                 rc = -EFAULT;
             else
             {
-                BUILD_BUG_ON((COMPAT_ARG_XLAT_SIZE - sizeof(*nat.setup)) / 
sizeof(*nat.setup->frame_list.p) < NR_GRANT_FRAMES);
+                BUG_ON((COMPAT_ARG_XLAT_SIZE - sizeof(*nat.setup)) / 
sizeof(*nat.setup->frame_list.p) < max_nr_grant_frames);
 #define XLAT_gnttab_setup_table_HNDL_frame_list(_d_, _s_) \
                 set_xen_guest_handle((_d_)->frame_list, (unsigned long 
*)(nat.setup + 1))
                 XLAT_gnttab_setup_table(nat.setup, &cmp.setup);
@@ -110,7 +110,6 @@ int compat_grant_table_op(unsigned int c
             }
             if ( rc == 0 )
             {
-                BUG_ON(nat.setup->nr_frames > NR_GRANT_FRAMES);
 #define XLAT_gnttab_setup_table_HNDL_frame_list(_d_, _s_) \
                 do \
                 { \
diff -r 047b3e9f9032 -r 70f05d642a2e xen/common/grant_table.c
--- a/xen/common/grant_table.c  Thu Feb 15 10:34:21 2007 +0000
+++ b/xen/common/grant_table.c  Thu Feb 15 10:54:12 2007 +0000
@@ -4,7 +4,7 @@
  * Mechanism for granting foreign access to page frames, and receiving
  * page-ownership transfers.
  * 
- * Copyright (c) 2005 Christopher Clark
+ * Copyright (c) 2005-2006 Christopher Clark
  * Copyright (c) 2004 K A Fraser
  * Copyright (c) 2005 Andrew Warfield
  * Modifications by Geoffrey Lefebvre are (c) Intel Research Cambridge
@@ -35,6 +35,15 @@
 #include <xen/domain_page.h>
 #include <acm/acm_hooks.h>
 
+unsigned int max_nr_grant_frames = DEFAULT_MAX_NR_GRANT_FRAMES;
+integer_param("gnttab_max_nr_frames", max_nr_grant_frames);
+
+/* The maximum number of grant mappings is defined as a multiplier of the
+ * maximum number of grant table entries. This defines the multiplier used.
+ * Pretty arbitrary. [POLICY]
+ */
+#define MAX_MAPTRACK_TO_GRANTS_RATIO 8
+
 /*
  * The first two members of a grant entry are updated as a combined pair.
  * The following union allows that to happen in an endian-neutral fashion.
@@ -54,14 +63,58 @@ union grant_combo {
         goto _lbl;                              \
     } while ( 0 )
 
+#define MAPTRACK_PER_PAGE (PAGE_SIZE / sizeof(struct grant_mapping))
+#define maptrack_entry(t, e) \
+    ((t)->maptrack[(e)/MAPTRACK_PER_PAGE][(e)%MAPTRACK_PER_PAGE])
+
+static inline unsigned int
+nr_maptrack_frames(struct grant_table *t)
+{
+    return t->maptrack_limit / MAPTRACK_PER_PAGE;
+}
+
+static unsigned inline int max_nr_maptrack_frames(void)
+{
+    return (max_nr_grant_frames * MAX_MAPTRACK_TO_GRANTS_RATIO);
+}
+
+static inline unsigned int
+num_act_frames_from_sha_frames(const unsigned int num)
+{
+    /* How many frames are needed for the active grant table,
+     * given the size of the shared grant table?
+     *
+     * act_per_page = PAGE_SIZE / sizeof(active_grant_entry_t);
+     * sha_per_page = PAGE_SIZE / sizeof(grant_entry_t);
+     * num_sha_entries = num * sha_per_page;
+     * num_act_frames = (num_sha_entries + (act_per_page-1)) / act_per_page;
+     */
+    return ((num * (PAGE_SIZE / sizeof(grant_entry_t))) +
+            ((PAGE_SIZE / sizeof(struct active_grant_entry))-1))
+           / (PAGE_SIZE / sizeof(struct active_grant_entry));
+}
+
+static inline unsigned int
+nr_active_grant_frames(struct grant_table *gt)
+{
+    return num_act_frames_from_sha_frames(nr_grant_frames(gt));
+}
+
+#define SHGNT_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_t))
+#define shared_entry(t, e) \
+    ((t)->shared[(e)/SHGNT_PER_PAGE][(e)%SHGNT_PER_PAGE])
+#define ACGNT_PER_PAGE (PAGE_SIZE / sizeof(struct active_grant_entry))
+#define active_entry(t, e) \
+    ((t)->active[(e)/ACGNT_PER_PAGE][(e)%ACGNT_PER_PAGE])
+
 static inline int
-get_maptrack_handle(
+__get_maptrack_handle(
     struct grant_table *t)
 {
     unsigned int h;
     if ( unlikely((h = t->maptrack_head) == (t->maptrack_limit - 1)) )
         return -1;
-    t->maptrack_head = t->maptrack[h].ref;
+    t->maptrack_head = maptrack_entry(t, h).ref;
     t->map_count++;
     return h;
 }
@@ -70,9 +123,61 @@ put_maptrack_handle(
 put_maptrack_handle(
     struct grant_table *t, int handle)
 {
-    t->maptrack[handle].ref = t->maptrack_head;
+    maptrack_entry(t, handle).ref = t->maptrack_head;
     t->maptrack_head = handle;
     t->map_count--;
+}
+
+static inline int
+get_maptrack_handle(
+    struct grant_table *lgt)
+{
+    int                   i;
+    grant_handle_t        handle;
+    struct grant_mapping *new_mt;
+    unsigned int          new_mt_limit, nr_frames;
+
+    if ( unlikely((handle = __get_maptrack_handle(lgt)) == -1) )
+    {
+        spin_lock(&lgt->lock);
+
+        if ( unlikely((handle = __get_maptrack_handle(lgt)) == -1) )
+        {
+            nr_frames = nr_maptrack_frames(lgt);
+            if ( nr_frames >= max_nr_maptrack_frames() )
+            {
+                spin_unlock(&lgt->lock);
+                return -1;
+            }
+
+            new_mt = alloc_xenheap_page();
+            if ( new_mt == NULL )
+            {
+                spin_unlock(&lgt->lock);
+                return -1;
+            }
+
+            memset(new_mt, 0, PAGE_SIZE);
+
+            new_mt_limit = lgt->maptrack_limit + MAPTRACK_PER_PAGE;
+
+            for ( i = lgt->maptrack_limit; i < new_mt_limit; i++ )
+            {
+                new_mt[i % MAPTRACK_PER_PAGE].ref = i+1;
+                new_mt[i % MAPTRACK_PER_PAGE].flags = 0;
+            }
+
+            lgt->maptrack[nr_frames] = new_mt;
+            lgt->maptrack_limit      = new_mt_limit;
+
+            gdprintk(XENLOG_INFO,
+                    "Increased maptrack size to %u frames.\n", nr_frames + 1);
+            handle = __get_maptrack_handle(lgt);
+        }
+
+        spin_unlock(&lgt->lock);
+    }
+    return handle;
 }
 
 /*
@@ -92,6 +197,7 @@ __gnttab_map_grant_ref(
     unsigned long  frame = 0;
     int            rc = GNTST_okay;
     struct active_grant_entry *act;
+    struct grant_mapping *mt;
     grant_entry_t *sha;
     union grant_combo scombo, prev_scombo, new_scombo;
 
@@ -108,11 +214,9 @@ __gnttab_map_grant_ref(
     led = current;
     ld = led->domain;
 
-    if ( unlikely(op->ref >= NR_GRANT_ENTRIES) ||
-         unlikely((op->flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0) )
-    {
-        gdprintk(XENLOG_INFO, "Bad ref (%d) or flags (%x).\n",
-                op->ref, op->flags);
+    if ( unlikely((op->flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0) )
+    {
+        gdprintk(XENLOG_INFO, "Bad flags in grant map op (%x).\n", op->flags);
         op->status = GNTST_bad_gntref;
         return;
     }
@@ -132,51 +236,22 @@ __gnttab_map_grant_ref(
         return;
     }
 
-    /* Get a maptrack handle. */
     if ( unlikely((handle = get_maptrack_handle(ld->grant_table)) == -1) )
     {
-        int                   i;
-        struct grant_mapping *new_mt;
-        struct grant_table   *lgt = ld->grant_table;
-
-        if ( (lgt->maptrack_limit << 1) > MAPTRACK_MAX_ENTRIES )
-        {
-            put_domain(rd);
-            gdprintk(XENLOG_INFO, "Maptrack table is at maximum size.\n");
-            op->status = GNTST_no_device_space;
-            return;
-        }
-
-        /* Grow the maptrack table. */
-        new_mt = alloc_xenheap_pages(lgt->maptrack_order + 1);
-        if ( new_mt == NULL )
-        {
-            put_domain(rd);
-            gdprintk(XENLOG_INFO, "No more map handles available.\n");
-            op->status = GNTST_no_device_space;
-            return;
-        }
-
-        memcpy(new_mt, lgt->maptrack, PAGE_SIZE << lgt->maptrack_order);
-        for ( i = lgt->maptrack_limit; i < (lgt->maptrack_limit << 1); i++ )
-        {
-            new_mt[i].ref = i+1;
-            new_mt[i].flags = 0;
-        }
-
-        free_xenheap_pages(lgt->maptrack, lgt->maptrack_order);
-        lgt->maptrack          = new_mt;
-        lgt->maptrack_order   += 1;
-        lgt->maptrack_limit  <<= 1;
-
-        gdprintk(XENLOG_INFO, "Doubled maptrack size\n");
-        handle = get_maptrack_handle(ld->grant_table);
-    }
-
-    act = &rd->grant_table->active[op->ref];
-    sha = &rd->grant_table->shared[op->ref];
+        put_domain(rd);
+        gdprintk(XENLOG_INFO, "Failed to obtain maptrack handle.\n");
+        op->status = GNTST_no_device_space;
+        return;
+    }
 
     spin_lock(&rd->grant_table->lock);
+
+    /* Bounds check on the grant ref */
+    if ( unlikely(op->ref >= nr_grant_entries(rd->grant_table)))
+        PIN_FAIL(unlock_out, GNTST_bad_gntref, "Bad ref (%d).\n", op->ref);
+
+    act = &active_entry(rd->grant_table, op->ref);
+    sha = &shared_entry(rd->grant_table, op->ref);
 
     /* If already pinned, check the active domid and avoid refcnt overflow. */
     if ( act->pin &&
@@ -247,9 +322,10 @@ __gnttab_map_grant_ref(
         act->pin += (op->flags & GNTMAP_readonly) ?
             GNTPIN_hstr_inc : GNTPIN_hstw_inc;
 
+    frame = act->frame;
+
     spin_unlock(&rd->grant_table->lock);
 
-    frame = act->frame;
     if ( unlikely(!mfn_valid(frame)) ||
          unlikely(!((op->flags & GNTMAP_readonly) ?
                     get_page(mfn_to_page(frame), rd) :
@@ -283,9 +359,10 @@ __gnttab_map_grant_ref(
 
     TRACE_1D(TRC_MEM_PAGE_GRANT_MAP, op->dom);
 
-    ld->grant_table->maptrack[handle].domid = op->dom;
-    ld->grant_table->maptrack[handle].ref   = op->ref;
-    ld->grant_table->maptrack[handle].flags = op->flags;
+    mt = &maptrack_entry(ld->grant_table, handle);
+    mt->domid = op->dom;
+    mt->ref   = op->ref;
+    mt->flags = op->flags;
 
     op->dev_bus_addr = (u64)frame << PAGE_SHIFT;
     op->handle       = handle;
@@ -296,6 +373,9 @@ __gnttab_map_grant_ref(
 
  undo_out:
     spin_lock(&rd->grant_table->lock);
+
+    act = &active_entry(rd->grant_table, op->ref);
+    sha = &shared_entry(rd->grant_table, op->ref);
 
     if ( op->flags & GNTMAP_device_map )
         act->pin -= (op->flags & GNTMAP_readonly) ?
@@ -355,12 +435,18 @@ __gnttab_unmap_grant_ref(
 
     frame = (unsigned long)(op->dev_bus_addr >> PAGE_SHIFT);
 
-    map = &ld->grant_table->maptrack[op->handle];
-
-    if ( unlikely(op->handle >= ld->grant_table->maptrack_limit) ||
-         unlikely(!map->flags) )
+    if ( unlikely(op->handle >= ld->grant_table->maptrack_limit) )
     {
         gdprintk(XENLOG_INFO, "Bad handle (%d).\n", op->handle);
+        op->status = GNTST_bad_handle;
+        return;
+    }
+
+    map = &maptrack_entry(ld->grant_table, op->handle);
+
+    if ( unlikely(!map->flags) )
+    {
+        gdprintk(XENLOG_INFO, "Zero flags for handle (%d).\n", op->handle);
         op->status = GNTST_bad_handle;
         return;
     }
@@ -379,10 +465,10 @@ __gnttab_unmap_grant_ref(
 
     TRACE_1D(TRC_MEM_PAGE_GRANT_UNMAP, dom);
 
-    act = &rd->grant_table->active[ref];
-    sha = &rd->grant_table->shared[ref];
-
     spin_lock(&rd->grant_table->lock);
+
+    act = &active_entry(rd->grant_table, ref);
+    sha = &shared_entry(rd->grant_table, ref);
 
     if ( frame == 0 )
     {
@@ -477,6 +563,62 @@ fault:
     return -EFAULT;    
 }
 
+int
+gnttab_grow_table(struct domain *d, unsigned int req_nr_frames)
+{
+    /* d's grant table lock must be held by the caller */
+
+    struct grant_table *gt = d->grant_table;
+    unsigned int i;
+
+    ASSERT(req_nr_frames <= max_nr_grant_frames);
+
+    gdprintk(XENLOG_INFO,
+            "Expanding dom (%d) grant table from (%d) to (%d) frames.\n",
+            d->domain_id, nr_grant_frames(gt), req_nr_frames);
+
+    /* Active */
+    for ( i = nr_active_grant_frames(gt);
+          i < num_act_frames_from_sha_frames(req_nr_frames); i++ )
+    {
+        if ( (gt->active[i] = alloc_xenheap_page()) == NULL )
+            goto active_alloc_failed;
+        memset(gt->active[i], 0, PAGE_SIZE);
+    }
+
+    /* Shared */
+    for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
+    {
+        if ( (gt->shared[i] = alloc_xenheap_page()) == NULL )
+            goto shared_alloc_failed;
+        memset(gt->shared[i], 0, PAGE_SIZE);
+    }
+
+    /* Share the new shared frames with the recipient domain */
+    for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
+        gnttab_create_shared_page(d, gt, i);
+
+    gt->nr_grant_frames = req_nr_frames;
+
+    return 1;
+
+shared_alloc_failed:
+    for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
+    {
+        free_xenheap_page(gt->shared[i]);
+        gt->shared[i] = NULL;
+    }
+active_alloc_failed:
+    for ( i = nr_active_grant_frames(gt);
+          i < num_act_frames_from_sha_frames(req_nr_frames); i++ )
+    {
+        free_xenheap_page(gt->active[i]);
+        gt->active[i] = NULL;
+    }
+    gdprintk(XENLOG_INFO, "Allocation failure when expanding grant table.\n");
+    return 0;
+}
+
 static long 
 gnttab_setup_table(
     XEN_GUEST_HANDLE(gnttab_setup_table_t) uop, unsigned int count)
@@ -496,11 +638,11 @@ gnttab_setup_table(
         return -EFAULT;
     }
 
-    if ( unlikely(op.nr_frames > NR_GRANT_FRAMES) )
+    if ( unlikely(op.nr_frames > max_nr_grant_frames) )
     {
         gdprintk(XENLOG_INFO, "Xen only supports up to %d grant-table frames"
                 " per domain.\n",
-                NR_GRANT_FRAMES);
+                max_nr_grant_frames);
         op.status = GNTST_general_error;
         goto out;
     }
@@ -523,7 +665,20 @@ gnttab_setup_table(
         goto out;
     }
 
-    ASSERT(d->grant_table != NULL);
+    spin_lock(&d->grant_table->lock);
+
+    if ( (op.nr_frames > nr_grant_frames(d->grant_table)) &&
+         !gnttab_grow_table(d, op.nr_frames) )
+    {
+        gdprintk(XENLOG_INFO,
+                "Expand grant table to %d failed. Current: %d Max: %d.\n",
+                op.nr_frames,
+                nr_grant_frames(d->grant_table),
+                max_nr_grant_frames);
+        op.status = GNTST_general_error;
+        goto setup_unlock_out;
+    }
+ 
     op.status = GNTST_okay;
     for ( i = 0; i < op.nr_frames; i++ )
     {
@@ -531,9 +686,64 @@ gnttab_setup_table(
         (void)copy_to_guest_offset(op.frame_list, i, &gmfn, 1);
     }
 
+ setup_unlock_out:
+    spin_unlock(&d->grant_table->lock);
+
     put_domain(d);
 
  out:
+    if ( unlikely(copy_to_guest(uop, &op, 1)) )
+        return -EFAULT;
+
+    return 0;
+}
+
+static long 
+gnttab_query_size(
+    XEN_GUEST_HANDLE(gnttab_query_size_t) uop, unsigned int count)
+{
+    struct gnttab_query_size op;
+    struct domain *d;
+    domid_t        dom;
+
+    if ( count != 1 )
+        return -EINVAL;
+
+    if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
+    {
+        gdprintk(XENLOG_INFO, "Fault while reading gnttab_query_size_t.\n");
+        return -EFAULT;
+    }
+
+    dom = op.dom;
+    if ( dom == DOMID_SELF )
+    {
+        dom = current->domain->domain_id;
+    }
+    else if ( unlikely(!IS_PRIV(current->domain)) )
+    {
+        op.status = GNTST_permission_denied;
+        goto query_out;
+    }
+
+    if ( unlikely((d = get_domain_by_id(dom)) == NULL) )
+    {
+        gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom);
+        op.status = GNTST_bad_domain;
+        goto query_out;
+    }
+
+    spin_lock(&d->grant_table->lock);
+
+    op.nr_frames     = nr_grant_frames(d->grant_table);
+    op.max_nr_frames = max_nr_grant_frames;
+    op.status        = GNTST_okay;
+
+    spin_unlock(&d->grant_table->lock);
+
+    put_domain(d);
+
+ query_out:
     if ( unlikely(copy_to_guest(uop, &op, 1)) )
         return -EFAULT;
 
@@ -553,17 +763,23 @@ gnttab_prepare_for_transfer(
     union grant_combo   scombo, prev_scombo, new_scombo;
     int                 retries = 0;
 
-    if ( unlikely((rgt = rd->grant_table) == NULL) ||
-         unlikely(ref >= NR_GRANT_ENTRIES) )
-    {
-        gdprintk(XENLOG_INFO, "Dom %d has no g.t., or ref is bad (%d).\n",
-                rd->domain_id, ref);
+    if ( unlikely((rgt = rd->grant_table) == NULL) )
+    {
+        gdprintk(XENLOG_INFO, "Dom %d has no grant table.\n", rd->domain_id);
         return 0;
     }
 
     spin_lock(&rgt->lock);
 
-    sha = &rgt->shared[ref];
+    if ( unlikely(ref >= nr_grant_entries(rd->grant_table)) )
+    {
+        gdprintk(XENLOG_INFO,
+                "Bad grant reference (%d) for transfer to domain(%d).\n",
+                ref, rd->domain_id);
+        goto fail;
+    }
+
+    sha = &shared_entry(rgt, ref);
     
     scombo.word = *(u32 *)&sha->flags;
 
@@ -699,12 +915,16 @@ gnttab_transfer(
         TRACE_1D(TRC_MEM_PAGE_GRANT_TRANSFER, e->domain_id);
 
         /* Tell the guest about its new page frame. */
-        sha = &e->grant_table->shared[gop.ref];
+        spin_lock(&e->grant_table->lock);
+
+        sha = &shared_entry(e->grant_table, gop.ref);
         guest_physmap_add_page(e, sha->frame, mfn);
         sha->frame = mfn;
         wmb();
         sha->flags |= GTF_transfer_completed;
 
+        spin_unlock(&e->grant_table->lock);
+
         put_domain(e);
 
         gop.status = GNTST_okay;
@@ -712,8 +932,8 @@ gnttab_transfer(
     copyback:
         if ( unlikely(__copy_to_guest_offset(uop, i, &gop, 1)) )
         {
-            gdprintk(XENLOG_INFO, "gnttab_transfer: error writing resp 
%d/%d\n",
-                    i, count);
+            gdprintk(XENLOG_INFO, "gnttab_transfer: error writing resp "
+                     "%d/%d\n", i, count);
             return -EFAULT;
         }
     }
@@ -727,17 +947,24 @@ __release_grant_for_copy(
 __release_grant_for_copy(
     struct domain *rd, unsigned long gref, int readonly)
 {
-    grant_entry_t *const sha = &rd->grant_table->shared[gref];
-    struct active_grant_entry *const act = &rd->grant_table->active[gref];
+    grant_entry_t *sha;
+    struct active_grant_entry *act;
+    unsigned long r_frame;
 
     spin_lock(&rd->grant_table->lock);
 
+    act = &active_entry(rd->grant_table, gref);
+    sha = &shared_entry(rd->grant_table, gref);
+    r_frame = act->frame;
+
     if ( readonly )
     {
         act->pin -= GNTPIN_hstr_inc;
     }
     else
     {
+        gnttab_mark_dirty(rd, r_frame);
+
         act->pin -= GNTPIN_hstw_inc;
         if ( !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) )
             gnttab_clear_flag(_GTF_writing, &sha->flags);
@@ -764,14 +991,14 @@ __acquire_grant_for_copy(
     int retries = 0;
     union grant_combo scombo, prev_scombo, new_scombo;
 
-    if ( unlikely(gref >= NR_GRANT_ENTRIES) )
-        PIN_FAIL(error_out, GNTST_bad_gntref,
+    spin_lock(&rd->grant_table->lock);
+
+    if ( unlikely(gref >= nr_grant_entries(rd->grant_table)) )
+        PIN_FAIL(unlock_out, GNTST_bad_gntref,
                  "Bad grant reference %ld\n", gref);
-    
-    act = &rd->grant_table->active[gref];
-    sha = &rd->grant_table->shared[gref];
-
-    spin_lock(&rd->grant_table->lock);
+
+    act = &active_entry(rd->grant_table, gref);
+    sha = &shared_entry(rd->grant_table, gref);
     
     /* If already pinned, check the active domid and avoid refcnt overflow. */
     if ( act->pin &&
@@ -834,7 +1061,6 @@ __acquire_grant_for_copy(
 
  unlock_out:
     spin_unlock(&rd->grant_table->lock);
- error_out:
     return rc;
 }
 
@@ -1037,6 +1263,12 @@ do_grant_table_op(
         rc = gnttab_copy(copy, count);
         break;
     }
+    case GNTTABOP_query_size:
+    {
+        rc = gnttab_query_size(
+            guest_handle_cast(uop, gnttab_query_size_t), count);
+        break;
+    }
     default:
         rc = -ENOSYS;
         break;
@@ -1052,6 +1284,13 @@ do_grant_table_op(
 #include "compat/grant_table.c"
 #endif
 
+static unsigned int max_nr_active_grant_frames(void)
+{
+    return (((max_nr_grant_frames * (PAGE_SIZE / sizeof(grant_entry_t))) + 
+                    ((PAGE_SIZE / sizeof(struct active_grant_entry))-1)) 
+                   / (PAGE_SIZE / sizeof(struct active_grant_entry)));
+}
+
 int 
 grant_table_create(
     struct domain *d)
@@ -1059,50 +1298,75 @@ grant_table_create(
     struct grant_table *t;
     int                 i;
 
-    BUG_ON(MAPTRACK_MAX_ENTRIES < NR_GRANT_ENTRIES);
+    /* If this sizeof assertion fails, fix the function: shared_index */
+    ASSERT(sizeof(grant_entry_t) == 8);
+
     if ( (t = xmalloc(struct grant_table)) == NULL )
-        goto no_mem;
+        goto no_mem_0;
 
     /* Simple stuff. */
     memset(t, 0, sizeof(*t));
     spin_lock_init(&t->lock);
+    t->nr_grant_frames = INITIAL_NR_GRANT_FRAMES;
 
     /* Active grant table. */
-    t->active = xmalloc_array(struct active_grant_entry, NR_GRANT_ENTRIES);
-    if ( t->active == NULL )
-        goto no_mem;
-    memset(t->active, 0, sizeof(struct active_grant_entry) * NR_GRANT_ENTRIES);
+    if ( (t->active = xmalloc_array(struct active_grant_entry *,
+                                    max_nr_active_grant_frames())) == NULL )
+        goto no_mem_1;
+    memset(t->active, 0, max_nr_active_grant_frames() * sizeof(t->active[0]));
+    for ( i = 0;
+          i < num_act_frames_from_sha_frames(INITIAL_NR_GRANT_FRAMES); i++ )
+    {
+        if ( (t->active[i] = alloc_xenheap_page()) == NULL )
+            goto no_mem_2;
+        memset(t->active[i], 0, PAGE_SIZE);
+    }
 
     /* Tracking of mapped foreign frames table */
-    if ( (t->maptrack = alloc_xenheap_page()) == NULL )
-        goto no_mem;
-    t->maptrack_order = 0;
+    if ( (t->maptrack = xmalloc_array(struct grant_mapping *,
+                                      max_nr_maptrack_frames())) == NULL )
+        goto no_mem_2;
+    memset(t->maptrack, 0, max_nr_maptrack_frames() * sizeof(t->maptrack[0]));
+    if ( (t->maptrack[0] = alloc_xenheap_page()) == NULL )
+        goto no_mem_3;
     t->maptrack_limit = PAGE_SIZE / sizeof(struct grant_mapping);
-    memset(t->maptrack, 0, PAGE_SIZE);
     for ( i = 0; i < t->maptrack_limit; i++ )
-        t->maptrack[i].ref = i+1;
+        t->maptrack[0][i].ref = i+1;
 
     /* Shared grant table. */
-    t->shared = alloc_xenheap_pages(ORDER_GRANT_FRAMES);
-    if ( t->shared == NULL )
-        goto no_mem;
-    memset(t->shared, 0, NR_GRANT_FRAMES * PAGE_SIZE);
-
-    for ( i = 0; i < NR_GRANT_FRAMES; i++ )
+    if ( (t->shared = xmalloc_array(struct grant_entry *,
+                                    max_nr_grant_frames)) == NULL )
+        goto no_mem_3;
+    memset(t->shared, 0, max_nr_grant_frames * sizeof(t->shared[0]));
+    for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
+    {
+        if ( (t->shared[i] = alloc_xenheap_page()) == NULL )
+            goto no_mem_4;
+        memset(t->shared[i], 0, PAGE_SIZE);
+    }
+
+    for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
         gnttab_create_shared_page(d, t, i);
 
     /* Okay, install the structure. */
-    wmb(); /* avoid races with lock-free access to d->grant_table */
     d->grant_table = t;
     return 0;
 
- no_mem:
-    if ( t != NULL )
-    {
-        xfree(t->active);
-        free_xenheap_page(t->maptrack);
-        xfree(t);
-    }
+ no_mem_4:
+    for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
+        free_xenheap_page(t->shared[i]);
+    xfree(t->shared);
+ no_mem_3:
+    free_xenheap_page(t->maptrack[0]);
+    xfree(t->maptrack);
+ no_mem_2:
+    for ( i = 0;
+          i < num_act_frames_from_sha_frames(INITIAL_NR_GRANT_FRAMES); i++ )
+        free_xenheap_page(t->active[i]);
+    xfree(t->active);
+ no_mem_1:
+    xfree(t);
+ no_mem_0:
     return -ENOMEM;
 }
 
@@ -1122,7 +1386,7 @@ gnttab_release_mappings(
 
     for ( handle = 0; handle < gt->maptrack_limit; handle++ )
     {
-        map = &gt->maptrack[handle];
+        map = &maptrack_entry(gt, handle);
         if ( !(map->flags & (GNTMAP_device_map|GNTMAP_host_map)) )
             continue;
 
@@ -1142,8 +1406,8 @@ gnttab_release_mappings(
 
         spin_lock(&rd->grant_table->lock);
 
-        act = &rd->grant_table->active[ref];
-        sha = &rd->grant_table->shared[ref];
+        act = &active_entry(rd->grant_table, ref);
+        sha = &shared_entry(rd->grant_table, ref);
 
         if ( map->flags & GNTMAP_readonly )
         {
@@ -1200,15 +1464,24 @@ grant_table_destroy(
     struct domain *d)
 {
     struct grant_table *t = d->grant_table;
+    int i;
 
     if ( t == NULL )
         return;
     
-    free_xenheap_pages(t->shared, ORDER_GRANT_FRAMES);
-    free_xenheap_pages(t->maptrack, t->maptrack_order);
+    for ( i = 0; i < nr_grant_frames(t); i++ )
+        free_xenheap_page(t->shared[i]);
+    xfree(t->shared);
+
+    for ( i = 0; i < nr_maptrack_frames(t); i++ )
+        free_xenheap_page(t->maptrack[i]);
+    xfree(t->maptrack);
+
+    for ( i = 0; i < nr_active_grant_frames(t); i++ )
+        free_xenheap_page(t->active[i]);
     xfree(t->active);
+
     xfree(t);
-
     d->grant_table = NULL;
 }
 
diff -r 047b3e9f9032 -r 70f05d642a2e xen/include/asm-ia64/grant_table.h
--- a/xen/include/asm-ia64/grant_table.h        Thu Feb 15 10:34:21 2007 +0000
+++ b/xen/include/asm-ia64/grant_table.h        Thu Feb 15 10:54:12 2007 +0000
@@ -5,7 +5,7 @@
 #ifndef __ASM_GRANT_TABLE_H__
 #define __ASM_GRANT_TABLE_H__
 
-#define ORDER_GRANT_FRAMES 0
+#define INITIAL_NR_GRANT_FRAMES 1
 
 // for grant map/unmap
 int create_grant_host_mapping(unsigned long gpaddr, unsigned long mfn, 
unsigned int flags);
diff -r 047b3e9f9032 -r 70f05d642a2e xen/include/asm-powerpc/grant_table.h
--- a/xen/include/asm-powerpc/grant_table.h     Thu Feb 15 10:34:21 2007 +0000
+++ b/xen/include/asm-powerpc/grant_table.h     Thu Feb 15 10:54:12 2007 +0000
@@ -23,7 +23,7 @@
 
 #include <asm/mm.h>
 
-#define ORDER_GRANT_FRAMES 2
+#define INITIAL_NR_GRANT_FRAMES 4
 
 /*
  * Caller must own caller's BIGLOCK, is responsible for flushing the TLB, and
diff -r 047b3e9f9032 -r 70f05d642a2e xen/include/asm-x86/grant_table.h
--- a/xen/include/asm-x86/grant_table.h Thu Feb 15 10:34:21 2007 +0000
+++ b/xen/include/asm-x86/grant_table.h Thu Feb 15 10:54:12 2007 +0000
@@ -7,7 +7,7 @@
 #ifndef __ASM_GRANT_TABLE_H__
 #define __ASM_GRANT_TABLE_H__
 
-#define ORDER_GRANT_FRAMES 2
+#define INITIAL_NR_GRANT_FRAMES 4
 
 /*
  * Caller must own caller's BIGLOCK, is responsible for flushing the TLB, and
@@ -21,12 +21,12 @@ int destroy_grant_host_mapping(
 #define gnttab_create_shared_page(d, t, i)                               \
     do {                                                                 \
         share_xen_page_with_guest(                                       \
-            virt_to_page((char *)(t)->shared + ((i) * PAGE_SIZE)),       \
+            virt_to_page((char *)(t)->shared[i]),                        \
             (d), XENSHARE_writable);                                     \
     } while ( 0 )
 
 #define gnttab_shared_mfn(d, t, i)                      \
-    ((virt_to_maddr((t)->shared) >> PAGE_SHIFT) + (i))
+    ((virt_to_maddr((t)->shared[i]) >> PAGE_SHIFT))
 
 #define gnttab_shared_gmfn(d, t, i)                     \
     (mfn_to_gmfn(d, gnttab_shared_mfn(d, t, i)))
diff -r 047b3e9f9032 -r 70f05d642a2e xen/include/public/grant_table.h
--- a/xen/include/public/grant_table.h  Thu Feb 15 10:34:21 2007 +0000
+++ b/xen/include/public/grant_table.h  Thu Feb 15 10:54:12 2007 +0000
@@ -308,6 +308,25 @@ typedef struct gnttab_copy {
     int16_t       status;
 } gnttab_copy_t;
 DEFINE_XEN_GUEST_HANDLE(gnttab_copy_t);
+
+/*
+ * GNTTABOP_query_size: Query the current and maximum sizes of the shared
+ * grant table.
+ * NOTES:
+ *  1. <dom> may be specified as DOMID_SELF.
+ *  2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
+ */
+#define GNTTABOP_query_size           6
+struct gnttab_query_size {
+    /* IN parameters. */
+    domid_t  dom;
+    /* OUT parameters. */
+    uint32_t nr_frames;
+    uint32_t max_nr_frames;
+    int16_t  status;              /* GNTST_* */
+};
+typedef struct gnttab_query_size gnttab_query_size_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_query_size_t);
 
 
 /*
diff -r 047b3e9f9032 -r 70f05d642a2e xen/include/xen/grant_table.h
--- a/xen/include/xen/grant_table.h     Thu Feb 15 10:34:21 2007 +0000
+++ b/xen/include/xen/grant_table.h     Thu Feb 15 10:54:12 2007 +0000
@@ -52,9 +52,14 @@ struct active_grant_entry {
 #define GNTPIN_devr_inc      (1 << GNTPIN_devr_shift)
 #define GNTPIN_devr_mask     (0xFFU << GNTPIN_devr_shift)
 
-#define NR_GRANT_FRAMES      (1U << ORDER_GRANT_FRAMES)
-#define NR_GRANT_ENTRIES     \
-    ((NR_GRANT_FRAMES << PAGE_SHIFT) / sizeof(grant_entry_t))
+/* Initial size of a grant table. */
+#define INITIAL_NR_GRANT_ENTRIES ((INITIAL_NR_GRANT_FRAMES << PAGE_SHIFT) / \
+                                     sizeof(grant_entry_t))
+
+/* Default maximum size of a grant table. [POLICY] */
+#define DEFAULT_MAX_NR_GRANT_FRAMES   32
+/* The maximum size of a grant table. */
+extern unsigned int max_nr_grant_frames;
 
 /*
  * Tracks a mapping of another domain's grant reference. Each domain has a
@@ -71,14 +76,15 @@ struct grant_mapping {
 
 /* Per-domain grant information. */
 struct grant_table {
+    /* Table size. Number of frames shared with guest */
+    unsigned int          nr_grant_frames;
     /* Shared grant table (see include/public/grant_table.h). */
-    struct grant_entry   *shared;
+    struct grant_entry  **shared;
     /* Active grant table. */
-    struct active_grant_entry *active;
+    struct active_grant_entry **active;
     /* Mapping tracking table. */
-    struct grant_mapping *maptrack;
+    struct grant_mapping **maptrack;
     unsigned int          maptrack_head;
-    unsigned int          maptrack_order;
     unsigned int          maptrack_limit;
     unsigned int          map_count;
     /* Lock protecting updates to active and shared grant tables. */
@@ -96,4 +102,22 @@ gnttab_release_mappings(
 gnttab_release_mappings(
     struct domain *d);
 
+/* Increase the size of a domain's grant table.
+ * Caller must hold d's grant table lock.
+ */
+int
+gnttab_grow_table(struct domain *d, unsigned int req_nr_frames);
+
+/* Number of grant table frames. Caller must hold d's grant table lock. */
+static inline unsigned int nr_grant_frames(struct grant_table *gt)
+{
+    return gt->nr_grant_frames;
+}
+
+/* Number of grant table entries. Caller must hold d's grant table lock. */
+static inline unsigned int nr_grant_entries(struct grant_table *gt)
+{
+    return (nr_grant_frames(gt) << PAGE_SHIFT) / sizeof(grant_entry_t);
+}
+
 #endif /* __XEN_GRANT_TABLE_H__ */

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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] Dynamic grant-table sizing., Xen patchbot-unstable <=