aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/core/gnttab.c241
-rw-r--r--linux-2.6-xen-sparse/include/xen/gnttab.h13
-rw-r--r--xen/arch/ia64/xen/mm.c4
-rw-r--r--xen/arch/x86/mm.c12
-rw-r--r--xen/common/compat/grant_table.c3
-rw-r--r--xen/common/grant_table.c491
-rw-r--r--xen/include/asm-ia64/grant_table.h2
-rw-r--r--xen/include/asm-powerpc/grant_table.h2
-rw-r--r--xen/include/asm-x86/grant_table.h6
-rw-r--r--xen/include/public/grant_table.h19
-rw-r--r--xen/include/xen/grant_table.h38
11 files changed, 647 insertions, 184 deletions
diff --git a/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c b/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c
index 1cab1d822b..80226fb6e8 100644
--- a/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c
+++ b/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c
@@ -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 GNTTAB_LIST_END 0xffffffff
+#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(grant_entry_t))
-#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];
+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 ref)
{
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 domid, unsigned long frame,
{
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_t domid, unsigned long pfn)
{
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_ref_t head)
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 count, grant_ref_t *head)
{
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_ref_t *private_head)
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 @@ EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
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 gnttab_free_callback *callback)
}
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, struct page *pmd_page,
}
#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
+ 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)
+static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
{
- unsigned long frames;
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_resume(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 --git a/linux-2.6-xen-sparse/include/xen/gnttab.h b/linux-2.6-xen-sparse/include/xen/gnttab.h
index f1543c01d6..2f02fe3cd3 100644
--- a/linux-2.6-xen-sparse/include/xen/gnttab.h
+++ b/linux-2.6-xen-sparse/include/xen/gnttab.h
@@ -43,13 +43,6 @@
#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;
void (*fn)(void *);
@@ -109,12 +102,6 @@ void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
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 --git a/xen/arch/ia64/xen/mm.c b/xen/arch/ia64/xen/mm.c
index 9b153b7f51..23ee2ffe27 100644
--- a/xen/arch/ia64/xen/mm.c
+++ b/xen/arch/ia64/xen/mm.c
@@ -2077,8 +2077,10 @@ arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
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 --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 5d043ad598..d7f13718e4 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -2971,8 +2971,16 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
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 --git a/xen/common/compat/grant_table.c b/xen/common/compat/grant_table.c
index 9680a1779d..b080447110 100644
--- a/xen/common/compat/grant_table.c
+++ b/xen/common/compat/grant_table.c
@@ -101,7 +101,7 @@ int compat_grant_table_op(unsigned int cmd,
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 cmd,
}
if ( rc == 0 )
{
- BUG_ON(nat.setup->nr_frames > NR_GRANT_FRAMES);
#define XLAT_gnttab_setup_table_HNDL_frame_list(_d_, _s_) \
do \
{ \
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index c2f8999751..f6961d5b1a 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -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,11 +123,63 @@ static inline void
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;
+}
+
/*
* Returns 0 if TLB flush / invalidate required by caller.
* va will indicate the address to be invalidated.
@@ -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) )
+ if ( unlikely((op->flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0) )
{
- gdprintk(XENLOG_INFO, "Bad ref (%d) or flags (%x).\n",
- op->ref, op->flags);
+ gdprintk(XENLOG_INFO, "Bad flags in grant map op (%x).\n", op->flags);
op->status = GNTST_bad_gntref;
return;
}
@@ -132,52 +236,23 @@ __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);
+ put_domain(rd);
+ gdprintk(XENLOG_INFO, "Failed to obtain maptrack handle.\n");
+ op->status = GNTST_no_device_space;
+ return;
}
- act = &rd->grant_table->active[op->ref];
- sha = &rd->grant_table->shared[op->ref];
-
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 &&
((act->domid != ld->domain_id) ||
@@ -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;
@@ -297,6 +374,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) ?
GNTPIN_devr_inc : GNTPIN_devw_inc;
@@ -355,16 +435,22 @@ __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;
+ }
+
dom = map->domid;
ref = map->ref;
flags = map->flags;
@@ -379,11 +465,11 @@ __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 )
{
frame = act->frame;
@@ -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,6 +686,9 @@ 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:
@@ -540,6 +698,58 @@ gnttab_setup_table(
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;
+
+ return 0;
+}
+
/*
* Check that the given grant reference (rd,ref) allows 'ld' to transfer
* ownership of a page frame. If so, lock down the grant entry.
@@ -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) )
+ if ( unlikely((rgt = rd->grant_table) == NULL) )
{
- gdprintk(XENLOG_INFO, "Dom %d has no g.t., or ref is bad (%d).\n",
- rd->domain_id, ref);
+ 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 @@ static void
__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);
+ 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 < NR_GRANT_FRAMES; i++ )
+ 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);
+ xfree(t);
d->grant_table = NULL;
}
diff --git a/xen/include/asm-ia64/grant_table.h b/xen/include/asm-ia64/grant_table.h
index 6b62d6abd3..106b0aad68 100644
--- a/xen/include/asm-ia64/grant_table.h
+++ b/xen/include/asm-ia64/grant_table.h
@@ -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 --git a/xen/include/asm-powerpc/grant_table.h b/xen/include/asm-powerpc/grant_table.h
index 81b1b1ed62..a50e51fca7 100644
--- a/xen/include/asm-powerpc/grant_table.h
+++ b/xen/include/asm-powerpc/grant_table.h
@@ -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 --git a/xen/include/asm-x86/grant_table.h b/xen/include/asm-x86/grant_table.h
index 9941a5c6f8..32dc43b898 100644
--- a/xen/include/asm-x86/grant_table.h
+++ b/xen/include/asm-x86/grant_table.h
@@ -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 --git a/xen/include/public/grant_table.h b/xen/include/public/grant_table.h
index 9622b56d02..222ac37b86 100644
--- a/xen/include/public/grant_table.h
+++ b/xen/include/public/grant_table.h
@@ -309,6 +309,25 @@ typedef struct gnttab_copy {
} 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);
+
/*
* Bitfield values for update_pin_status.flags.
diff --git a/xen/include/xen/grant_table.h b/xen/include/xen/grant_table.h
index 9fc63a0cbb..54ea021683 100644
--- a/xen/include/xen/grant_table.h
+++ b/xen/include/xen/grant_table.h
@@ -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 @@ void
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__ */