[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [linux-2.6.18-xen] xen: Variable-size gntdev support



# 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.