ia64/linux-2.6.18-xen.hg

changeset 485:2783eccd4805

xen: Variable-size gntdev support

This patch adds the ability to set the number of slots that may be
used for mapping grant references, using the gntdev user-space grant
reference mapping driver.

Signed-off-by: Derek Murray <Derek.Murray@cl.cam.ac.uk>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 18 15:01:09 2008 +0000 (2008-03-18)
parents 24d797fe8251
children a461c109f74f
files drivers/xen/gntdev/gntdev.c include/xen/public/gntdev.h
line diff
     1.1 --- a/drivers/xen/gntdev/gntdev.c	Tue Mar 18 11:43:42 2008 +0000
     1.2 +++ b/drivers/xen/gntdev/gntdev.c	Tue Mar 18 15:01:09 2008 +0000
     1.3 @@ -43,7 +43,8 @@ MODULE_LICENSE("GPL");
     1.4  MODULE_AUTHOR(DRIVER_AUTHOR);
     1.5  MODULE_DESCRIPTION(DRIVER_DESC);
     1.6  
     1.7 -#define MAX_GRANTS 128
     1.8 +#define MAX_GRANTS_LIMIT   1024
     1.9 +#define DEFAULT_MAX_GRANTS 128
    1.10  
    1.11  /* A slot can be in one of three states:
    1.12   *
    1.13 @@ -90,7 +91,8 @@ typedef struct gntdev_grant_info {
    1.14  typedef struct gntdev_file_private_data {
    1.15    
    1.16  	/* Array of grant information. */
    1.17 -	gntdev_grant_info_t grants[MAX_GRANTS];
    1.18 +	gntdev_grant_info_t *grants;
    1.19 +	uint32_t grants_size;
    1.20  
    1.21  	/* Read/write semaphore used to protect the grants array. */
    1.22  	struct rw_semaphore grants_sem;
    1.23 @@ -102,7 +104,7 @@ typedef struct gntdev_file_private_data 
    1.24  	 * been compressed. However, this is not visible across invocations of
    1.25  	 * the device.
    1.26  	 */
    1.27 -	int32_t free_list[MAX_GRANTS];
    1.28 +	int32_t *free_list;
    1.29  	
    1.30  	/* The number of free slots in the grants array. */
    1.31  	uint32_t free_list_size;
    1.32 @@ -314,7 +316,7 @@ static int find_contiguous_free_range(st
    1.33  
    1.34  	/* First search from the start_index to the end of the array. */
    1.35  	range_length = 0;
    1.36 -	for (i = start_index; i < MAX_GRANTS; ++i) {
    1.37 +	for (i = start_index; i < private_data->grants_size; ++i) {
    1.38  		if (private_data->grants[i].state == GNTDEV_SLOT_INVALID) {
    1.39  			if (range_length == 0) {
    1.40  				range_start = i;
    1.41 @@ -343,6 +345,50 @@ static int find_contiguous_free_range(st
    1.42  	return -ENOMEM;
    1.43  }
    1.44  
    1.45 +static int init_private_data(gntdev_file_private_data_t *priv,
    1.46 +			     uint32_t max_grants)
    1.47 +{
    1.48 +	int i;
    1.49 +
    1.50 +	/* Allocate space for the kernel-mapping of granted pages. */
    1.51 +	priv->foreign_pages = 
    1.52 +		alloc_empty_pages_and_pagevec(max_grants);
    1.53 +	if (!priv->foreign_pages)
    1.54 +		goto nomem_out;
    1.55 +
    1.56 +	/* Allocate the grant list and free-list. */
    1.57 +	priv->grants = kmalloc(max_grants * sizeof(gntdev_grant_info_t),
    1.58 +			       GFP_KERNEL);
    1.59 +	if (!priv->grants)
    1.60 +		goto nomem_out2;
    1.61 +	priv->free_list = kmalloc(max_grants * sizeof(int32_t), GFP_KERNEL);
    1.62 +	if (!priv->free_list)
    1.63 +		goto nomem_out3;
    1.64 +
    1.65 +	/* Initialise the free-list, which contains all slots at first. */
    1.66 +	for (i = 0; i < max_grants; ++i) {
    1.67 +		priv->free_list[max_grants - i - 1] = i;
    1.68 +		priv->grants[i].state = GNTDEV_SLOT_INVALID;
    1.69 +		priv->grants[i].u.free_list_index = max_grants - i - 1;
    1.70 +	}
    1.71 +	priv->grants_size = max_grants;
    1.72 +	priv->free_list_size = max_grants;
    1.73 +	priv->next_fit_index = 0;
    1.74 +
    1.75 +	up_write(&priv->grants_sem);
    1.76 +	up_write(&priv->free_list_sem);
    1.77 +
    1.78 +	return 0;
    1.79 +
    1.80 +nomem_out3:
    1.81 +	kfree(priv->grants);
    1.82 +nomem_out2:
    1.83 +	free_empty_pages_and_pagevec(priv->foreign_pages, max_grants);
    1.84 +nomem_out:
    1.85 +	return -ENOMEM;
    1.86 +
    1.87 +}
    1.88 +
    1.89  /* Interface functions. */
    1.90  
    1.91  /* Initialises the driver. Called when the module is loaded. */
    1.92 @@ -400,7 +446,6 @@ static void __exit gntdev_exit(void)
    1.93  static int gntdev_open(struct inode *inode, struct file *flip)
    1.94  {
    1.95  	gntdev_file_private_data_t *private_data;
    1.96 -	int i;
    1.97  
    1.98  	try_module_get(THIS_MODULE);
    1.99  
   1.100 @@ -409,21 +454,10 @@ static int gntdev_open(struct inode *ino
   1.101  	if (!private_data)
   1.102  		goto nomem_out;
   1.103  
   1.104 -	/* Allocate space for the kernel-mapping of granted pages. */
   1.105 -	private_data->foreign_pages = 
   1.106 -		alloc_empty_pages_and_pagevec(MAX_GRANTS);
   1.107 -	if (!private_data->foreign_pages)
   1.108 -		goto nomem_out2;
   1.109 -
   1.110 -	/* Initialise the free-list, which contains all slots at first.
   1.111 -	 */
   1.112 -	for (i = 0; i < MAX_GRANTS; ++i) {
   1.113 -		private_data->free_list[MAX_GRANTS - i - 1] = i;
   1.114 -		private_data->grants[i].state = GNTDEV_SLOT_INVALID;
   1.115 -		private_data->grants[i].u.free_list_index = MAX_GRANTS - i - 1;
   1.116 -	}
   1.117 -	private_data->free_list_size = MAX_GRANTS;
   1.118 -	private_data->next_fit_index = 0;
   1.119 +	/* These will be lazily initialised by init_private_data. */
   1.120 +	private_data->grants = NULL;
   1.121 +	private_data->free_list = NULL;
   1.122 +	private_data->foreign_pages = NULL;
   1.123  
   1.124  	init_rwsem(&private_data->grants_sem);
   1.125  	init_rwsem(&private_data->free_list_sem);
   1.126 @@ -432,8 +466,6 @@ static int gntdev_open(struct inode *ino
   1.127  
   1.128  	return 0;
   1.129  
   1.130 -nomem_out2:
   1.131 -	kfree(private_data);
   1.132  nomem_out:
   1.133  	return -ENOMEM;
   1.134  }
   1.135 @@ -445,10 +477,14 @@ static int gntdev_release(struct inode *
   1.136  	if (flip->private_data) {
   1.137  		gntdev_file_private_data_t *private_data = 
   1.138  			(gntdev_file_private_data_t *) flip->private_data;
   1.139 -		if (private_data->foreign_pages) {
   1.140 +		if (private_data->foreign_pages)
   1.141  			free_empty_pages_and_pagevec
   1.142 -				(private_data->foreign_pages, MAX_GRANTS);
   1.143 -		}
   1.144 +				(private_data->foreign_pages,
   1.145 +				 private_data->grants_size);
   1.146 +		if (private_data->grants) 
   1.147 +			kfree(private_data->grants);
   1.148 +		if (private_data->free_list)
   1.149 +			kfree(private_data->free_list);
   1.150  		kfree(private_data);
   1.151  	}
   1.152  	module_put(THIS_MODULE);
   1.153 @@ -479,7 +515,17 @@ static int gntdev_mmap (struct file *fli
   1.154  		return -EINVAL;
   1.155  	}
   1.156  
   1.157 -	if (unlikely((size <= 0) || (size + slot_index) > MAX_GRANTS)) {
   1.158 +	/* Test to make sure that the grants array has been initialised. */
   1.159 +	down_read(&private_data->grants_sem);
   1.160 +	if (unlikely(!private_data->grants)) {
   1.161 +		up_read(&private_data->grants_sem);
   1.162 +		printk(KERN_ERR "Attempted to mmap before ioctl.\n");
   1.163 +		return -EINVAL;
   1.164 +	}
   1.165 +	up_read(&private_data->grants_sem);
   1.166 +
   1.167 +	if (unlikely((size <= 0) || 
   1.168 +		     (size + slot_index) > private_data->grants_size)) {
   1.169  		printk(KERN_ERR "Invalid number of pages or offset"
   1.170  		       "(num_pages = %d, first_slot = %ld).\n",
   1.171  		       size, slot_index);
   1.172 @@ -789,6 +835,33 @@ static long gntdev_ioctl(struct file *fl
   1.173  	gntdev_file_private_data_t *private_data = 
   1.174  		(gntdev_file_private_data_t *) flip->private_data;
   1.175  
   1.176 +	/* On the first invocation, we will lazily initialise the grant array
   1.177 +	 * and free-list.
   1.178 +	 */
   1.179 +	if (unlikely(!private_data->grants) 
   1.180 +	    && likely(cmd != IOCTL_GNTDEV_SET_MAX_GRANTS)) {
   1.181 +		down_write(&private_data->grants_sem);
   1.182 +		
   1.183 +		if (unlikely(private_data->grants)) {
   1.184 +			up_write(&private_data->grants_sem);
   1.185 +			goto private_data_initialised;
   1.186 +		}
   1.187 +		
   1.188 +		/* Just use the default. Setting to a non-default is handled
   1.189 +		 * in the ioctl switch.
   1.190 +		 */
   1.191 +		rc = init_private_data(private_data, DEFAULT_MAX_GRANTS);
   1.192 +		
   1.193 +		up_write(&private_data->grants_sem);
   1.194 +
   1.195 +		if (rc) {
   1.196 +			printk (KERN_ERR "Initialising gntdev private data "
   1.197 +				"failed.\n");
   1.198 +			return rc;
   1.199 +		}
   1.200 +	}
   1.201 +	    
   1.202 +private_data_initialised:
   1.203  	switch (cmd) {
   1.204  	case IOCTL_GNTDEV_MAP_GRANT_REF:
   1.205  	{
   1.206 @@ -972,6 +1045,30 @@ static long gntdev_ioctl(struct file *fl
   1.207  	get_offset_out:
   1.208  		return rc;
   1.209  	}
   1.210 +	case IOCTL_GNTDEV_SET_MAX_GRANTS:
   1.211 +	{
   1.212 +		struct ioctl_gntdev_set_max_grants op;
   1.213 +		if ((rc = copy_from_user(&op, 
   1.214 +					 (void __user *) arg, 
   1.215 +					 sizeof(op)))) {
   1.216 +			rc = -EFAULT;
   1.217 +			goto set_max_out;
   1.218 +		}
   1.219 +		down_write(&private_data->grants_sem);
   1.220 +		if (private_data->grants) {
   1.221 +			rc = -EBUSY;
   1.222 +			goto set_max_unlock_out;
   1.223 +		}
   1.224 +		if (op.count > MAX_GRANTS_LIMIT) {
   1.225 +			rc = -EINVAL;
   1.226 +			goto set_max_unlock_out;
   1.227 +		}						 
   1.228 +		rc = init_private_data(private_data, op.count);
   1.229 +	set_max_unlock_out:
   1.230 +		up_write(&private_data->grants_sem);
   1.231 +	set_max_out:
   1.232 +		return rc;
   1.233 +	}
   1.234  	default:
   1.235  		return -ENOIOCTLCMD;
   1.236  	}
     2.1 --- a/include/xen/public/gntdev.h	Tue Mar 18 11:43:42 2008 +0000
     2.2 +++ b/include/xen/public/gntdev.h	Tue Mar 18 15:01:09 2008 +0000
     2.3 @@ -102,4 +102,18 @@ struct ioctl_gntdev_get_offset_for_vaddr
     2.4  	uint32_t pad;
     2.5  };
     2.6  
     2.7 +/*
     2.8 + * Sets the maximum number of grants that may mapped at once by this gntdev
     2.9 + * instance.
    2.10 + *
    2.11 + * N.B. This must be called before any other ioctl is performed on the device.
    2.12 + */
    2.13 +#define IOCTL_GNTDEV_SET_MAX_GRANTS \
    2.14 +_IOC(_IOC_NONE, 'G', 3, sizeof(struct ioctl_gntdev_set_max_grants))
    2.15 +struct ioctl_gntdev_set_max_grants {
    2.16 +	/* IN parameter */
    2.17 +	/* The maximum number of grants that may be mapped at once. */
    2.18 +	uint32_t count;
    2.19 +};
    2.20 +
    2.21  #endif /* __LINUX_PUBLIC_GNTDEV_H__ */