# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1205852469 0
# Node ID 2783eccd480552523bb16f3dee5967260862ed9b
# Parent 24d797fe82519db6016a7324a9558923ab1143b5
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@xxxxxxxxxxxx>
---
drivers/xen/gntdev/gntdev.c | 149 ++++++++++++++++++++++++++++++++++++--------
include/xen/public/gntdev.h | 14 ++++
2 files changed, 137 insertions(+), 26 deletions(-)
diff -r 24d797fe8251 -r 2783eccd4805 drivers/xen/gntdev/gntdev.c
--- a/drivers/xen/gntdev/gntdev.c Tue Mar 18 11:43:42 2008 +0000
+++ b/drivers/xen/gntdev/gntdev.c Tue Mar 18 15:01:09 2008 +0000
@@ -43,7 +43,8 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
-#define MAX_GRANTS 128
+#define MAX_GRANTS_LIMIT 1024
+#define DEFAULT_MAX_GRANTS 128
/* A slot can be in one of three states:
*
@@ -90,7 +91,8 @@ typedef struct gntdev_file_private_data
typedef struct gntdev_file_private_data {
/* Array of grant information. */
- gntdev_grant_info_t grants[MAX_GRANTS];
+ gntdev_grant_info_t *grants;
+ uint32_t grants_size;
/* Read/write semaphore used to protect the grants array. */
struct rw_semaphore grants_sem;
@@ -102,7 +104,7 @@ typedef struct gntdev_file_private_data
* been compressed. However, this is not visible across invocations of
* the device.
*/
- int32_t free_list[MAX_GRANTS];
+ int32_t *free_list;
/* The number of free slots in the grants array. */
uint32_t free_list_size;
@@ -314,7 +316,7 @@ static int find_contiguous_free_range(st
/* First search from the start_index to the end of the array. */
range_length = 0;
- for (i = start_index; i < MAX_GRANTS; ++i) {
+ for (i = start_index; i < private_data->grants_size; ++i) {
if (private_data->grants[i].state == GNTDEV_SLOT_INVALID) {
if (range_length == 0) {
range_start = i;
@@ -343,6 +345,50 @@ static int find_contiguous_free_range(st
return -ENOMEM;
}
+static int init_private_data(gntdev_file_private_data_t *priv,
+ uint32_t max_grants)
+{
+ int i;
+
+ /* Allocate space for the kernel-mapping of granted pages. */
+ priv->foreign_pages =
+ alloc_empty_pages_and_pagevec(max_grants);
+ if (!priv->foreign_pages)
+ goto nomem_out;
+
+ /* Allocate the grant list and free-list. */
+ priv->grants = kmalloc(max_grants * sizeof(gntdev_grant_info_t),
+ GFP_KERNEL);
+ if (!priv->grants)
+ goto nomem_out2;
+ priv->free_list = kmalloc(max_grants * sizeof(int32_t), GFP_KERNEL);
+ if (!priv->free_list)
+ goto nomem_out3;
+
+ /* Initialise the free-list, which contains all slots at first. */
+ for (i = 0; i < max_grants; ++i) {
+ priv->free_list[max_grants - i - 1] = i;
+ priv->grants[i].state = GNTDEV_SLOT_INVALID;
+ priv->grants[i].u.free_list_index = max_grants - i - 1;
+ }
+ priv->grants_size = max_grants;
+ priv->free_list_size = max_grants;
+ priv->next_fit_index = 0;
+
+ up_write(&priv->grants_sem);
+ up_write(&priv->free_list_sem);
+
+ return 0;
+
+nomem_out3:
+ kfree(priv->grants);
+nomem_out2:
+ free_empty_pages_and_pagevec(priv->foreign_pages, max_grants);
+nomem_out:
+ return -ENOMEM;
+
+}
+
/* Interface functions. */
/* Initialises the driver. Called when the module is loaded. */
@@ -400,7 +446,6 @@ static int gntdev_open(struct inode *ino
static int gntdev_open(struct inode *inode, struct file *flip)
{
gntdev_file_private_data_t *private_data;
- int i;
try_module_get(THIS_MODULE);
@@ -409,21 +454,10 @@ static int gntdev_open(struct inode *ino
if (!private_data)
goto nomem_out;
- /* Allocate space for the kernel-mapping of granted pages. */
- private_data->foreign_pages =
- alloc_empty_pages_and_pagevec(MAX_GRANTS);
- if (!private_data->foreign_pages)
- goto nomem_out2;
-
- /* Initialise the free-list, which contains all slots at first.
- */
- for (i = 0; i < MAX_GRANTS; ++i) {
- private_data->free_list[MAX_GRANTS - i - 1] = i;
- private_data->grants[i].state = GNTDEV_SLOT_INVALID;
- private_data->grants[i].u.free_list_index = MAX_GRANTS - i - 1;
- }
- private_data->free_list_size = MAX_GRANTS;
- private_data->next_fit_index = 0;
+ /* These will be lazily initialised by init_private_data. */
+ private_data->grants = NULL;
+ private_data->free_list = NULL;
+ private_data->foreign_pages = NULL;
init_rwsem(&private_data->grants_sem);
init_rwsem(&private_data->free_list_sem);
@@ -432,8 +466,6 @@ static int gntdev_open(struct inode *ino
return 0;
-nomem_out2:
- kfree(private_data);
nomem_out:
return -ENOMEM;
}
@@ -445,10 +477,14 @@ static int gntdev_release(struct inode *
if (flip->private_data) {
gntdev_file_private_data_t *private_data =
(gntdev_file_private_data_t *) flip->private_data;
- if (private_data->foreign_pages) {
+ if (private_data->foreign_pages)
free_empty_pages_and_pagevec
- (private_data->foreign_pages, MAX_GRANTS);
- }
+ (private_data->foreign_pages,
+ private_data->grants_size);
+ if (private_data->grants)
+ kfree(private_data->grants);
+ if (private_data->free_list)
+ kfree(private_data->free_list);
kfree(private_data);
}
module_put(THIS_MODULE);
@@ -479,7 +515,17 @@ static int gntdev_mmap (struct file *fli
return -EINVAL;
}
- if (unlikely((size <= 0) || (size + slot_index) > MAX_GRANTS)) {
+ /* Test to make sure that the grants array has been initialised. */
+ down_read(&private_data->grants_sem);
+ if (unlikely(!private_data->grants)) {
+ up_read(&private_data->grants_sem);
+ printk(KERN_ERR "Attempted to mmap before ioctl.\n");
+ return -EINVAL;
+ }
+ up_read(&private_data->grants_sem);
+
+ if (unlikely((size <= 0) ||
+ (size + slot_index) > private_data->grants_size)) {
printk(KERN_ERR "Invalid number of pages or offset"
"(num_pages = %d, first_slot = %ld).\n",
size, slot_index);
@@ -789,6 +835,33 @@ static long gntdev_ioctl(struct file *fl
gntdev_file_private_data_t *private_data =
(gntdev_file_private_data_t *) flip->private_data;
+ /* On the first invocation, we will lazily initialise the grant array
+ * and free-list.
+ */
+ if (unlikely(!private_data->grants)
+ && likely(cmd != IOCTL_GNTDEV_SET_MAX_GRANTS)) {
+ down_write(&private_data->grants_sem);
+
+ if (unlikely(private_data->grants)) {
+ up_write(&private_data->grants_sem);
+ goto private_data_initialised;
+ }
+
+ /* Just use the default. Setting to a non-default is handled
+ * in the ioctl switch.
+ */
+ rc = init_private_data(private_data, DEFAULT_MAX_GRANTS);
+
+ up_write(&private_data->grants_sem);
+
+ if (rc) {
+ printk (KERN_ERR "Initialising gntdev private data "
+ "failed.\n");
+ return rc;
+ }
+ }
+
+private_data_initialised:
switch (cmd) {
case IOCTL_GNTDEV_MAP_GRANT_REF:
{
@@ -972,6 +1045,30 @@ static long gntdev_ioctl(struct file *fl
get_offset_out:
return rc;
}
+ case IOCTL_GNTDEV_SET_MAX_GRANTS:
+ {
+ struct ioctl_gntdev_set_max_grants op;
+ if ((rc = copy_from_user(&op,
+ (void __user *) arg,
+ sizeof(op)))) {
+ rc = -EFAULT;
+ goto set_max_out;
+ }
+ down_write(&private_data->grants_sem);
+ if (private_data->grants) {
+ rc = -EBUSY;
+ goto set_max_unlock_out;
+ }
+ if (op.count > MAX_GRANTS_LIMIT) {
+ rc = -EINVAL;
+ goto set_max_unlock_out;
+ }
+ rc = init_private_data(private_data, op.count);
+ set_max_unlock_out:
+ up_write(&private_data->grants_sem);
+ set_max_out:
+ return rc;
+ }
default:
return -ENOIOCTLCMD;
}
diff -r 24d797fe8251 -r 2783eccd4805 include/xen/public/gntdev.h
--- a/include/xen/public/gntdev.h Tue Mar 18 11:43:42 2008 +0000
+++ b/include/xen/public/gntdev.h Tue Mar 18 15:01:09 2008 +0000
@@ -102,4 +102,18 @@ struct ioctl_gntdev_get_offset_for_vaddr
uint32_t pad;
};
+/*
+ * Sets the maximum number of grants that may mapped at once by this gntdev
+ * instance.
+ *
+ * N.B. This must be called before any other ioctl is performed on the device.
+ */
+#define IOCTL_GNTDEV_SET_MAX_GRANTS \
+_IOC(_IOC_NONE, 'G', 3, sizeof(struct ioctl_gntdev_set_max_grants))
+struct ioctl_gntdev_set_max_grants {
+ /* IN parameter */
+ /* The maximum number of grants that may be mapped at once. */
+ uint32_t count;
+};
+
#endif /* __LINUX_PUBLIC_GNTDEV_H__ */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|