ia64/xen-unstable

changeset 13970:70f05d642a2e

Dynamic grant-table sizing.
Signed-off-by: Christopher CLark <christopher.clark@cl.cam.ac.uk>
Signed-off-by: Andrei Petrov <andrei.petrov@xensource.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Thu Feb 15 10:54:12 2007 +0000 (2007-02-15)
parents 047b3e9f9032
children 4bd0ea9c499f
files linux-2.6-xen-sparse/drivers/xen/core/gnttab.c linux-2.6-xen-sparse/include/xen/gnttab.h xen/arch/ia64/xen/mm.c xen/arch/x86/mm.c xen/common/compat/grant_table.c xen/common/grant_table.c xen/include/asm-ia64/grant_table.h xen/include/asm-powerpc/grant_table.h xen/include/asm-x86/grant_table.h xen/include/public/grant_table.h xen/include/xen/grant_table.h
line diff
     1.1 --- a/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c	Thu Feb 15 10:34:21 2007 +0000
     1.2 +++ b/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c	Thu Feb 15 10:54:12 2007 +0000
     1.3 @@ -3,7 +3,7 @@
     1.4   *
     1.5   * Granting foreign access to our memory reservation.
     1.6   *
     1.7 - * Copyright (c) 2005, Christopher Clark
     1.8 + * Copyright (c) 2005-2006, Christopher Clark
     1.9   * Copyright (c) 2004-2005, K A Fraser
    1.10   *
    1.11   * This program is free software; you can redistribute it and/or
    1.12 @@ -35,7 +35,6 @@
    1.13  #include <linux/module.h>
    1.14  #include <linux/sched.h>
    1.15  #include <linux/mm.h>
    1.16 -#include <linux/vmalloc.h>
    1.17  #include <xen/interface/xen.h>
    1.18  #include <xen/gnttab.h>
    1.19  #include <asm/pgtable.h>
    1.20 @@ -43,6 +42,7 @@
    1.21  #include <asm/synch_bitops.h>
    1.22  #include <asm/io.h>
    1.23  #include <xen/interface/memory.h>
    1.24 +#include <xen/driver_util.h>
    1.25  
    1.26  #ifdef HAVE_XEN_PLATFORM_COMPAT_H
    1.27  #include <xen/platform-compat.h>
    1.28 @@ -50,37 +50,51 @@
    1.29  
    1.30  /* External tools reserve first few grant table entries. */
    1.31  #define NR_RESERVED_ENTRIES 8
    1.32 +#define GNTTAB_LIST_END 0xffffffff
    1.33 +#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(grant_entry_t))
    1.34  
    1.35 -#define NR_GRANT_ENTRIES \
    1.36 -	(NR_GRANT_FRAMES * PAGE_SIZE / sizeof(struct grant_entry))
    1.37 -#define GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1)
    1.38 -
    1.39 -static grant_ref_t gnttab_list[NR_GRANT_ENTRIES];
    1.40 +static grant_ref_t **gnttab_list;
    1.41 +static unsigned int nr_grant_frames;
    1.42 +static unsigned int boot_max_nr_grant_frames;
    1.43  static int gnttab_free_count;
    1.44  static grant_ref_t gnttab_free_head;
    1.45  static DEFINE_SPINLOCK(gnttab_list_lock);
    1.46  
    1.47  static struct grant_entry *shared;
    1.48 +#ifndef CONFIG_XEN
    1.49 +static unsigned long resume_frames;
    1.50 +#endif
    1.51  
    1.52  static struct gnttab_free_callback *gnttab_free_callback_list;
    1.53  
    1.54 +static int gnttab_expand(unsigned int req_entries);
    1.55 +
    1.56 +#define RPP (PAGE_SIZE / sizeof(grant_ref_t))
    1.57 +#define gnttab_entry(entry) (gnttab_list[(entry) / RPP][(entry) % RPP])
    1.58 +
    1.59  static int get_free_entries(int count)
    1.60  {
    1.61  	unsigned long flags;
    1.62 -	int ref;
    1.63 +	int ref, rc;
    1.64  	grant_ref_t head;
    1.65 +
    1.66  	spin_lock_irqsave(&gnttab_list_lock, flags);
    1.67 -	if (gnttab_free_count < count) {
    1.68 +
    1.69 +	if ((gnttab_free_count < count) &&
    1.70 +	    ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
    1.71  		spin_unlock_irqrestore(&gnttab_list_lock, flags);
    1.72 -		return -1;
    1.73 +		return rc;
    1.74  	}
    1.75 +
    1.76  	ref = head = gnttab_free_head;
    1.77  	gnttab_free_count -= count;
    1.78  	while (count-- > 1)
    1.79 -		head = gnttab_list[head];
    1.80 -	gnttab_free_head = gnttab_list[head];
    1.81 -	gnttab_list[head] = GNTTAB_LIST_END;
    1.82 +		head = gnttab_entry(head);
    1.83 + 	gnttab_free_head = gnttab_entry(head);
    1.84 +	gnttab_entry(head) = GNTTAB_LIST_END;
    1.85 +
    1.86  	spin_unlock_irqrestore(&gnttab_list_lock, flags);
    1.87 +
    1.88  	return ref;
    1.89  }
    1.90  
    1.91 @@ -116,7 +130,7 @@ static void put_free_entry(grant_ref_t r
    1.92  {
    1.93  	unsigned long flags;
    1.94  	spin_lock_irqsave(&gnttab_list_lock, flags);
    1.95 -	gnttab_list[ref] = gnttab_free_head;
    1.96 +	gnttab_entry(ref) = gnttab_free_head;
    1.97  	gnttab_free_head = ref;
    1.98  	gnttab_free_count++;
    1.99  	check_free_callbacks();
   1.100 @@ -132,7 +146,7 @@ int gnttab_grant_foreign_access(domid_t 
   1.101  {
   1.102  	int ref;
   1.103  
   1.104 -	if (unlikely((ref = get_free_entry()) == -1))
   1.105 +	if (unlikely((ref = get_free_entry()) < 0))
   1.106  		return -ENOSPC;
   1.107  
   1.108  	shared[ref].frame = frame;
   1.109 @@ -202,7 +216,7 @@ int gnttab_grant_foreign_transfer(domid_
   1.110  {
   1.111  	int ref;
   1.112  
   1.113 -	if (unlikely((ref = get_free_entry()) == -1))
   1.114 +	if (unlikely((ref = get_free_entry()) < 0))
   1.115  		return -ENOSPC;
   1.116  	gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
   1.117  
   1.118 @@ -273,11 +287,11 @@ void gnttab_free_grant_references(grant_
   1.119  		return;
   1.120  	spin_lock_irqsave(&gnttab_list_lock, flags);
   1.121  	ref = head;
   1.122 -	while (gnttab_list[ref] != GNTTAB_LIST_END) {
   1.123 -		ref = gnttab_list[ref];
   1.124 +	while (gnttab_entry(ref) != GNTTAB_LIST_END) {
   1.125 +		ref = gnttab_entry(ref);
   1.126  		count++;
   1.127  	}
   1.128 -	gnttab_list[ref] = gnttab_free_head;
   1.129 +	gnttab_entry(ref) = gnttab_free_head;
   1.130  	gnttab_free_head = head;
   1.131  	gnttab_free_count += count;
   1.132  	check_free_callbacks();
   1.133 @@ -289,7 +303,7 @@ int gnttab_alloc_grant_references(u16 co
   1.134  {
   1.135  	int h = get_free_entries(count);
   1.136  
   1.137 -	if (h == -1)
   1.138 +	if (h < 0)
   1.139  		return -ENOSPC;
   1.140  
   1.141  	*head = h;
   1.142 @@ -309,7 +323,7 @@ int gnttab_claim_grant_reference(grant_r
   1.143  	grant_ref_t g = *private_head;
   1.144  	if (unlikely(g == GNTTAB_LIST_END))
   1.145  		return -ENOSPC;
   1.146 -	*private_head = gnttab_list[g];
   1.147 +	*private_head = gnttab_entry(g);
   1.148  	return g;
   1.149  }
   1.150  EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
   1.151 @@ -317,7 +331,7 @@ EXPORT_SYMBOL_GPL(gnttab_claim_grant_ref
   1.152  void gnttab_release_grant_reference(grant_ref_t *private_head,
   1.153  				    grant_ref_t release)
   1.154  {
   1.155 -	gnttab_list[release] = *private_head;
   1.156 +	gnttab_entry(release) = *private_head;
   1.157  	*private_head = release;
   1.158  }
   1.159  EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
   1.160 @@ -356,6 +370,64 @@ void gnttab_cancel_free_callback(struct 
   1.161  }
   1.162  EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
   1.163  
   1.164 +static int grow_gnttab_list(unsigned int more_frames)
   1.165 +{
   1.166 +	unsigned int new_nr_grant_frames, extra_entries, i;
   1.167 +
   1.168 +	new_nr_grant_frames = nr_grant_frames + more_frames;
   1.169 +	extra_entries       = more_frames * GREFS_PER_GRANT_FRAME;
   1.170 +
   1.171 +	for (i = nr_grant_frames; i < new_nr_grant_frames; i++)
   1.172 +	{
   1.173 +		gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
   1.174 +		if (!gnttab_list[i])
   1.175 +			goto grow_nomem;
   1.176 +	}
   1.177 +
   1.178 +
   1.179 +	for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames;
   1.180 +	     i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
   1.181 +		gnttab_entry(i) = i + 1;
   1.182 +
   1.183 +	gnttab_entry(i) = gnttab_free_head;
   1.184 +	gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames;
   1.185 +	gnttab_free_count += extra_entries;
   1.186 +
   1.187 +	nr_grant_frames = new_nr_grant_frames;
   1.188 +
   1.189 +	check_free_callbacks();
   1.190 +
   1.191 +	return 0;
   1.192 +	
   1.193 +grow_nomem:
   1.194 +	for ( ; i >= nr_grant_frames; i--)
   1.195 +		free_page((unsigned long) gnttab_list[i]);
   1.196 +	return -ENOMEM;
   1.197 +}
   1.198 +
   1.199 +static unsigned int __max_nr_grant_frames(void)
   1.200 +{
   1.201 +	struct gnttab_query_size query;
   1.202 +	int rc;
   1.203 +
   1.204 +	query.dom = DOMID_SELF;
   1.205 +
   1.206 +	rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
   1.207 +	if ((rc < 0) || (query.status != GNTST_okay))
   1.208 +		return 4; /* Legacy max supported number of frames */
   1.209 +
   1.210 +	return query.max_nr_frames;
   1.211 +}
   1.212 +
   1.213 +static inline unsigned int max_nr_grant_frames(void)
   1.214 +{
   1.215 +	unsigned int xen_max = __max_nr_grant_frames();
   1.216 +
   1.217 +	if (xen_max > boot_max_nr_grant_frames)
   1.218 +		return boot_max_nr_grant_frames;
   1.219 +	return xen_max;
   1.220 +}
   1.221 +
   1.222  #ifdef CONFIG_XEN
   1.223  
   1.224  #ifndef __ia64__
   1.225 @@ -378,49 +450,62 @@ static int unmap_pte_fn(pte_t *pte, stru
   1.226  }
   1.227  #endif
   1.228  
   1.229 -int gnttab_resume(void)
   1.230 +static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
   1.231  {
   1.232  	struct gnttab_setup_table setup;
   1.233 -	unsigned long frames[NR_GRANT_FRAMES];
   1.234 +	unsigned long *frames;
   1.235 +	unsigned int nr_gframes = end_idx + 1;
   1.236  	int rc;
   1.237 -#ifndef __ia64__
   1.238 -	void *pframes = frames;
   1.239 -	struct vm_struct *area;
   1.240 -#endif
   1.241 +
   1.242 +	frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
   1.243 +	if (!frames)
   1.244 +		return -ENOMEM;
   1.245  
   1.246  	setup.dom        = DOMID_SELF;
   1.247 -	setup.nr_frames  = NR_GRANT_FRAMES;
   1.248 +	setup.nr_frames  = nr_gframes;
   1.249  	set_xen_guest_handle(setup.frame_list, frames);
   1.250  
   1.251  	rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
   1.252 -	if (rc == -ENOSYS)
   1.253 +	if (rc == -ENOSYS) {
   1.254 +		kfree(frames);
   1.255  		return -ENOSYS;
   1.256 +	}
   1.257  
   1.258  	BUG_ON(rc || setup.status);
   1.259  
   1.260  #ifndef __ia64__
   1.261  	if (shared == NULL) {
   1.262 -		area = get_vm_area(PAGE_SIZE * NR_GRANT_FRAMES, VM_IOREMAP);
   1.263 +		struct vm_struct *area;
   1.264 +		area = alloc_vm_area(PAGE_SIZE * max_nr_grant_frames());
   1.265  		BUG_ON(area == NULL);
   1.266  		shared = area->addr;
   1.267  	}
   1.268  	rc = apply_to_page_range(&init_mm, (unsigned long)shared,
   1.269 -				 PAGE_SIZE * NR_GRANT_FRAMES,
   1.270 -				 map_pte_fn, &pframes);
   1.271 +				 PAGE_SIZE * nr_gframes,
   1.272 +				 map_pte_fn, &frames);
   1.273  	BUG_ON(rc);
   1.274 +        frames -= nr_gframes; /* adjust after map_pte_fn() */
   1.275  #else
   1.276  	shared = __va(frames[0] << PAGE_SHIFT);
   1.277 -	printk("grant table at %p\n", shared);
   1.278  #endif
   1.279  
   1.280 +	kfree(frames);
   1.281 +
   1.282  	return 0;
   1.283  }
   1.284  
   1.285 +int gnttab_resume(void)
   1.286 +{
   1.287 +	if (max_nr_grant_frames() < nr_grant_frames)
   1.288 +		return -ENOSYS;
   1.289 +	return gnttab_map(0, nr_grant_frames - 1);
   1.290 +}
   1.291 +
   1.292  int gnttab_suspend(void)
   1.293  {
   1.294  #ifndef __ia64__
   1.295  	apply_to_page_range(&init_mm, (unsigned long)shared,
   1.296 -			    PAGE_SIZE * NR_GRANT_FRAMES,
   1.297 +			    PAGE_SIZE * nr_grant_frames,
   1.298  			    unmap_pte_fn, NULL);
   1.299  #endif
   1.300  	return 0;
   1.301 @@ -430,24 +515,39 @@ int gnttab_suspend(void)
   1.302  
   1.303  #include <platform-pci.h>
   1.304  
   1.305 -int gnttab_resume(void)
   1.306 +static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
   1.307  {
   1.308 -	unsigned long frames;
   1.309  	struct xen_add_to_physmap xatp;
   1.310  	unsigned int i;
   1.311  
   1.312 -	frames = alloc_xen_mmio(PAGE_SIZE * NR_GRANT_FRAMES);
   1.313 -
   1.314 -	for (i = 0; i < NR_GRANT_FRAMES; i++) {
   1.315 +	/* Loop backwards, so that the first hypercall has the largest index,
   1.316 +	 * ensuring that the table will grow only once.
   1.317 +	 */
   1.318 +	for (i = end_idx; i >= start_idx; i--) {
   1.319  		xatp.domid = DOMID_SELF;
   1.320  		xatp.idx = i;
   1.321  		xatp.space = XENMAPSPACE_grant_table;
   1.322 -		xatp.gpfn = (frames >> PAGE_SHIFT) + i;
   1.323 +		xatp.gpfn = (resume_frames >> PAGE_SHIFT) + i;
   1.324  		if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
   1.325  			BUG();
   1.326  	}
   1.327 +}
   1.328  
   1.329 -	shared = ioremap(frames, PAGE_SIZE * NR_GRANT_FRAMES);
   1.330 +int gnttab_resume(void)
   1.331 +{
   1.332 +	struct xen_add_to_physmap xatp;
   1.333 +	unsigned int i, max_nr_gframes, nr_gframes;
   1.334 +
   1.335 +	nr_gframes = nr_grant_frames;
   1.336 +	max_nr_gframes = max_nr_grant_frames();
   1.337 +	if (max_nr_gframes < nr_gframes)
   1.338 +		return -ENOSYS;
   1.339 +
   1.340 +	resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes);
   1.341 +
   1.342 +	gnttab_map(0, nr_gframes - 1);
   1.343 +
   1.344 +	shared = ioremap(resume_frames, PAGE_SIZE * max_nr_gframes);
   1.345  	if (shared == NULL) {
   1.346  		printk("error to ioremap gnttab share frames\n");
   1.347  		return -1;
   1.348 @@ -459,28 +559,79 @@ int gnttab_resume(void)
   1.349  int gnttab_suspend(void)
   1.350  {
   1.351  	iounmap(shared);
   1.352 +	resume_frames = 0;
   1.353  	return 0;
   1.354  }
   1.355  
   1.356  #endif /* !CONFIG_XEN */
   1.357  
   1.358 +static int gnttab_expand(unsigned int req_entries)
   1.359 +{
   1.360 +	int rc;
   1.361 +	unsigned int cur, extra;
   1.362 +
   1.363 +	cur = nr_grant_frames;
   1.364 +	extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) /
   1.365 +		 GREFS_PER_GRANT_FRAME);
   1.366 +	if (cur + extra > max_nr_grant_frames())
   1.367 +		return -ENOSPC;
   1.368 +
   1.369 +	if ((rc = gnttab_map(cur, cur + extra - 1)) == 0)
   1.370 +		rc = grow_gnttab_list(extra);
   1.371 +
   1.372 +	return rc;
   1.373 +}
   1.374 +
   1.375  int __devinit gnttab_init(void)
   1.376  {
   1.377  	int i;
   1.378 +	unsigned int max_nr_glist_frames;
   1.379 +	unsigned int nr_init_grefs;
   1.380  
   1.381  	if (!is_running_on_xen())
   1.382  		return -ENODEV;
   1.383  
   1.384 +	nr_grant_frames = 1;
   1.385 +	boot_max_nr_grant_frames = __max_nr_grant_frames();
   1.386 +
   1.387 +	/* Determine the maximum number of frames required for the
   1.388 +	 * grant reference free list on the current hypervisor.
   1.389 +	 */
   1.390 +	max_nr_glist_frames = (boot_max_nr_grant_frames *
   1.391 +			       GREFS_PER_GRANT_FRAME /
   1.392 +			       (PAGE_SIZE / sizeof(grant_ref_t)));
   1.393 +
   1.394 +	gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
   1.395 +			      GFP_KERNEL);
   1.396 +	if (gnttab_list == NULL)
   1.397 +		return -ENOMEM;
   1.398 +
   1.399 +	for (i = 0; i < nr_grant_frames; i++) {
   1.400 +		gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
   1.401 +		if (gnttab_list[i] == NULL)
   1.402 +			goto ini_nomem;
   1.403 +	}
   1.404 +
   1.405  	if (gnttab_resume() < 0)
   1.406  		return -ENODEV;
   1.407  
   1.408 -	for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++)
   1.409 -		gnttab_list[i] = i + 1;
   1.410 -	gnttab_free_count = NR_GRANT_ENTRIES - NR_RESERVED_ENTRIES;
   1.411 +	nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME;
   1.412 +
   1.413 +	for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
   1.414 +		gnttab_entry(i) = i + 1;
   1.415 +
   1.416 +	gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
   1.417 +	gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
   1.418  	gnttab_free_head  = NR_RESERVED_ENTRIES;
   1.419  
   1.420  	printk("Grant table initialized\n");
   1.421  	return 0;
   1.422 +
   1.423 + ini_nomem:
   1.424 +	for (i--; i >= 0; i--)
   1.425 +		free_page((unsigned long)gnttab_list[i]);
   1.426 +	kfree(gnttab_list);
   1.427 +	return -ENOMEM;
   1.428  }
   1.429  
   1.430  #ifdef CONFIG_XEN
     2.1 --- a/linux-2.6-xen-sparse/include/xen/gnttab.h	Thu Feb 15 10:34:21 2007 +0000
     2.2 +++ b/linux-2.6-xen-sparse/include/xen/gnttab.h	Thu Feb 15 10:54:12 2007 +0000
     2.3 @@ -43,13 +43,6 @@
     2.4  #include <xen/interface/grant_table.h>
     2.5  #include <xen/features.h>
     2.6  
     2.7 -/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */
     2.8 -#ifdef __ia64__
     2.9 -#define NR_GRANT_FRAMES 1
    2.10 -#else
    2.11 -#define NR_GRANT_FRAMES 4
    2.12 -#endif
    2.13 -
    2.14  struct gnttab_free_callback {
    2.15  	struct gnttab_free_callback *next;
    2.16  	void (*fn)(void *);
    2.17 @@ -109,12 +102,6 @@ void gnttab_grant_foreign_access_ref(gra
    2.18  void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid,
    2.19  				       unsigned long pfn);
    2.20  
    2.21 -#ifdef __ia64__
    2.22 -#define gnttab_map_vaddr(map) __va(map.dev_bus_addr)
    2.23 -#else
    2.24 -#define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr))
    2.25 -#endif
    2.26 -
    2.27  int gnttab_suspend(void);
    2.28  int gnttab_resume(void);
    2.29  
     3.1 --- a/xen/arch/ia64/xen/mm.c	Thu Feb 15 10:34:21 2007 +0000
     3.2 +++ b/xen/arch/ia64/xen/mm.c	Thu Feb 15 10:54:12 2007 +0000
     3.3 @@ -2077,8 +2077,10 @@ arch_memory_op(int op, XEN_GUEST_HANDLE(
     3.4                  mfn = virt_to_mfn(d->shared_info);
     3.5              break;
     3.6          case XENMAPSPACE_grant_table:
     3.7 -            if (xatp.idx < NR_GRANT_FRAMES)
     3.8 +            spin_lock(d->grant_table->lock);
     3.9 +            if ( xatp.idx < nr_grant_frames(d->grant_table) )
    3.10                  mfn = virt_to_mfn(d->grant_table->shared) + xatp.idx;
    3.11 +            spin_unlock(d->grant_table->lock);
    3.12              break;
    3.13          default:
    3.14              break;
     4.1 --- a/xen/arch/x86/mm.c	Thu Feb 15 10:34:21 2007 +0000
     4.2 +++ b/xen/arch/x86/mm.c	Thu Feb 15 10:54:12 2007 +0000
     4.3 @@ -2971,8 +2971,16 @@ long arch_memory_op(int op, XEN_GUEST_HA
     4.4                  mfn = virt_to_mfn(d->shared_info);
     4.5              break;
     4.6          case XENMAPSPACE_grant_table:
     4.7 -            if ( xatp.idx < NR_GRANT_FRAMES )
     4.8 -                mfn = virt_to_mfn(d->grant_table->shared) + xatp.idx;
     4.9 +            spin_lock(&d->grant_table->lock);
    4.10 +
    4.11 +            if ( (xatp.idx >= nr_grant_frames(d->grant_table)) &&
    4.12 +                 (xatp.idx < max_nr_grant_frames) )
    4.13 +                gnttab_grow_table(d, xatp.idx + 1);
    4.14 +
    4.15 +            if ( xatp.idx < nr_grant_frames(d->grant_table) )
    4.16 +                mfn = virt_to_mfn(d->grant_table->shared[xatp.idx]);
    4.17 +
    4.18 +            spin_unlock(&d->grant_table->lock);
    4.19              break;
    4.20          default:
    4.21              break;
     5.1 --- a/xen/common/compat/grant_table.c	Thu Feb 15 10:34:21 2007 +0000
     5.2 +++ b/xen/common/compat/grant_table.c	Thu Feb 15 10:54:12 2007 +0000
     5.3 @@ -101,7 +101,7 @@ int compat_grant_table_op(unsigned int c
     5.4                  rc = -EFAULT;
     5.5              else
     5.6              {
     5.7 -                BUILD_BUG_ON((COMPAT_ARG_XLAT_SIZE - sizeof(*nat.setup)) / sizeof(*nat.setup->frame_list.p) < NR_GRANT_FRAMES);
     5.8 +                BUG_ON((COMPAT_ARG_XLAT_SIZE - sizeof(*nat.setup)) / sizeof(*nat.setup->frame_list.p) < max_nr_grant_frames);
     5.9  #define XLAT_gnttab_setup_table_HNDL_frame_list(_d_, _s_) \
    5.10                  set_xen_guest_handle((_d_)->frame_list, (unsigned long *)(nat.setup + 1))
    5.11                  XLAT_gnttab_setup_table(nat.setup, &cmp.setup);
    5.12 @@ -110,7 +110,6 @@ int compat_grant_table_op(unsigned int c
    5.13              }
    5.14              if ( rc == 0 )
    5.15              {
    5.16 -                BUG_ON(nat.setup->nr_frames > NR_GRANT_FRAMES);
    5.17  #define XLAT_gnttab_setup_table_HNDL_frame_list(_d_, _s_) \
    5.18                  do \
    5.19                  { \
     6.1 --- a/xen/common/grant_table.c	Thu Feb 15 10:34:21 2007 +0000
     6.2 +++ b/xen/common/grant_table.c	Thu Feb 15 10:54:12 2007 +0000
     6.3 @@ -4,7 +4,7 @@
     6.4   * Mechanism for granting foreign access to page frames, and receiving
     6.5   * page-ownership transfers.
     6.6   * 
     6.7 - * Copyright (c) 2005 Christopher Clark
     6.8 + * Copyright (c) 2005-2006 Christopher Clark
     6.9   * Copyright (c) 2004 K A Fraser
    6.10   * Copyright (c) 2005 Andrew Warfield
    6.11   * Modifications by Geoffrey Lefebvre are (c) Intel Research Cambridge
    6.12 @@ -35,6 +35,15 @@
    6.13  #include <xen/domain_page.h>
    6.14  #include <acm/acm_hooks.h>
    6.15  
    6.16 +unsigned int max_nr_grant_frames = DEFAULT_MAX_NR_GRANT_FRAMES;
    6.17 +integer_param("gnttab_max_nr_frames", max_nr_grant_frames);
    6.18 +
    6.19 +/* The maximum number of grant mappings is defined as a multiplier of the
    6.20 + * maximum number of grant table entries. This defines the multiplier used.
    6.21 + * Pretty arbitrary. [POLICY]
    6.22 + */
    6.23 +#define MAX_MAPTRACK_TO_GRANTS_RATIO 8
    6.24 +
    6.25  /*
    6.26   * The first two members of a grant entry are updated as a combined pair.
    6.27   * The following union allows that to happen in an endian-neutral fashion.
    6.28 @@ -54,14 +63,58 @@ union grant_combo {
    6.29          goto _lbl;                              \
    6.30      } while ( 0 )
    6.31  
    6.32 +#define MAPTRACK_PER_PAGE (PAGE_SIZE / sizeof(struct grant_mapping))
    6.33 +#define maptrack_entry(t, e) \
    6.34 +    ((t)->maptrack[(e)/MAPTRACK_PER_PAGE][(e)%MAPTRACK_PER_PAGE])
    6.35 +
    6.36 +static inline unsigned int
    6.37 +nr_maptrack_frames(struct grant_table *t)
    6.38 +{
    6.39 +    return t->maptrack_limit / MAPTRACK_PER_PAGE;
    6.40 +}
    6.41 +
    6.42 +static unsigned inline int max_nr_maptrack_frames(void)
    6.43 +{
    6.44 +    return (max_nr_grant_frames * MAX_MAPTRACK_TO_GRANTS_RATIO);
    6.45 +}
    6.46 +
    6.47 +static inline unsigned int
    6.48 +num_act_frames_from_sha_frames(const unsigned int num)
    6.49 +{
    6.50 +    /* How many frames are needed for the active grant table,
    6.51 +     * given the size of the shared grant table?
    6.52 +     *
    6.53 +     * act_per_page = PAGE_SIZE / sizeof(active_grant_entry_t);
    6.54 +     * sha_per_page = PAGE_SIZE / sizeof(grant_entry_t);
    6.55 +     * num_sha_entries = num * sha_per_page;
    6.56 +     * num_act_frames = (num_sha_entries + (act_per_page-1)) / act_per_page;
    6.57 +     */
    6.58 +    return ((num * (PAGE_SIZE / sizeof(grant_entry_t))) +
    6.59 +            ((PAGE_SIZE / sizeof(struct active_grant_entry))-1))
    6.60 +           / (PAGE_SIZE / sizeof(struct active_grant_entry));
    6.61 +}
    6.62 +
    6.63 +static inline unsigned int
    6.64 +nr_active_grant_frames(struct grant_table *gt)
    6.65 +{
    6.66 +    return num_act_frames_from_sha_frames(nr_grant_frames(gt));
    6.67 +}
    6.68 +
    6.69 +#define SHGNT_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_t))
    6.70 +#define shared_entry(t, e) \
    6.71 +    ((t)->shared[(e)/SHGNT_PER_PAGE][(e)%SHGNT_PER_PAGE])
    6.72 +#define ACGNT_PER_PAGE (PAGE_SIZE / sizeof(struct active_grant_entry))
    6.73 +#define active_entry(t, e) \
    6.74 +    ((t)->active[(e)/ACGNT_PER_PAGE][(e)%ACGNT_PER_PAGE])
    6.75 +
    6.76  static inline int
    6.77 -get_maptrack_handle(
    6.78 +__get_maptrack_handle(
    6.79      struct grant_table *t)
    6.80  {
    6.81      unsigned int h;
    6.82      if ( unlikely((h = t->maptrack_head) == (t->maptrack_limit - 1)) )
    6.83          return -1;
    6.84 -    t->maptrack_head = t->maptrack[h].ref;
    6.85 +    t->maptrack_head = maptrack_entry(t, h).ref;
    6.86      t->map_count++;
    6.87      return h;
    6.88  }
    6.89 @@ -70,11 +123,63 @@ static inline void
    6.90  put_maptrack_handle(
    6.91      struct grant_table *t, int handle)
    6.92  {
    6.93 -    t->maptrack[handle].ref = t->maptrack_head;
    6.94 +    maptrack_entry(t, handle).ref = t->maptrack_head;
    6.95      t->maptrack_head = handle;
    6.96      t->map_count--;
    6.97  }
    6.98  
    6.99 +static inline int
   6.100 +get_maptrack_handle(
   6.101 +    struct grant_table *lgt)
   6.102 +{
   6.103 +    int                   i;
   6.104 +    grant_handle_t        handle;
   6.105 +    struct grant_mapping *new_mt;
   6.106 +    unsigned int          new_mt_limit, nr_frames;
   6.107 +
   6.108 +    if ( unlikely((handle = __get_maptrack_handle(lgt)) == -1) )
   6.109 +    {
   6.110 +        spin_lock(&lgt->lock);
   6.111 +
   6.112 +        if ( unlikely((handle = __get_maptrack_handle(lgt)) == -1) )
   6.113 +        {
   6.114 +            nr_frames = nr_maptrack_frames(lgt);
   6.115 +            if ( nr_frames >= max_nr_maptrack_frames() )
   6.116 +            {
   6.117 +                spin_unlock(&lgt->lock);
   6.118 +                return -1;
   6.119 +            }
   6.120 +
   6.121 +            new_mt = alloc_xenheap_page();
   6.122 +            if ( new_mt == NULL )
   6.123 +            {
   6.124 +                spin_unlock(&lgt->lock);
   6.125 +                return -1;
   6.126 +            }
   6.127 +
   6.128 +            memset(new_mt, 0, PAGE_SIZE);
   6.129 +
   6.130 +            new_mt_limit = lgt->maptrack_limit + MAPTRACK_PER_PAGE;
   6.131 +
   6.132 +            for ( i = lgt->maptrack_limit; i < new_mt_limit; i++ )
   6.133 +            {
   6.134 +                new_mt[i % MAPTRACK_PER_PAGE].ref = i+1;
   6.135 +                new_mt[i % MAPTRACK_PER_PAGE].flags = 0;
   6.136 +            }
   6.137 +
   6.138 +            lgt->maptrack[nr_frames] = new_mt;
   6.139 +            lgt->maptrack_limit      = new_mt_limit;
   6.140 +
   6.141 +            gdprintk(XENLOG_INFO,
   6.142 +                    "Increased maptrack size to %u frames.\n", nr_frames + 1);
   6.143 +            handle = __get_maptrack_handle(lgt);
   6.144 +        }
   6.145 +
   6.146 +        spin_unlock(&lgt->lock);
   6.147 +    }
   6.148 +    return handle;
   6.149 +}
   6.150 +
   6.151  /*
   6.152   * Returns 0 if TLB flush / invalidate required by caller.
   6.153   * va will indicate the address to be invalidated.
   6.154 @@ -92,6 +197,7 @@ static void
   6.155      unsigned long  frame = 0;
   6.156      int            rc = GNTST_okay;
   6.157      struct active_grant_entry *act;
   6.158 +    struct grant_mapping *mt;
   6.159      grant_entry_t *sha;
   6.160      union grant_combo scombo, prev_scombo, new_scombo;
   6.161  
   6.162 @@ -108,11 +214,9 @@ static void
   6.163      led = current;
   6.164      ld = led->domain;
   6.165  
   6.166 -    if ( unlikely(op->ref >= NR_GRANT_ENTRIES) ||
   6.167 -         unlikely((op->flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0) )
   6.168 +    if ( unlikely((op->flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0) )
   6.169      {
   6.170 -        gdprintk(XENLOG_INFO, "Bad ref (%d) or flags (%x).\n",
   6.171 -                op->ref, op->flags);
   6.172 +        gdprintk(XENLOG_INFO, "Bad flags in grant map op (%x).\n", op->flags);
   6.173          op->status = GNTST_bad_gntref;
   6.174          return;
   6.175      }
   6.176 @@ -132,51 +236,22 @@ static void
   6.177          return;
   6.178      }
   6.179  
   6.180 -    /* Get a maptrack handle. */
   6.181      if ( unlikely((handle = get_maptrack_handle(ld->grant_table)) == -1) )
   6.182      {
   6.183 -        int                   i;
   6.184 -        struct grant_mapping *new_mt;
   6.185 -        struct grant_table   *lgt = ld->grant_table;
   6.186 -
   6.187 -        if ( (lgt->maptrack_limit << 1) > MAPTRACK_MAX_ENTRIES )
   6.188 -        {
   6.189 -            put_domain(rd);
   6.190 -            gdprintk(XENLOG_INFO, "Maptrack table is at maximum size.\n");
   6.191 -            op->status = GNTST_no_device_space;
   6.192 -            return;
   6.193 -        }
   6.194 -
   6.195 -        /* Grow the maptrack table. */
   6.196 -        new_mt = alloc_xenheap_pages(lgt->maptrack_order + 1);
   6.197 -        if ( new_mt == NULL )
   6.198 -        {
   6.199 -            put_domain(rd);
   6.200 -            gdprintk(XENLOG_INFO, "No more map handles available.\n");
   6.201 -            op->status = GNTST_no_device_space;
   6.202 -            return;
   6.203 -        }
   6.204 -
   6.205 -        memcpy(new_mt, lgt->maptrack, PAGE_SIZE << lgt->maptrack_order);
   6.206 -        for ( i = lgt->maptrack_limit; i < (lgt->maptrack_limit << 1); i++ )
   6.207 -        {
   6.208 -            new_mt[i].ref = i+1;
   6.209 -            new_mt[i].flags = 0;
   6.210 -        }
   6.211 -
   6.212 -        free_xenheap_pages(lgt->maptrack, lgt->maptrack_order);
   6.213 -        lgt->maptrack          = new_mt;
   6.214 -        lgt->maptrack_order   += 1;
   6.215 -        lgt->maptrack_limit  <<= 1;
   6.216 -
   6.217 -        gdprintk(XENLOG_INFO, "Doubled maptrack size\n");
   6.218 -        handle = get_maptrack_handle(ld->grant_table);
   6.219 +        put_domain(rd);
   6.220 +        gdprintk(XENLOG_INFO, "Failed to obtain maptrack handle.\n");
   6.221 +        op->status = GNTST_no_device_space;
   6.222 +        return;
   6.223      }
   6.224  
   6.225 -    act = &rd->grant_table->active[op->ref];
   6.226 -    sha = &rd->grant_table->shared[op->ref];
   6.227 +    spin_lock(&rd->grant_table->lock);
   6.228  
   6.229 -    spin_lock(&rd->grant_table->lock);
   6.230 +    /* Bounds check on the grant ref */
   6.231 +    if ( unlikely(op->ref >= nr_grant_entries(rd->grant_table)))
   6.232 +        PIN_FAIL(unlock_out, GNTST_bad_gntref, "Bad ref (%d).\n", op->ref);
   6.233 +
   6.234 +    act = &active_entry(rd->grant_table, op->ref);
   6.235 +    sha = &shared_entry(rd->grant_table, op->ref);
   6.236  
   6.237      /* If already pinned, check the active domid and avoid refcnt overflow. */
   6.238      if ( act->pin &&
   6.239 @@ -247,9 +322,10 @@ static void
   6.240          act->pin += (op->flags & GNTMAP_readonly) ?
   6.241              GNTPIN_hstr_inc : GNTPIN_hstw_inc;
   6.242  
   6.243 +    frame = act->frame;
   6.244 +
   6.245      spin_unlock(&rd->grant_table->lock);
   6.246  
   6.247 -    frame = act->frame;
   6.248      if ( unlikely(!mfn_valid(frame)) ||
   6.249           unlikely(!((op->flags & GNTMAP_readonly) ?
   6.250                      get_page(mfn_to_page(frame), rd) :
   6.251 @@ -283,9 +359,10 @@ static void
   6.252  
   6.253      TRACE_1D(TRC_MEM_PAGE_GRANT_MAP, op->dom);
   6.254  
   6.255 -    ld->grant_table->maptrack[handle].domid = op->dom;
   6.256 -    ld->grant_table->maptrack[handle].ref   = op->ref;
   6.257 -    ld->grant_table->maptrack[handle].flags = op->flags;
   6.258 +    mt = &maptrack_entry(ld->grant_table, handle);
   6.259 +    mt->domid = op->dom;
   6.260 +    mt->ref   = op->ref;
   6.261 +    mt->flags = op->flags;
   6.262  
   6.263      op->dev_bus_addr = (u64)frame << PAGE_SHIFT;
   6.264      op->handle       = handle;
   6.265 @@ -297,6 +374,9 @@ static void
   6.266   undo_out:
   6.267      spin_lock(&rd->grant_table->lock);
   6.268  
   6.269 +    act = &active_entry(rd->grant_table, op->ref);
   6.270 +    sha = &shared_entry(rd->grant_table, op->ref);
   6.271 +
   6.272      if ( op->flags & GNTMAP_device_map )
   6.273          act->pin -= (op->flags & GNTMAP_readonly) ?
   6.274              GNTPIN_devr_inc : GNTPIN_devw_inc;
   6.275 @@ -355,16 +435,22 @@ static void
   6.276  
   6.277      frame = (unsigned long)(op->dev_bus_addr >> PAGE_SHIFT);
   6.278  
   6.279 -    map = &ld->grant_table->maptrack[op->handle];
   6.280 -
   6.281 -    if ( unlikely(op->handle >= ld->grant_table->maptrack_limit) ||
   6.282 -         unlikely(!map->flags) )
   6.283 +    if ( unlikely(op->handle >= ld->grant_table->maptrack_limit) )
   6.284      {
   6.285          gdprintk(XENLOG_INFO, "Bad handle (%d).\n", op->handle);
   6.286          op->status = GNTST_bad_handle;
   6.287          return;
   6.288      }
   6.289  
   6.290 +    map = &maptrack_entry(ld->grant_table, op->handle);
   6.291 +
   6.292 +    if ( unlikely(!map->flags) )
   6.293 +    {
   6.294 +        gdprintk(XENLOG_INFO, "Zero flags for handle (%d).\n", op->handle);
   6.295 +        op->status = GNTST_bad_handle;
   6.296 +        return;
   6.297 +    }
   6.298 +
   6.299      dom   = map->domid;
   6.300      ref   = map->ref;
   6.301      flags = map->flags;
   6.302 @@ -379,10 +465,10 @@ static void
   6.303  
   6.304      TRACE_1D(TRC_MEM_PAGE_GRANT_UNMAP, dom);
   6.305  
   6.306 -    act = &rd->grant_table->active[ref];
   6.307 -    sha = &rd->grant_table->shared[ref];
   6.308 +    spin_lock(&rd->grant_table->lock);
   6.309  
   6.310 -    spin_lock(&rd->grant_table->lock);
   6.311 +    act = &active_entry(rd->grant_table, ref);
   6.312 +    sha = &shared_entry(rd->grant_table, ref);
   6.313  
   6.314      if ( frame == 0 )
   6.315      {
   6.316 @@ -477,6 +563,62 @@ fault:
   6.317      return -EFAULT;    
   6.318  }
   6.319  
   6.320 +int
   6.321 +gnttab_grow_table(struct domain *d, unsigned int req_nr_frames)
   6.322 +{
   6.323 +    /* d's grant table lock must be held by the caller */
   6.324 +
   6.325 +    struct grant_table *gt = d->grant_table;
   6.326 +    unsigned int i;
   6.327 +
   6.328 +    ASSERT(req_nr_frames <= max_nr_grant_frames);
   6.329 +
   6.330 +    gdprintk(XENLOG_INFO,
   6.331 +            "Expanding dom (%d) grant table from (%d) to (%d) frames.\n",
   6.332 +            d->domain_id, nr_grant_frames(gt), req_nr_frames);
   6.333 +
   6.334 +    /* Active */
   6.335 +    for ( i = nr_active_grant_frames(gt);
   6.336 +          i < num_act_frames_from_sha_frames(req_nr_frames); i++ )
   6.337 +    {
   6.338 +        if ( (gt->active[i] = alloc_xenheap_page()) == NULL )
   6.339 +            goto active_alloc_failed;
   6.340 +        memset(gt->active[i], 0, PAGE_SIZE);
   6.341 +    }
   6.342 +
   6.343 +    /* Shared */
   6.344 +    for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
   6.345 +    {
   6.346 +        if ( (gt->shared[i] = alloc_xenheap_page()) == NULL )
   6.347 +            goto shared_alloc_failed;
   6.348 +        memset(gt->shared[i], 0, PAGE_SIZE);
   6.349 +    }
   6.350 +
   6.351 +    /* Share the new shared frames with the recipient domain */
   6.352 +    for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
   6.353 +        gnttab_create_shared_page(d, gt, i);
   6.354 +
   6.355 +    gt->nr_grant_frames = req_nr_frames;
   6.356 +
   6.357 +    return 1;
   6.358 +
   6.359 +shared_alloc_failed:
   6.360 +    for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
   6.361 +    {
   6.362 +        free_xenheap_page(gt->shared[i]);
   6.363 +        gt->shared[i] = NULL;
   6.364 +    }
   6.365 +active_alloc_failed:
   6.366 +    for ( i = nr_active_grant_frames(gt);
   6.367 +          i < num_act_frames_from_sha_frames(req_nr_frames); i++ )
   6.368 +    {
   6.369 +        free_xenheap_page(gt->active[i]);
   6.370 +        gt->active[i] = NULL;
   6.371 +    }
   6.372 +    gdprintk(XENLOG_INFO, "Allocation failure when expanding grant table.\n");
   6.373 +    return 0;
   6.374 +}
   6.375 +
   6.376  static long 
   6.377  gnttab_setup_table(
   6.378      XEN_GUEST_HANDLE(gnttab_setup_table_t) uop, unsigned int count)
   6.379 @@ -496,11 +638,11 @@ gnttab_setup_table(
   6.380          return -EFAULT;
   6.381      }
   6.382  
   6.383 -    if ( unlikely(op.nr_frames > NR_GRANT_FRAMES) )
   6.384 +    if ( unlikely(op.nr_frames > max_nr_grant_frames) )
   6.385      {
   6.386          gdprintk(XENLOG_INFO, "Xen only supports up to %d grant-table frames"
   6.387                  " per domain.\n",
   6.388 -                NR_GRANT_FRAMES);
   6.389 +                max_nr_grant_frames);
   6.390          op.status = GNTST_general_error;
   6.391          goto out;
   6.392      }
   6.393 @@ -523,7 +665,20 @@ gnttab_setup_table(
   6.394          goto out;
   6.395      }
   6.396  
   6.397 -    ASSERT(d->grant_table != NULL);
   6.398 +    spin_lock(&d->grant_table->lock);
   6.399 +
   6.400 +    if ( (op.nr_frames > nr_grant_frames(d->grant_table)) &&
   6.401 +         !gnttab_grow_table(d, op.nr_frames) )
   6.402 +    {
   6.403 +        gdprintk(XENLOG_INFO,
   6.404 +                "Expand grant table to %d failed. Current: %d Max: %d.\n",
   6.405 +                op.nr_frames,
   6.406 +                nr_grant_frames(d->grant_table),
   6.407 +                max_nr_grant_frames);
   6.408 +        op.status = GNTST_general_error;
   6.409 +        goto setup_unlock_out;
   6.410 +    }
   6.411 + 
   6.412      op.status = GNTST_okay;
   6.413      for ( i = 0; i < op.nr_frames; i++ )
   6.414      {
   6.415 @@ -531,6 +686,9 @@ gnttab_setup_table(
   6.416          (void)copy_to_guest_offset(op.frame_list, i, &gmfn, 1);
   6.417      }
   6.418  
   6.419 + setup_unlock_out:
   6.420 +    spin_unlock(&d->grant_table->lock);
   6.421 +
   6.422      put_domain(d);
   6.423  
   6.424   out:
   6.425 @@ -540,6 +698,58 @@ gnttab_setup_table(
   6.426      return 0;
   6.427  }
   6.428  
   6.429 +static long 
   6.430 +gnttab_query_size(
   6.431 +    XEN_GUEST_HANDLE(gnttab_query_size_t) uop, unsigned int count)
   6.432 +{
   6.433 +    struct gnttab_query_size op;
   6.434 +    struct domain *d;
   6.435 +    domid_t        dom;
   6.436 +
   6.437 +    if ( count != 1 )
   6.438 +        return -EINVAL;
   6.439 +
   6.440 +    if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
   6.441 +    {
   6.442 +        gdprintk(XENLOG_INFO, "Fault while reading gnttab_query_size_t.\n");
   6.443 +        return -EFAULT;
   6.444 +    }
   6.445 +
   6.446 +    dom = op.dom;
   6.447 +    if ( dom == DOMID_SELF )
   6.448 +    {
   6.449 +        dom = current->domain->domain_id;
   6.450 +    }
   6.451 +    else if ( unlikely(!IS_PRIV(current->domain)) )
   6.452 +    {
   6.453 +        op.status = GNTST_permission_denied;
   6.454 +        goto query_out;
   6.455 +    }
   6.456 +
   6.457 +    if ( unlikely((d = get_domain_by_id(dom)) == NULL) )
   6.458 +    {
   6.459 +        gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom);
   6.460 +        op.status = GNTST_bad_domain;
   6.461 +        goto query_out;
   6.462 +    }
   6.463 +
   6.464 +    spin_lock(&d->grant_table->lock);
   6.465 +
   6.466 +    op.nr_frames     = nr_grant_frames(d->grant_table);
   6.467 +    op.max_nr_frames = max_nr_grant_frames;
   6.468 +    op.status        = GNTST_okay;
   6.469 +
   6.470 +    spin_unlock(&d->grant_table->lock);
   6.471 +
   6.472 +    put_domain(d);
   6.473 +
   6.474 + query_out:
   6.475 +    if ( unlikely(copy_to_guest(uop, &op, 1)) )
   6.476 +        return -EFAULT;
   6.477 +
   6.478 +    return 0;
   6.479 +}
   6.480 +
   6.481  /*
   6.482   * Check that the given grant reference (rd,ref) allows 'ld' to transfer
   6.483   * ownership of a page frame. If so, lock down the grant entry.
   6.484 @@ -553,17 +763,23 @@ gnttab_prepare_for_transfer(
   6.485      union grant_combo   scombo, prev_scombo, new_scombo;
   6.486      int                 retries = 0;
   6.487  
   6.488 -    if ( unlikely((rgt = rd->grant_table) == NULL) ||
   6.489 -         unlikely(ref >= NR_GRANT_ENTRIES) )
   6.490 +    if ( unlikely((rgt = rd->grant_table) == NULL) )
   6.491      {
   6.492 -        gdprintk(XENLOG_INFO, "Dom %d has no g.t., or ref is bad (%d).\n",
   6.493 -                rd->domain_id, ref);
   6.494 +        gdprintk(XENLOG_INFO, "Dom %d has no grant table.\n", rd->domain_id);
   6.495          return 0;
   6.496      }
   6.497  
   6.498      spin_lock(&rgt->lock);
   6.499  
   6.500 -    sha = &rgt->shared[ref];
   6.501 +    if ( unlikely(ref >= nr_grant_entries(rd->grant_table)) )
   6.502 +    {
   6.503 +        gdprintk(XENLOG_INFO,
   6.504 +                "Bad grant reference (%d) for transfer to domain(%d).\n",
   6.505 +                ref, rd->domain_id);
   6.506 +        goto fail;
   6.507 +    }
   6.508 +
   6.509 +    sha = &shared_entry(rgt, ref);
   6.510      
   6.511      scombo.word = *(u32 *)&sha->flags;
   6.512  
   6.513 @@ -699,12 +915,16 @@ gnttab_transfer(
   6.514          TRACE_1D(TRC_MEM_PAGE_GRANT_TRANSFER, e->domain_id);
   6.515  
   6.516          /* Tell the guest about its new page frame. */
   6.517 -        sha = &e->grant_table->shared[gop.ref];
   6.518 +        spin_lock(&e->grant_table->lock);
   6.519 +
   6.520 +        sha = &shared_entry(e->grant_table, gop.ref);
   6.521          guest_physmap_add_page(e, sha->frame, mfn);
   6.522          sha->frame = mfn;
   6.523          wmb();
   6.524          sha->flags |= GTF_transfer_completed;
   6.525  
   6.526 +        spin_unlock(&e->grant_table->lock);
   6.527 +
   6.528          put_domain(e);
   6.529  
   6.530          gop.status = GNTST_okay;
   6.531 @@ -712,8 +932,8 @@ gnttab_transfer(
   6.532      copyback:
   6.533          if ( unlikely(__copy_to_guest_offset(uop, i, &gop, 1)) )
   6.534          {
   6.535 -            gdprintk(XENLOG_INFO, "gnttab_transfer: error writing resp %d/%d\n",
   6.536 -                    i, count);
   6.537 +            gdprintk(XENLOG_INFO, "gnttab_transfer: error writing resp "
   6.538 +                     "%d/%d\n", i, count);
   6.539              return -EFAULT;
   6.540          }
   6.541      }
   6.542 @@ -727,17 +947,24 @@ static void
   6.543  __release_grant_for_copy(
   6.544      struct domain *rd, unsigned long gref, int readonly)
   6.545  {
   6.546 -    grant_entry_t *const sha = &rd->grant_table->shared[gref];
   6.547 -    struct active_grant_entry *const act = &rd->grant_table->active[gref];
   6.548 +    grant_entry_t *sha;
   6.549 +    struct active_grant_entry *act;
   6.550 +    unsigned long r_frame;
   6.551  
   6.552      spin_lock(&rd->grant_table->lock);
   6.553  
   6.554 +    act = &active_entry(rd->grant_table, gref);
   6.555 +    sha = &shared_entry(rd->grant_table, gref);
   6.556 +    r_frame = act->frame;
   6.557 +
   6.558      if ( readonly )
   6.559      {
   6.560          act->pin -= GNTPIN_hstr_inc;
   6.561      }
   6.562      else
   6.563      {
   6.564 +        gnttab_mark_dirty(rd, r_frame);
   6.565 +
   6.566          act->pin -= GNTPIN_hstw_inc;
   6.567          if ( !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) )
   6.568              gnttab_clear_flag(_GTF_writing, &sha->flags);
   6.569 @@ -764,14 +991,14 @@ static int
   6.570      int retries = 0;
   6.571      union grant_combo scombo, prev_scombo, new_scombo;
   6.572  
   6.573 -    if ( unlikely(gref >= NR_GRANT_ENTRIES) )
   6.574 -        PIN_FAIL(error_out, GNTST_bad_gntref,
   6.575 +    spin_lock(&rd->grant_table->lock);
   6.576 +
   6.577 +    if ( unlikely(gref >= nr_grant_entries(rd->grant_table)) )
   6.578 +        PIN_FAIL(unlock_out, GNTST_bad_gntref,
   6.579                   "Bad grant reference %ld\n", gref);
   6.580 -    
   6.581 -    act = &rd->grant_table->active[gref];
   6.582 -    sha = &rd->grant_table->shared[gref];
   6.583  
   6.584 -    spin_lock(&rd->grant_table->lock);
   6.585 +    act = &active_entry(rd->grant_table, gref);
   6.586 +    sha = &shared_entry(rd->grant_table, gref);
   6.587      
   6.588      /* If already pinned, check the active domid and avoid refcnt overflow. */
   6.589      if ( act->pin &&
   6.590 @@ -834,7 +1061,6 @@ static int
   6.591  
   6.592   unlock_out:
   6.593      spin_unlock(&rd->grant_table->lock);
   6.594 - error_out:
   6.595      return rc;
   6.596  }
   6.597  
   6.598 @@ -1037,6 +1263,12 @@ do_grant_table_op(
   6.599          rc = gnttab_copy(copy, count);
   6.600          break;
   6.601      }
   6.602 +    case GNTTABOP_query_size:
   6.603 +    {
   6.604 +        rc = gnttab_query_size(
   6.605 +            guest_handle_cast(uop, gnttab_query_size_t), count);
   6.606 +        break;
   6.607 +    }
   6.608      default:
   6.609          rc = -ENOSYS;
   6.610          break;
   6.611 @@ -1052,6 +1284,13 @@ do_grant_table_op(
   6.612  #include "compat/grant_table.c"
   6.613  #endif
   6.614  
   6.615 +static unsigned int max_nr_active_grant_frames(void)
   6.616 +{
   6.617 +    return (((max_nr_grant_frames * (PAGE_SIZE / sizeof(grant_entry_t))) + 
   6.618 +                    ((PAGE_SIZE / sizeof(struct active_grant_entry))-1)) 
   6.619 +                   / (PAGE_SIZE / sizeof(struct active_grant_entry)));
   6.620 +}
   6.621 +
   6.622  int 
   6.623  grant_table_create(
   6.624      struct domain *d)
   6.625 @@ -1059,50 +1298,75 @@ grant_table_create(
   6.626      struct grant_table *t;
   6.627      int                 i;
   6.628  
   6.629 -    BUG_ON(MAPTRACK_MAX_ENTRIES < NR_GRANT_ENTRIES);
   6.630 +    /* If this sizeof assertion fails, fix the function: shared_index */
   6.631 +    ASSERT(sizeof(grant_entry_t) == 8);
   6.632 +
   6.633      if ( (t = xmalloc(struct grant_table)) == NULL )
   6.634 -        goto no_mem;
   6.635 +        goto no_mem_0;
   6.636  
   6.637      /* Simple stuff. */
   6.638      memset(t, 0, sizeof(*t));
   6.639      spin_lock_init(&t->lock);
   6.640 +    t->nr_grant_frames = INITIAL_NR_GRANT_FRAMES;
   6.641  
   6.642      /* Active grant table. */
   6.643 -    t->active = xmalloc_array(struct active_grant_entry, NR_GRANT_ENTRIES);
   6.644 -    if ( t->active == NULL )
   6.645 -        goto no_mem;
   6.646 -    memset(t->active, 0, sizeof(struct active_grant_entry) * NR_GRANT_ENTRIES);
   6.647 +    if ( (t->active = xmalloc_array(struct active_grant_entry *,
   6.648 +                                    max_nr_active_grant_frames())) == NULL )
   6.649 +        goto no_mem_1;
   6.650 +    memset(t->active, 0, max_nr_active_grant_frames() * sizeof(t->active[0]));
   6.651 +    for ( i = 0;
   6.652 +          i < num_act_frames_from_sha_frames(INITIAL_NR_GRANT_FRAMES); i++ )
   6.653 +    {
   6.654 +        if ( (t->active[i] = alloc_xenheap_page()) == NULL )
   6.655 +            goto no_mem_2;
   6.656 +        memset(t->active[i], 0, PAGE_SIZE);
   6.657 +    }
   6.658  
   6.659      /* Tracking of mapped foreign frames table */
   6.660 -    if ( (t->maptrack = alloc_xenheap_page()) == NULL )
   6.661 -        goto no_mem;
   6.662 -    t->maptrack_order = 0;
   6.663 +    if ( (t->maptrack = xmalloc_array(struct grant_mapping *,
   6.664 +                                      max_nr_maptrack_frames())) == NULL )
   6.665 +        goto no_mem_2;
   6.666 +    memset(t->maptrack, 0, max_nr_maptrack_frames() * sizeof(t->maptrack[0]));
   6.667 +    if ( (t->maptrack[0] = alloc_xenheap_page()) == NULL )
   6.668 +        goto no_mem_3;
   6.669      t->maptrack_limit = PAGE_SIZE / sizeof(struct grant_mapping);
   6.670 -    memset(t->maptrack, 0, PAGE_SIZE);
   6.671      for ( i = 0; i < t->maptrack_limit; i++ )
   6.672 -        t->maptrack[i].ref = i+1;
   6.673 +        t->maptrack[0][i].ref = i+1;
   6.674  
   6.675      /* Shared grant table. */
   6.676 -    t->shared = alloc_xenheap_pages(ORDER_GRANT_FRAMES);
   6.677 -    if ( t->shared == NULL )
   6.678 -        goto no_mem;
   6.679 -    memset(t->shared, 0, NR_GRANT_FRAMES * PAGE_SIZE);
   6.680 +    if ( (t->shared = xmalloc_array(struct grant_entry *,
   6.681 +                                    max_nr_grant_frames)) == NULL )
   6.682 +        goto no_mem_3;
   6.683 +    memset(t->shared, 0, max_nr_grant_frames * sizeof(t->shared[0]));
   6.684 +    for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
   6.685 +    {
   6.686 +        if ( (t->shared[i] = alloc_xenheap_page()) == NULL )
   6.687 +            goto no_mem_4;
   6.688 +        memset(t->shared[i], 0, PAGE_SIZE);
   6.689 +    }
   6.690  
   6.691 -    for ( i = 0; i < NR_GRANT_FRAMES; i++ )
   6.692 +    for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
   6.693          gnttab_create_shared_page(d, t, i);
   6.694  
   6.695      /* Okay, install the structure. */
   6.696 -    wmb(); /* avoid races with lock-free access to d->grant_table */
   6.697      d->grant_table = t;
   6.698      return 0;
   6.699  
   6.700 - no_mem:
   6.701 -    if ( t != NULL )
   6.702 -    {
   6.703 -        xfree(t->active);
   6.704 -        free_xenheap_page(t->maptrack);
   6.705 -        xfree(t);
   6.706 -    }
   6.707 + no_mem_4:
   6.708 +    for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
   6.709 +        free_xenheap_page(t->shared[i]);
   6.710 +    xfree(t->shared);
   6.711 + no_mem_3:
   6.712 +    free_xenheap_page(t->maptrack[0]);
   6.713 +    xfree(t->maptrack);
   6.714 + no_mem_2:
   6.715 +    for ( i = 0;
   6.716 +          i < num_act_frames_from_sha_frames(INITIAL_NR_GRANT_FRAMES); i++ )
   6.717 +        free_xenheap_page(t->active[i]);
   6.718 +    xfree(t->active);
   6.719 + no_mem_1:
   6.720 +    xfree(t);
   6.721 + no_mem_0:
   6.722      return -ENOMEM;
   6.723  }
   6.724  
   6.725 @@ -1122,7 +1386,7 @@ gnttab_release_mappings(
   6.726  
   6.727      for ( handle = 0; handle < gt->maptrack_limit; handle++ )
   6.728      {
   6.729 -        map = &gt->maptrack[handle];
   6.730 +        map = &maptrack_entry(gt, handle);
   6.731          if ( !(map->flags & (GNTMAP_device_map|GNTMAP_host_map)) )
   6.732              continue;
   6.733  
   6.734 @@ -1142,8 +1406,8 @@ gnttab_release_mappings(
   6.735  
   6.736          spin_lock(&rd->grant_table->lock);
   6.737  
   6.738 -        act = &rd->grant_table->active[ref];
   6.739 -        sha = &rd->grant_table->shared[ref];
   6.740 +        act = &active_entry(rd->grant_table, ref);
   6.741 +        sha = &shared_entry(rd->grant_table, ref);
   6.742  
   6.743          if ( map->flags & GNTMAP_readonly )
   6.744          {
   6.745 @@ -1200,15 +1464,24 @@ grant_table_destroy(
   6.746      struct domain *d)
   6.747  {
   6.748      struct grant_table *t = d->grant_table;
   6.749 +    int i;
   6.750  
   6.751      if ( t == NULL )
   6.752          return;
   6.753      
   6.754 -    free_xenheap_pages(t->shared, ORDER_GRANT_FRAMES);
   6.755 -    free_xenheap_pages(t->maptrack, t->maptrack_order);
   6.756 +    for ( i = 0; i < nr_grant_frames(t); i++ )
   6.757 +        free_xenheap_page(t->shared[i]);
   6.758 +    xfree(t->shared);
   6.759 +
   6.760 +    for ( i = 0; i < nr_maptrack_frames(t); i++ )
   6.761 +        free_xenheap_page(t->maptrack[i]);
   6.762 +    xfree(t->maptrack);
   6.763 +
   6.764 +    for ( i = 0; i < nr_active_grant_frames(t); i++ )
   6.765 +        free_xenheap_page(t->active[i]);
   6.766      xfree(t->active);
   6.767 +
   6.768      xfree(t);
   6.769 -
   6.770      d->grant_table = NULL;
   6.771  }
   6.772  
     7.1 --- a/xen/include/asm-ia64/grant_table.h	Thu Feb 15 10:34:21 2007 +0000
     7.2 +++ b/xen/include/asm-ia64/grant_table.h	Thu Feb 15 10:54:12 2007 +0000
     7.3 @@ -5,7 +5,7 @@
     7.4  #ifndef __ASM_GRANT_TABLE_H__
     7.5  #define __ASM_GRANT_TABLE_H__
     7.6  
     7.7 -#define ORDER_GRANT_FRAMES 0
     7.8 +#define INITIAL_NR_GRANT_FRAMES 1
     7.9  
    7.10  // for grant map/unmap
    7.11  int create_grant_host_mapping(unsigned long gpaddr, unsigned long mfn, unsigned int flags);
     8.1 --- a/xen/include/asm-powerpc/grant_table.h	Thu Feb 15 10:34:21 2007 +0000
     8.2 +++ b/xen/include/asm-powerpc/grant_table.h	Thu Feb 15 10:54:12 2007 +0000
     8.3 @@ -23,7 +23,7 @@
     8.4  
     8.5  #include <asm/mm.h>
     8.6  
     8.7 -#define ORDER_GRANT_FRAMES 2
     8.8 +#define INITIAL_NR_GRANT_FRAMES 4
     8.9  
    8.10  /*
    8.11   * Caller must own caller's BIGLOCK, is responsible for flushing the TLB, and
     9.1 --- a/xen/include/asm-x86/grant_table.h	Thu Feb 15 10:34:21 2007 +0000
     9.2 +++ b/xen/include/asm-x86/grant_table.h	Thu Feb 15 10:54:12 2007 +0000
     9.3 @@ -7,7 +7,7 @@
     9.4  #ifndef __ASM_GRANT_TABLE_H__
     9.5  #define __ASM_GRANT_TABLE_H__
     9.6  
     9.7 -#define ORDER_GRANT_FRAMES 2
     9.8 +#define INITIAL_NR_GRANT_FRAMES 4
     9.9  
    9.10  /*
    9.11   * Caller must own caller's BIGLOCK, is responsible for flushing the TLB, and
    9.12 @@ -21,12 +21,12 @@ int destroy_grant_host_mapping(
    9.13  #define gnttab_create_shared_page(d, t, i)                               \
    9.14      do {                                                                 \
    9.15          share_xen_page_with_guest(                                       \
    9.16 -            virt_to_page((char *)(t)->shared + ((i) * PAGE_SIZE)),       \
    9.17 +            virt_to_page((char *)(t)->shared[i]),                        \
    9.18              (d), XENSHARE_writable);                                     \
    9.19      } while ( 0 )
    9.20  
    9.21  #define gnttab_shared_mfn(d, t, i)                      \
    9.22 -    ((virt_to_maddr((t)->shared) >> PAGE_SHIFT) + (i))
    9.23 +    ((virt_to_maddr((t)->shared[i]) >> PAGE_SHIFT))
    9.24  
    9.25  #define gnttab_shared_gmfn(d, t, i)                     \
    9.26      (mfn_to_gmfn(d, gnttab_shared_mfn(d, t, i)))
    10.1 --- a/xen/include/public/grant_table.h	Thu Feb 15 10:34:21 2007 +0000
    10.2 +++ b/xen/include/public/grant_table.h	Thu Feb 15 10:54:12 2007 +0000
    10.3 @@ -309,6 +309,25 @@ typedef struct gnttab_copy {
    10.4  } gnttab_copy_t;
    10.5  DEFINE_XEN_GUEST_HANDLE(gnttab_copy_t);
    10.6  
    10.7 +/*
    10.8 + * GNTTABOP_query_size: Query the current and maximum sizes of the shared
    10.9 + * grant table.
   10.10 + * NOTES:
   10.11 + *  1. <dom> may be specified as DOMID_SELF.
   10.12 + *  2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
   10.13 + */
   10.14 +#define GNTTABOP_query_size           6
   10.15 +struct gnttab_query_size {
   10.16 +    /* IN parameters. */
   10.17 +    domid_t  dom;
   10.18 +    /* OUT parameters. */
   10.19 +    uint32_t nr_frames;
   10.20 +    uint32_t max_nr_frames;
   10.21 +    int16_t  status;              /* GNTST_* */
   10.22 +};
   10.23 +typedef struct gnttab_query_size gnttab_query_size_t;
   10.24 +DEFINE_XEN_GUEST_HANDLE(gnttab_query_size_t);
   10.25 +
   10.26  
   10.27  /*
   10.28   * Bitfield values for update_pin_status.flags.
    11.1 --- a/xen/include/xen/grant_table.h	Thu Feb 15 10:34:21 2007 +0000
    11.2 +++ b/xen/include/xen/grant_table.h	Thu Feb 15 10:54:12 2007 +0000
    11.3 @@ -52,9 +52,14 @@ struct active_grant_entry {
    11.4  #define GNTPIN_devr_inc      (1 << GNTPIN_devr_shift)
    11.5  #define GNTPIN_devr_mask     (0xFFU << GNTPIN_devr_shift)
    11.6  
    11.7 -#define NR_GRANT_FRAMES      (1U << ORDER_GRANT_FRAMES)
    11.8 -#define NR_GRANT_ENTRIES     \
    11.9 -    ((NR_GRANT_FRAMES << PAGE_SHIFT) / sizeof(grant_entry_t))
   11.10 +/* Initial size of a grant table. */
   11.11 +#define INITIAL_NR_GRANT_ENTRIES ((INITIAL_NR_GRANT_FRAMES << PAGE_SHIFT) / \
   11.12 +                                     sizeof(grant_entry_t))
   11.13 +
   11.14 +/* Default maximum size of a grant table. [POLICY] */
   11.15 +#define DEFAULT_MAX_NR_GRANT_FRAMES   32
   11.16 +/* The maximum size of a grant table. */
   11.17 +extern unsigned int max_nr_grant_frames;
   11.18  
   11.19  /*
   11.20   * Tracks a mapping of another domain's grant reference. Each domain has a
   11.21 @@ -71,14 +76,15 @@ struct grant_mapping {
   11.22  
   11.23  /* Per-domain grant information. */
   11.24  struct grant_table {
   11.25 +    /* Table size. Number of frames shared with guest */
   11.26 +    unsigned int          nr_grant_frames;
   11.27      /* Shared grant table (see include/public/grant_table.h). */
   11.28 -    struct grant_entry   *shared;
   11.29 +    struct grant_entry  **shared;
   11.30      /* Active grant table. */
   11.31 -    struct active_grant_entry *active;
   11.32 +    struct active_grant_entry **active;
   11.33      /* Mapping tracking table. */
   11.34 -    struct grant_mapping *maptrack;
   11.35 +    struct grant_mapping **maptrack;
   11.36      unsigned int          maptrack_head;
   11.37 -    unsigned int          maptrack_order;
   11.38      unsigned int          maptrack_limit;
   11.39      unsigned int          map_count;
   11.40      /* Lock protecting updates to active and shared grant tables. */
   11.41 @@ -96,4 +102,22 @@ void
   11.42  gnttab_release_mappings(
   11.43      struct domain *d);
   11.44  
   11.45 +/* Increase the size of a domain's grant table.
   11.46 + * Caller must hold d's grant table lock.
   11.47 + */
   11.48 +int
   11.49 +gnttab_grow_table(struct domain *d, unsigned int req_nr_frames);
   11.50 +
   11.51 +/* Number of grant table frames. Caller must hold d's grant table lock. */
   11.52 +static inline unsigned int nr_grant_frames(struct grant_table *gt)
   11.53 +{
   11.54 +    return gt->nr_grant_frames;
   11.55 +}
   11.56 +
   11.57 +/* Number of grant table entries. Caller must hold d's grant table lock. */
   11.58 +static inline unsigned int nr_grant_entries(struct grant_table *gt)
   11.59 +{
   11.60 +    return (nr_grant_frames(gt) << PAGE_SHIFT) / sizeof(grant_entry_t);
   11.61 +}
   11.62 +
   11.63  #endif /* __XEN_GRANT_TABLE_H__ */