Hi Phil,
Attached patch fixes the read buffer bug that you had mentioned and
also implements the variable sized buffer counts and lengths that we
can pass as command line options to pvfs2-client-core.
I did not implement module time options for buffer size settings since
that is fairly complicated and not intuitive (client core driving the
buffer size and count settings
seems to make more sense to me).

So now we can do
pvfs2-client --desc-count=<NUM1> --desc-size=<NUM2>
in addition to the usual options.
With regards to the changes itself, this involved modifying the
parameters of an existing ioctl, and so we break binary compatibility,
but I don't think we have a policy of maintaining backward binary
compatibility, do we?
I have updated the compat ioctl code as well, so hopefully we won't
break in mixed 32-64 bit environments.
I have tested this out with various buffer sizes and counts on 32 bit
platforms only!
That said, I haven't done a comprehensive testing..so there may still be bugs..
Please review it and let me know if this looks ok.
BTW: patch is against pvfs-2.6.0..sorry abut that.
cvs ports are firewalled off at work and my internet at home is
temporarily not working.
thanks,
Murali


On 11/29/06, Murali Vilayannur <[EMAIL PROTECTED]> wrote:
Hi Phil,
Thanks for running these tests.
I think this buffer size will be dependant on the machine configuration right?
If we work out a simple formula for the buffer size based on say
memory b/w (and/or latency), network b/w (and/or latency), we could
plug that in as a sane default (bandwidth .
I did not realize that this setting will have such a noticable effect
on performance.
I can work on a patch to change these settings at runtime.
thanks,
Murali

> >> - single client
> >> - 16 servers
> >> - gigabit ethernet
> >> - read/write tests, with 40 GB files
> >> - using reads and writes of 100 MB each in size
> >> - varying number of processes running concurrently on the client
> >>
> >> This test application can be configured to be run with multiple
> >> processes and/or multiple client nodes.  In this case we kept
> >> everything on a single client to focus on bottlenecks on that side.
> >>
> >> What we were looking at was the kernel buffer settings controlled  in
> >> pint-dev-shared.h.  By default PVFS2 uses 5 buffers of 4 MB  each.
> >> After experimenting for a while, we made a few observations:
> >>
> >> - increasing the buffer size helped performance
> >> - using only 2 buffers (rather than 5) was sufficient to saturate  the
> >> client when we were running multiple processes; adding more  made only
> >> a marginal difference
> >>
> >> We found good results using 2 32MB buffers.  Here are some
> >> comparisons between the standard settings and the 2 x 32MB
> >> configuration:
> >>
> >> results for RHEL4 (2.6 kernel):
> >> ------------------------------
> >> 5 x 4MB, 1 process: 83.6 MB/s
> >> 2 x 32MB, 1 process: 95.5 MB/s
> >>
> >> 5 x 4MB, 5 processes: 107.4 MB/s
> >> 2 x 32MB, 5 processes: 111.2 MB/s
> >>
> >> results for RHEL3 (2.4 kernel):
> >> -------------------------------
> >> 5 x 4MB, 1 process: 80.5 MB/s
> >> 2 x 32MB, 1 process: 90.7 MB/s
> >>
> >> 5 x 4MB, 5 processes: 91 MB/s
> >> 2 x 32MB, 5 processes: 103.5 MB/s
> >>
> >>
> >> A few comments based on those numbers:
> >>
> >> - on 3 out of 4 tests, we saw a 13-15% performance improvement by
> >> going to 2 32 MB buffers
> >> - the remaining test (5 process RHEL4) probably did not see as much
> >> improvement because we maxed out the network.  In the past, netpipe
> >> has shown that we can get around 112 MB/s out of these nodes.
> >> - the RHEL3 nodes are on a different switch, so it is hard to say  how
> >> much of the difference from RHEL3 to RHEL4 is due to network  topology
> >> and how much is due to the kernel version
> >>
> >> It is also worth noting that even with this tuning, the single
> >> process tests are about 14% slower than the 5 process tests.  I am
> >> guessing that this is due to a lack of pipelining, probably caused  by
> >> two things:
> >> - the application only submitting one read/write at a time
> >> - the kernel module itself serializing when it breaks reads/writes
> >> into buffer sized chunks
> >>
> >> The latter could be addressed by either pipelining the I/O through
> >> the bufmap interface (so that a single read or write could keep
> >> multiple buffers busy) or by going to a system like Murali came up
> >> with for memory transfers a while back that isn't limited by buffer
> >> size.
> >>
> >> It would also be nice to have a way to set these buffer settings
> >> without recompiling- either via module options or via pvfs2-client-
> >> core command line options.  For the time being we are going to hard
> >> code our tree to run with the 32 MB buffers.  The 64 MB of RAM that
> >> this uses up (vs. 20 MB with the old settings) doesn't really  matter
> >> for our standard node footprint.
> >>
> >> -Phil
> >> _______________________________________________
> >> Pvfs2-developers mailing list
> >> [email protected]
> >> http://www.beowulf-underground.org/mailman/listinfo/pvfs2-developers
> >>
> >
>
> _______________________________________________
> Pvfs2-developers mailing list
> [email protected]
> http://www.beowulf-underground.org/mailman/listinfo/pvfs2-developers
>

diff -Naur --exclude doc pvfs-2.6.0/src/apps/kernel/linux/pvfs2-client.c /exit14/home/muraliv/pvfs-2.6.0/src/apps/kernel/linux/pvfs2-client.c
--- pvfs-2.6.0/src/apps/kernel/linux/pvfs2-client.c	2006-11-14 21:07:05.000000000 -0800
+++ /exit14/home/muraliv/pvfs-2.6.0/src/apps/kernel/linux/pvfs2-client.c	2006-11-29 19:47:01.358970000 -0800
@@ -53,6 +53,8 @@
     char *path;
     char *logfile;
     char *logstamp;
+    char *dev_buffer_count;
+    char *dev_buffer_size;
     int threaded;
 } options_t;
 
@@ -345,6 +347,18 @@
                 arg_list[arg_index+1] = opts->logstamp;
                 arg_index+=2;
             }
+            if(opts->dev_buffer_count)
+            {
+                arg_list[arg_index] = "--desc-count";
+                arg_list[arg_index+1] = opts->dev_buffer_count;
+                arg_index+=2;
+            }
+            if(opts->dev_buffer_size)
+            {
+                arg_list[arg_index] = "--desc-size";
+                arg_list[arg_index+1] = opts->dev_buffer_size;
+                arg_index+=2;
+            }
 
             ret = execvp(opts->path, arg_list);
 
@@ -406,6 +420,8 @@
         {"ncache-timeout",1,0,0},
         {"ncache-soft-limit",1,0,0},
         {"ncache-hard-limit",1,0,0},
+        {"desc-count",1,0,0},
+        {"desc-size",1,0,0},
         {"ncache-reclaim-percentage",1,0,0},
         {"perf-time-interval-secs",1,0,0},
         {"perf-history-size",1,0,0},
@@ -492,6 +508,16 @@
                     opts->ncache_reclaim_percentage = optarg;
                     break;
                 }
+                else if (strcmp("desc-count", cur_option) == 0) 
+                {
+                    opts->dev_buffer_count = optarg;
+                    break;
+                }
+                else if (strcmp("desc-size", cur_option) == 0)
+                {
+                    opts->dev_buffer_size = optarg;
+                    break;
+                }
                 else if (strcmp("perf-time-interval-secs", cur_option) == 0)
                 {
                     opts->perf_time_interval_secs = optarg;
diff -Naur --exclude doc pvfs-2.6.0/src/apps/kernel/linux/pvfs2-client-core.c /exit14/home/muraliv/pvfs-2.6.0/src/apps/kernel/linux/pvfs2-client-core.c
--- pvfs-2.6.0/src/apps/kernel/linux/pvfs2-client-core.c	2006-11-14 21:07:05.000000000 -0800
+++ /exit14/home/muraliv/pvfs-2.6.0/src/apps/kernel/linux/pvfs2-client-core.c	2006-11-29 19:41:37.612543000 -0800
@@ -54,7 +54,7 @@
   optimal i/o transfer size); regardless of this value, the fragment
   size (underlying fs block size) in the kernel is fixed at 1024
 */
-#define STATFS_DEFAULT_BLOCKSIZE PVFS2_BUFMAP_DEFAULT_DESC_SIZE
+#define STATFS_DEFAULT_BLOCKSIZE pvfs2_bufmap_desc_size
 
 /*
   default timeout value to wait for completion of in progress
@@ -99,6 +99,11 @@
     int logstamp_type;
     int logstamp_type_set;
     int standalone;
+    /* kernel module buffer size settings */
+    unsigned int dev_buffer_count;
+    int dev_buffer_count_set;
+    unsigned int dev_buffer_size;
+    int dev_buffer_size_set;
 } options_t;
 
 /*
@@ -185,7 +190,7 @@
 /* We have 2 set of description buffers, one used for staging I/O and one for readdir/readdirplus */
 #define NUM_MAP_DESC 2
 static struct PVFS_dev_map_desc s_io_desc[NUM_MAP_DESC];
-static int s_desc_size[NUM_MAP_DESC] = {PVFS2_BUFMAP_TOTAL_SIZE, PVFS2_READDIR_TOTAL_SIZE};
+static struct PINT_dev_params s_desc_params[NUM_MAP_DESC];
 
 static struct PINT_perf_counter* acache_pc = NULL;
 static struct PINT_perf_counter* ncache_pc = NULL;
@@ -204,6 +209,7 @@
 static void reset_acache_timeout(void);
 static char *get_vfs_op_name_str(int op_type);
 static int set_acache_parameters(options_t* s_opts);
+static void set_device_parameters(options_t *s_opts);
 static void reset_ncache_timeout(void);
 static int set_ncache_parameters(options_t* s_opts);
 
@@ -1414,7 +1420,7 @@
 
     assert((vfs_request->in_upcall.req.io.buf_index > -1) &&
            (vfs_request->in_upcall.req.io.buf_index <
-            PVFS2_BUFMAP_DESC_COUNT));
+            pvfs2_bufmap_desc_count));
 
     vfs_request->io_tmp_buf = malloc(
         vfs_request->in_upcall.req.io.readahead_size);
@@ -1561,7 +1567,7 @@
 
     assert((vfs_request->in_upcall.req.io.buf_index > -1) &&
            (vfs_request->in_upcall.req.io.buf_index <
-            PVFS2_BUFMAP_DESC_COUNT));
+            pvfs2_bufmap_desc_count));
 
     /* get a shared kernel/userspace buffer for the I/O transfer */
     vfs_request->io_kernel_mapped_buf = 
@@ -1636,7 +1642,7 @@
             (unsigned long) vfs_request->in_upcall.req.iox.count);
 
     if ((vfs_request->in_upcall.req.iox.buf_index < 0) ||
-           (vfs_request->in_upcall.req.iox.buf_index >= PVFS2_BUFMAP_DESC_COUNT))
+           (vfs_request->in_upcall.req.iox.buf_index >= pvfs2_bufmap_desc_count))
     {
         gossip_err("post_iox_request: invalid buffer index %d\n",
                 vfs_request->in_upcall.req.iox.buf_index);
@@ -3147,6 +3153,7 @@
         PVFS_perror("set_ncache_parameters", ret);
         return(ret);
     }
+    set_device_parameters(&s_opts);
 
     /* start performance counters for acache */
     acache_pc = PINT_perf_initialize(acache_keys);
@@ -3229,7 +3236,7 @@
 
     /* setup a mapped region for I/O transfers */
     memset(s_io_desc, 0 , NUM_MAP_DESC * sizeof(struct PVFS_dev_map_desc));
-    ret = PINT_dev_get_mapped_regions(NUM_MAP_DESC, s_io_desc, s_desc_size);
+    ret = PINT_dev_get_mapped_regions(NUM_MAP_DESC, s_io_desc, s_desc_params);
     if (ret < 0)
     {
 	PVFS_perror("PINT_dev_get_mapped_region", ret);
@@ -3323,7 +3330,9 @@
     printf("--logfile=VALUE               override the default log file\n");
     printf("--logstamp=none|usec|datetime overrides the default log message's time stamp\n");
     printf("--gossip-mask=MASK_LIST       gossip logging mask\n");
- }
+    printf("--desc-count=VALUE            overrides the default # of kernel buffer descriptors\n");
+    printf("--desc-size=VALUE             overrides the default size of each kernel buffer descriptor\n");
+}
 
 static void parse_args(int argc, char **argv, options_t *opts)
 {
@@ -3343,6 +3352,8 @@
         {"acache-soft-limit",1,0,0},
         {"ncache-hard-limit",1,0,0},
         {"ncache-soft-limit",1,0,0},
+        {"desc-count",1,0,0},
+        {"desc-size",1,0,0},
         {"logfile",1,0,0},
         {"logstamp",1,0,0},
         {"standalone",0,0,0},
@@ -3373,6 +3384,28 @@
                 {
                     goto do_ncache;
                 }
+                else if (strcmp("desc-count", cur_option) == 0) 
+                {
+                    ret = sscanf(optarg, "%u", &opts->dev_buffer_count);
+                    if(ret != 1)
+                    {
+                        gossip_err(
+                            "Error: invalid descriptor count value.\n");
+                        exit(EXIT_FAILURE);
+                    }
+                    opts->dev_buffer_count_set = 1;
+                }
+                else if (strcmp("desc-size", cur_option) == 0)
+                {
+                    ret = sscanf(optarg, "%u", &opts->dev_buffer_size);
+                    if(ret != 1)
+                    {
+                        gossip_err(
+                            "Error: invalid descriptor size value.\n");
+                        exit(EXIT_FAILURE);
+                    }
+                    opts->dev_buffer_size_set = 1;
+                }
                 else if (strcmp("logfile", cur_option) == 0)
                 {
                     goto do_logfile;
@@ -3773,6 +3806,30 @@
     return(0);
 }
 
+static void set_device_parameters(options_t *s_opts)
+{
+    if (s_opts->dev_buffer_count_set)
+    {
+        s_desc_params[BM_IO].dev_buffer_count = s_opts->dev_buffer_count;
+    }
+    else
+    {
+        s_desc_params[BM_IO].dev_buffer_count = PVFS2_BUFMAP_DEFAULT_DESC_COUNT;
+    }
+    if (s_opts->dev_buffer_size_set)
+    {
+        s_desc_params[BM_IO].dev_buffer_size  = s_opts->dev_buffer_size;
+    }
+    else
+    {
+        s_desc_params[BM_IO].dev_buffer_size = PVFS2_BUFMAP_DEFAULT_DESC_SIZE;
+    }
+    /* No command line options accepted for the readdir buffers */
+    s_desc_params[BM_READDIR].dev_buffer_count = PVFS2_READDIR_DEFAULT_DESC_COUNT;
+    s_desc_params[BM_READDIR].dev_buffer_size  = PVFS2_READDIR_DEFAULT_DESC_SIZE;
+    return;
+}
+
 /*
  * Local variables:
  *  c-indent-level: 4
diff -Naur --exclude doc pvfs-2.6.0/src/io/dev/pint-dev.c /exit14/home/muraliv/pvfs-2.6.0/src/io/dev/pint-dev.c
--- pvfs-2.6.0/src/io/dev/pint-dev.c	2006-11-14 21:07:06.000000000 -0800
+++ /exit14/home/muraliv/pvfs-2.6.0/src/io/dev/pint-dev.c	2006-11-29 19:40:27.383384000 -0800
@@ -41,6 +41,9 @@
 static int32_t pdev_max_upsize;
 static int32_t pdev_max_downsize;
 
+int32_t pvfs2_bufmap_total_size, pvfs2_bufmap_desc_size;
+int32_t pvfs2_bufmap_desc_count, pvfs2_bufmap_desc_shift;
+
 /* PINT_dev_initialize()
  *
  * initializes the device management interface
@@ -147,34 +150,52 @@
  *
  * returns 0 on success, -PVFS_error on failure
  */
-int PINT_dev_get_mapped_regions(int ndesc, struct PVFS_dev_map_desc *desc, int *size)
+int PINT_dev_get_mapped_regions(int ndesc, struct PVFS_dev_map_desc *desc,
+                                struct PINT_dev_params *params)
 {
     int i, ret = -1;
-    int page_count = 0;
-    long page_size = sysconf(_SC_PAGE_SIZE);
+    long page_size = sysconf(_SC_PAGE_SIZE), total_size;
     void *ptr = NULL;
     int ioctl_cmd[2] = {PVFS_DEV_MAP, 0};
 
     for (i = 0; i < ndesc; i++)
     {
+        total_size = params[i].dev_buffer_size * params[i].dev_buffer_count;
+        if (total_size < 0) 
+        {
+            gossip_err("Error:please provide sane values for device parameters.\n");
+            break;
+        }
+        if (total_size % page_size != 0) 
+        {
+            gossip_err("Error: total device buffer size must be a multiple of system page size.\n");
+            break;
+        }
+        if (total_size >= PVFS2_BUFMAP_MAX_TOTAL_SIZE)
+        {
+            gossip_err("Error: total size (%ld) of device buffer must be < %d MB.\n",
+                    total_size, PVFS2_BUFMAP_MAX_TOTAL_SIZE);
+            break;
+        }
+        if (params[i].dev_buffer_size & (params[i].dev_buffer_size - 1))
+        {
+            gossip_err("Error: descriptor size must be a power of 2 (%d)\n",
+                        params[i].dev_buffer_size);
+            break;
+        }
         /* we would like to use a memaligned region that is a multiple
          * of the system page size
          */
-        page_count = (int)(size[i] / page_size);
-        if ((size[i] % page_size) != 0)
-        {
-            page_count++;
-        }
-
-        ptr = PINT_mem_aligned_alloc(
-            (page_count * page_size), page_size);
+        ptr = PINT_mem_aligned_alloc(total_size, page_size);
         if (!ptr)
         {
             desc[i].ptr = NULL;
             break;
         }
         desc[i].ptr  = ptr;
-        desc[i].size = (page_count * page_size);
+        desc[i].total_size = total_size;
+        desc[i].size = params[i].dev_buffer_size;
+        desc[i].count = params[i].dev_buffer_count;
 
         /* ioctl to ask driver to map pages if needed */
         if (ioctl_cmd[i] != 0)
@@ -184,6 +205,10 @@
             {
                 break;
             }
+            pvfs2_bufmap_desc_count = params[i].dev_buffer_count;
+            pvfs2_bufmap_desc_size  = params[i].dev_buffer_size;
+            pvfs2_bufmap_total_size = total_size;
+            pvfs2_bufmap_desc_shift = LOG2(pvfs2_bufmap_desc_size);
         }
     }
     if (i != ndesc) {
@@ -223,7 +248,7 @@
 
 /* PINT_dev_get_mapped_buffer()
  *
- * returns a memory buffer of size PVFS2_BUFMAP_DEFAULT_DESC_SIZE
+ * returns a memory buffer of size (pvfs2_bufmap_desc_size)
  * matching the specified buffer_index given a PVFS_dev_map_desc
  *
  * returns a valid desc addr on success, NULL on failure
@@ -240,10 +265,10 @@
         return NULL;
 
     desc_count = (bm_type == BM_IO) ? 
-                PVFS2_BUFMAP_DESC_COUNT :
-                PVFS2_READDIR_DESC_COUNT;
+                pvfs2_bufmap_desc_count :
+                PVFS2_READDIR_DEFAULT_DESC_COUNT;
     desc_size  = (bm_type == BM_IO) ? 
-                PVFS2_BUFMAP_DEFAULT_DESC_SIZE : 
+                pvfs2_bufmap_desc_size : 
                 PVFS2_READDIR_DEFAULT_DESC_SIZE;
     ptr =  (char *) desc[bm_type].ptr;
     return ((desc && ptr &&
diff -Naur --exclude doc pvfs-2.6.0/src/io/dev/pint-dev.h /exit14/home/muraliv/pvfs-2.6.0/src/io/dev/pint-dev.h
--- pvfs-2.6.0/src/io/dev/pint-dev.h	2006-11-14 21:07:06.000000000 -0800
+++ /exit14/home/muraliv/pvfs-2.6.0/src/io/dev/pint-dev.h	2006-11-29 16:55:22.924417000 -0800
@@ -29,6 +29,12 @@
     PINT_DEV_EXT_ALLOC = 2
 };
 
+struct PINT_dev_params 
+{
+    int32_t dev_buffer_count;
+    int32_t dev_buffer_size;
+};
+
 int PINT_dev_initialize(
     const char* dev_name,
     int flags);
@@ -36,7 +42,7 @@
 int PINT_dev_get_mapped_regions(
     int ndesc,
     struct PVFS_dev_map_desc *desc,
-    int *size);
+    struct PINT_dev_params *params);
 
 void PINT_dev_put_mapped_regions(
     int ndesc,
diff -Naur --exclude doc pvfs-2.6.0/src/io/dev/pint-dev-shared.h /exit14/home/muraliv/pvfs-2.6.0/src/io/dev/pint-dev-shared.h
--- pvfs-2.6.0/src/io/dev/pint-dev-shared.h	2006-11-14 21:07:06.000000000 -0800
+++ /exit14/home/muraliv/pvfs-2.6.0/src/io/dev/pint-dev-shared.h	2006-11-29 17:22:45.495323000 -0800
@@ -24,11 +24,11 @@
 #define PVFS_KERNEL_PROTO_VERSION ((PVFS2_VERSION_MAJOR * 10000) + \
   (PVFS2_VERSION_MINOR * 100) + PVFS2_VERSION_SUB)
 
-/* This is the number of discrete buffers we will break the mapped I/O
+/* This is the default number of discrete buffers we will break the mapped I/O
  * region into.  In some sense it governs the number of concurrent I/O
  * operations that we will allow
  */
-#define PVFS2_BUFMAP_DESC_COUNT    5
+#define PVFS2_BUFMAP_DEFAULT_DESC_COUNT    5
 
 /*
   by default, we assume each description size is 4MB; this value
@@ -44,14 +44,39 @@
 #define PVFS2_BUFMAP_DEFAULT_DESC_SHIFT 22 /* NOTE: 2^22 == 4MB */
 
 /* size of mapped buffer region to use for I/O transfers (in bytes) */
-#define PVFS2_BUFMAP_TOTAL_SIZE \
-(PVFS2_BUFMAP_DESC_COUNT * PVFS2_BUFMAP_DEFAULT_DESC_SIZE)
+#define PVFS2_BUFMAP_DEFAULT_TOTAL_SIZE \
+(PVFS2_BUFMAP_DEFAULT_DESC_COUNT * PVFS2_BUFMAP_DEFAULT_DESC_SIZE)
 
-#define PVFS2_READDIR_DESC_COUNT  5
+/* Since there is no clean way to share C files and declarations of variables,
+   between kernel and user-land, we extern a variable here and expect that 
+   kernel and userspace C file will provide the definitions and space for them.
+*/
+extern int32_t pvfs2_bufmap_total_size, pvfs2_bufmap_desc_size;
+extern int32_t pvfs2_bufmap_desc_count, pvfs2_bufmap_desc_shift;
+
+/* Sane maximum values for these parameters (128 MB) */
+#define PVFS2_BUFMAP_MAX_TOTAL_SIZE      (128 * (1024 * 1024))
+
+/* log to base 2 when we know that number is a power of 2 */
+static inline int LOG2(int number)
+{
+    int count = 0;
+    if (number == 0 || (number & (number - 1))) 
+    {
+        return -1;
+    }
+    while (number >>= 1)
+    {
+        count++;
+    }
+    return count;
+}
+
+#define PVFS2_READDIR_DEFAULT_DESC_COUNT  5
 #define PVFS2_READDIR_DEFAULT_DESC_SIZE  (128 * 1024)
 #define PVFS2_READDIR_DEFAULT_DESC_SHIFT 17
-#define PVFS2_READDIR_TOTAL_SIZE \
-(PVFS2_READDIR_DESC_COUNT * PVFS2_READDIR_DEFAULT_DESC_SIZE)
+#define PVFS2_READDIR_DEFAULT_TOTAL_SIZE \
+(PVFS2_READDIR_DEFAULT_DESC_COUNT * PVFS2_READDIR_DEFAULT_DESC_SIZE)
 
 /* pvfs2-client-core can cache readahead data up to this size in bytes */
 #define PVFS2_MMAP_RACACHE_MAX_SIZE ((loff_t)(8 * (1024 * 1024)))
@@ -66,7 +91,9 @@
 struct PVFS_dev_map_desc
 {
     void     *ptr;
-    int32_t  size; /* Changed to an int32_t for fixed size structure */
+    int32_t  total_size; 
+    int32_t  size;
+    int32_t  count;
 };
 
 #define PVFS_DEV_MAGIC 'k'
diff -Naur --exclude doc pvfs-2.6.0/src/kernel/linux-2.6/devpvfs2-req.c /exit14/home/muraliv/pvfs-2.6.0/src/kernel/linux-2.6/devpvfs2-req.c
--- pvfs-2.6.0/src/kernel/linux-2.6/devpvfs2-req.c	2006-11-14 21:07:06.000000000 -0800
+++ /exit14/home/muraliv/pvfs-2.6.0/src/kernel/linux-2.6/devpvfs2-req.c	2006-11-29 20:06:15.505992000 -0800
@@ -775,7 +775,9 @@
 struct PVFS_dev_map_desc32 
 {
     compat_uptr_t ptr;
+    int32_t      total_size;
     int32_t      size;
+    int32_t      count;
 };
 
 #ifndef PVFS2_LINUX_KERNEL_2_4
@@ -794,9 +796,13 @@
     /* try to put that into a 64-bit layout */
     if (put_user(compat_ptr(addr), &p->ptr))
         goto err;
-    /* copy the remaining field */
+    /* copy the remaining fields */
+    if (copy_in_user(&p->total_size, &p32->total_size, sizeof(int32_t)))
+        goto err;
     if (copy_in_user(&p->size, &p32->size, sizeof(int32_t)))
         goto err;
+    if (copy_in_user(&p->count, &p32->count, sizeof(int32_t)))
+        goto err;
     return (unsigned long) p;
 err:
     *error = -EFAULT;
@@ -807,17 +813,23 @@
         unsigned long args, struct PVFS_dev_map_desc *p, long *error)
 {
     struct PVFS_dev_map_desc32  __user *p32 = (void __user *) args;
-    u32 addr, size;
+    u32 addr, size, total_size, count;
 
     *error = 0;
     /* get the ptr from the 32 bit user-space */
     if (get_user(addr, &p32->ptr))
         goto err;
     p->ptr = compat_ptr(addr);
-    /* copy the size */
+    /* copy the remaining fields */
+    if (get_user(total_size, &p32->total_size))
+        goto err;
     if (get_user(size, &p32->size))
         goto err;
+    if (get_user(count, &p32->count))
+        goto err;
+    p->total_size = total_size;
     p->size = size;
+    p->count = count;
     return 0;
 err:
     *error = -EFAULT;
diff -Naur --exclude doc pvfs-2.6.0/src/kernel/linux-2.6/file.c /exit14/home/muraliv/pvfs-2.6.0/src/kernel/linux-2.6/file.c
--- pvfs-2.6.0/src/kernel/linux-2.6/file.c	2006-11-14 21:07:06.000000000 -0800
+++ /exit14/home/muraliv/pvfs-2.6.0/src/kernel/linux-2.6/file.c	2006-11-29 18:23:03.887778000 -0800
@@ -307,7 +307,9 @@
 /*
  * The reason we need to do this is to be able to support 
  * readv and writev that are
- * larger than PVFS_DEFAULT_DESC_SIZE (4 MB). What that means is that
+ * larger than (pvfs_bufmap_size_query())
+ * Default is PVFS2_BUFMAP_DEFAULT_DESC_SIZE MB.
+ * What that means is that
  * we will create a new io vec descriptor for those memory addresses that 
  * go beyond the limit
  * Return value for this routine is -ve in case of errors
@@ -315,7 +317,7 @@
  * Further, the new_nr_segs pointer is updated to hold the new value
  * of number of iovecs, the new_vec pointer is updated to hold the pointer
  * to the new split iovec, and the size array is an array of integers holding
- * the number of iovecs that straddle PVFS_DEFAULT_DESC_SIZE.
+ * the number of iovecs that straddle pvfs_bufmap_size_query().
  * The max_new_nr_segs value is computed by the caller and returned.
  * (It will be (count of all iov_len/ block_size) + 1).
  */
@@ -854,7 +856,9 @@
 
 /*
  * The reason we need to do this is to be able to support readx() and writex()
- * of larger than PVFS_DEFAULT_DESC_SIZE (4 MB). What that means is that
+ * of larger than (pvfs_bufmap_size_query()) 
+ * (default is PVFS2_BUFMAP_DEFAULT_DESC_SIZE MB).
+ * What that means is that
  * we will create a new xtvec descriptor for those file offsets that 
  * go beyond the limit
  * Return value for this routine is -ve in case of errors
@@ -862,7 +866,7 @@
  * Further, the new_nr_segs pointer is updated to hold the new value
  * of number of xtvecs, the new_xtvec pointer is updated to hold the pointer
  * to the new split xtvec, and the size array is an array of integers holding
- * the number of xtvecs that straddle PVFS_DEFAULT_DESC_SIZE.
+ * the number of xtvecs that straddle (pvfs_bufmap_size_query()).
  * The max_new_nr_segs value is computed by the caller and passed in.
  * (It will be (count of all xtv_len/ block_size) + 1).
  */
diff -Naur --exclude doc pvfs-2.6.0/src/kernel/linux-2.6/pvfs2-bufmap.c /exit14/home/muraliv/pvfs-2.6.0/src/kernel/linux-2.6/pvfs2-bufmap.c
--- pvfs-2.6.0/src/kernel/linux-2.6/pvfs2-bufmap.c	2006-11-14 21:07:06.000000000 -0800
+++ /exit14/home/muraliv/pvfs-2.6.0/src/kernel/linux-2.6/pvfs2-bufmap.c	2006-11-29 19:41:14.699665000 -0800
@@ -7,23 +7,84 @@
 #include "pvfs2-bufmap.h"
 #include "pint-dev-shared.h"
 
-#define BUFMAP_PAGE_COUNT (PVFS2_BUFMAP_TOTAL_SIZE/PAGE_SIZE)
-#define PAGES_PER_DESC (PVFS2_BUFMAP_DEFAULT_DESC_SIZE/PAGE_SIZE)
+
+static int bufmap_page_count, pages_per_desc;
+
+static int32_t pvfs2_bufmap_total_size;
+static int32_t pvfs2_bufmap_desc_count; 
+int32_t pvfs2_bufmap_desc_size, pvfs2_bufmap_desc_shift;
 
 static int bufmap_init = 0;
 static struct page **bufmap_page_array = NULL;
+
 /* array to track usage of buffer descriptors */
-static int buffer_index_array[PVFS2_BUFMAP_DESC_COUNT] = {0};
+static int *buffer_index_array = NULL;
 static spinlock_t buffer_index_lock = SPIN_LOCK_UNLOCKED;
 
 /* array to track usage of buffer descriptors for readdir/readdirplus */
-int readdir_index_array[PVFS2_READDIR_DESC_COUNT] = {0};
+static int readdir_index_array[PVFS2_READDIR_DEFAULT_DESC_COUNT] = {0};
 static spinlock_t readdir_index_lock = SPIN_LOCK_UNLOCKED;
 
-static struct pvfs_bufmap_desc desc_array[PVFS2_BUFMAP_DESC_COUNT];
+static struct pvfs_bufmap_desc *desc_array = NULL;
+
 static DECLARE_WAIT_QUEUE_HEAD(bufmap_waitq);
 static DECLARE_WAIT_QUEUE_HEAD(readdir_waitq);
 
+static int initialize_bufmap_descriptors(int ndescs)
+{
+    int err;
+
+    err = -EINVAL;
+    if (ndescs < 0)
+    {
+        gossip_err("pvfs2: ndescs (%d) cannot be < 0.\n", ndescs);
+        goto out;
+    }
+    err = -ENOMEM;
+    buffer_index_array = (int *) kmalloc(ndescs * sizeof(int), 
+                                         PVFS2_BUFMAP_GFP_FLAGS);
+    if (buffer_index_array == NULL) 
+    {
+        gossip_err("pvfs2: could not allocate %d bytes\n",
+                ndescs * sizeof(int));
+        goto out;
+    }
+    memset(buffer_index_array, 0, ndescs * sizeof(int));
+
+    desc_array = (struct pvfs_bufmap_desc *) 
+                 kmalloc(ndescs * sizeof(struct pvfs_bufmap_desc),
+                         PVFS2_BUFMAP_GFP_FLAGS);
+    if (desc_array == NULL)
+    {
+        gossip_err("pvfs2: could not allocate %d bytes\n",
+                ndescs * sizeof(struct pvfs_bufmap_desc));
+        goto out1;
+    }
+    err = 0;
+    goto out;
+
+out1:
+    kfree(buffer_index_array);
+    buffer_index_array = NULL;
+out:
+    return err;
+}
+
+static void finalize_bufmap_descriptors(void)
+{
+    if (buffer_index_array != NULL) 
+    {
+        kfree(buffer_index_array);
+        buffer_index_array = NULL;
+    }
+    if (desc_array != NULL)
+    {
+        kfree(desc_array);
+        desc_array = NULL;
+    }
+    return;
+}
+
 /* pvfs_bufmap_initialize()
  *
  * initializes the mapped buffer interface
@@ -36,7 +97,9 @@
     int i = 0;
     int offset = 0;
 
-    gossip_debug(GOSSIP_BUFMAP_DEBUG, "pvfs2_bufmap_initialize: called\n");
+    gossip_debug(GOSSIP_BUFMAP_DEBUG, "pvfs2_bufmap_initialize: called "
+                 "(ptr (%p) sz (%d) cnt(%d).\n",
+                 user_desc->ptr, user_desc->size, user_desc->count);
 
     if (bufmap_init == 1)
     {
@@ -51,34 +114,50 @@
     if (PAGE_ALIGN((unsigned long)user_desc->ptr) != 
         (unsigned long)user_desc->ptr)
     {
-        gossip_err("pvfs2 error: memory alignment (front).\n");
+        gossip_err("pvfs2 error: memory alignment (front). %p\n",
+                user_desc->ptr);
         goto init_failure;
     }
 
-    if (PAGE_ALIGN(((unsigned long)user_desc->ptr + user_desc->size)) != 
-        (unsigned long)(user_desc->ptr + user_desc->size))
+    if (PAGE_ALIGN(((unsigned long)user_desc->ptr + user_desc->total_size)) != 
+        (unsigned long)(user_desc->ptr + user_desc->total_size))
     {
-        gossip_err("pvfs2 error: memory alignment (back).\n");
+        gossip_err("pvfs2 error: memory alignment (back).(%p + %d)\n",
+                user_desc->ptr, user_desc->total_size);
         goto init_failure;
     }
 
-    if (user_desc->size != PVFS2_BUFMAP_TOTAL_SIZE)
+    if (user_desc->total_size != (user_desc->size * user_desc->count))
     {
         gossip_err("pvfs2 error: user provided an oddly "
-                    "sized buffer...\n");
+                    "sized buffer...(%d, %d, %d)\n",
+                    user_desc->total_size, user_desc->size, user_desc->count);
         goto init_failure;
     }
 
-    if ((PVFS2_BUFMAP_DEFAULT_DESC_SIZE % PAGE_SIZE) != 0)
+    if ((user_desc->size % PAGE_SIZE) != 0)
     {
         gossip_err("pvfs2 error: bufmap size not page size "
-                    "divisible.\n");
+                    "divisible (%d).\n", user_desc->size);
+        goto init_failure;
+    }
+    /* Initialize critical variables */
+    pvfs2_bufmap_total_size = user_desc->total_size;
+    pvfs2_bufmap_desc_count = user_desc->count;
+    pvfs2_bufmap_desc_size  = user_desc->size;
+    pvfs2_bufmap_desc_shift = LOG2(pvfs2_bufmap_desc_size);
+    bufmap_page_count = pvfs2_bufmap_total_size / PAGE_SIZE;
+    pages_per_desc    = pvfs2_bufmap_desc_size / PAGE_SIZE;
+    /* Initialize descriptor arrays */
+    if ((ret = initialize_bufmap_descriptors(pvfs2_bufmap_desc_count)) < 0)
+    {
         goto init_failure;
     }
 
     /* allocate storage to track our page mappings */
-    bufmap_page_array = (struct page **)kmalloc(
-        BUFMAP_PAGE_COUNT*sizeof(struct page *), PVFS2_BUFMAP_GFP_FLAGS);
+    bufmap_page_array = (struct page **)
+                         kmalloc(bufmap_page_count * sizeof(struct page *),
+                                 PVFS2_BUFMAP_GFP_FLAGS);
     if (!bufmap_page_array)
     {
         ret = -ENOMEM;
@@ -90,7 +169,7 @@
 
     ret = get_user_pages(
         current, current->mm, (unsigned long)user_desc->ptr,
-        BUFMAP_PAGE_COUNT, 1, 0, bufmap_page_array, NULL);
+        bufmap_page_count, 1, 0, bufmap_page_array, NULL);
 
     up_read(&current->mm->mmap_sem);
 
@@ -104,10 +183,10 @@
       in theory we could run with what we got, but I will just treat
       it as an error for simplicity's sake right now
     */
-    if (ret != BUFMAP_PAGE_COUNT)
+    if (ret != bufmap_page_count)
     {
         gossip_err("pvfs2 error: asked for %d pages, only got %d.\n",
-                    (int)BUFMAP_PAGE_COUNT, ret);
+                    (int) bufmap_page_count, ret);
 
         for(i = 0; i < ret; i++)
         {
@@ -129,37 +208,43 @@
       it's worth.  in 2.4.x, marking the pages does what's expected
       and doesn't try to swap out our pages
     */
-    for(i = 0; i < BUFMAP_PAGE_COUNT; i++)
+    for(i = 0; i < bufmap_page_count; i++)
     {
         flush_dcache_page(bufmap_page_array[i]);
         pvfs2_set_page_reserved(bufmap_page_array[i]);
     }
 
     /* build a list of available descriptors */
-    for(offset = 0, i = 0; i < PVFS2_BUFMAP_DESC_COUNT; i++)
+    for(offset = 0, i = 0; i < pvfs2_bufmap_desc_count; i++)
     {
         desc_array[i].page_array = &bufmap_page_array[offset];
-        desc_array[i].array_count = PAGES_PER_DESC;
+        desc_array[i].array_count = pages_per_desc;
         desc_array[i].uaddr =
-            (user_desc->ptr + (i * PAGES_PER_DESC * PAGE_SIZE));
-        offset += PAGES_PER_DESC;
+            (user_desc->ptr + (i * pages_per_desc * PAGE_SIZE));
+        offset += pages_per_desc;
     }
 
     /* clear any previously used buffer indices */
     spin_lock(&buffer_index_lock);
-    for(i = 0; i < PVFS2_BUFMAP_DESC_COUNT; i++)
+    for(i = 0; i < pvfs2_bufmap_desc_count; i++)
     {
         buffer_index_array[i] = 0;
     }
     spin_unlock(&buffer_index_lock);
+    spin_lock(&readdir_index_lock);
+    for (i = 0; i < PVFS2_READDIR_DEFAULT_DESC_COUNT; i++)
+    {
+        readdir_index_array[i] = 0;
+    }
+    spin_unlock(&readdir_index_lock);
 
     bufmap_init = 1;
 
     gossip_debug(GOSSIP_BUFMAP_DEBUG, "pvfs2_bufmap_initialize: exiting normally\n");
     return 0;
 
-  init_failure:
-
+init_failure:
+    finalize_bufmap_descriptors();
     return ret;
 }
 
@@ -183,7 +268,7 @@
         return;
     }
 
-    for(i = 0; i < BUFMAP_PAGE_COUNT; i++)
+    for(i = 0; i < bufmap_page_count; i++)
     {
         pvfs2_clear_page_reserved(bufmap_page_array[i]);
         page_cache_release(bufmap_page_array[i]);
@@ -192,6 +277,7 @@
 
     bufmap_init = 0;
 
+    finalize_bufmap_descriptors();
     gossip_debug(GOSSIP_BUFMAP_DEBUG, "pvfs2_bufmap_finalize: exiting normally\n");
 }
 
@@ -281,7 +367,7 @@
 {
     struct slot_args slargs;
 
-    slargs.slot_count = PVFS2_BUFMAP_DESC_COUNT;
+    slargs.slot_count = pvfs2_bufmap_desc_count;
     slargs.slot_array = buffer_index_array;
     slargs.slot_lock  = &buffer_index_lock;
     slargs.slot_wq    = &bufmap_waitq;
@@ -298,7 +384,7 @@
 {
     struct slot_args slargs;
 
-    slargs.slot_count = PVFS2_BUFMAP_DESC_COUNT;
+    slargs.slot_count = pvfs2_bufmap_desc_count;
     slargs.slot_array = buffer_index_array;
     slargs.slot_lock  = &buffer_index_lock;
     slargs.slot_wq    = &bufmap_waitq;
@@ -320,7 +406,7 @@
 {
     struct slot_args slargs;
 
-    slargs.slot_count = PVFS2_READDIR_DESC_COUNT;
+    slargs.slot_count = PVFS2_READDIR_DEFAULT_DESC_COUNT;
     slargs.slot_array = readdir_index_array;
     slargs.slot_lock  = &readdir_index_lock;
     slargs.slot_wq    = &readdir_waitq;
@@ -331,7 +417,7 @@
 {
     struct slot_args slargs;
 
-    slargs.slot_count = PVFS2_READDIR_DESC_COUNT;
+    slargs.slot_count = PVFS2_READDIR_DEFAULT_DESC_COUNT;
     slargs.slot_array = readdir_index_array;
     slargs.slot_lock  = &readdir_index_lock;
     slargs.slot_wq    = &readdir_waitq;
@@ -548,21 +634,21 @@
 
         if (iv->iov_len < (PAGE_SIZE - page_offset)) 
         {
-            cur_copy_size = iv->iov_len;
+            cur_copy_size = PVFS_util_min(iv->iov_len, size - amt_copied);
             seg++;
             from_addr = iv->iov_base;
             inc_index = 0;
         }
         else if (iv->iov_len == (PAGE_SIZE - page_offset))
         {
-            cur_copy_size = iv->iov_len;
+            cur_copy_size = PVFS_util_min(iv->iov_len, size - amt_copied);
             seg++;
             from_addr = iv->iov_base;
             inc_index = 1;
         }
         else 
         {
-            cur_copy_size = (PAGE_SIZE - page_offset);
+            cur_copy_size = PVFS_util_min(PAGE_SIZE - page_offset, size - amt_copied);
             from_addr = iv->iov_base;
             iv->iov_base += cur_copy_size;
             iv->iov_len -= cur_copy_size;
@@ -671,21 +757,21 @@
 
         if (iv->iov_len < (PAGE_SIZE - page_offset)) 
         {
-            cur_copy_size = iv->iov_len;
+            cur_copy_size = PVFS_util_min(iv->iov_len, size - amt_copied);
             seg++;
             from_kaddr = iv->iov_base;
             inc_index = 0;
         }
         else if (iv->iov_len == (PAGE_SIZE - page_offset))
         {
-            cur_copy_size = iv->iov_len;
+            cur_copy_size = PVFS_util_min(iv->iov_len, size - amt_copied);
             seg++;
             from_kaddr = iv->iov_base;
             inc_index = 1;
         }
         else 
         {
-            cur_copy_size = (PAGE_SIZE - page_offset);
+            cur_copy_size = PVFS_util_min(PAGE_SIZE - page_offset, size - amt_copied);
             from_kaddr = iv->iov_base;
             iv->iov_base += cur_copy_size;
             iv->iov_len -= cur_copy_size;
@@ -784,21 +870,21 @@
 
         if (iv->iov_len < (PAGE_SIZE - page_offset))
         {
-            cur_copy_size = iv->iov_len;
+            cur_copy_size = PVFS_util_min(iv->iov_len, size - amt_copied);
             seg++;
             to_addr = iv->iov_base;
             inc_index = 0;
         }
         else if (iv->iov_len == (PAGE_SIZE - page_offset))
         {
-            cur_copy_size = iv->iov_len;
+            cur_copy_size = PVFS_util_min(iv->iov_len, size - amt_copied);
             seg++;
             to_addr = iv->iov_base;
             inc_index = 1;
         }
         else 
         {
-            cur_copy_size = (PAGE_SIZE - page_offset);
+            cur_copy_size = PVFS_util_min(PAGE_SIZE - page_offset, size - amt_copied);
             to_addr = iv->iov_base;
             iv->iov_base += cur_copy_size;
             iv->iov_len  -= cur_copy_size;
@@ -904,21 +990,21 @@
 
         if (iv->iov_len < (PAGE_SIZE - page_offset))
         {
-            cur_copy_size = iv->iov_len;
+            cur_copy_size = PVFS_util_min(iv->iov_len, size - amt_copied);
             seg++;
             to_kaddr = iv->iov_base;
             inc_index = 0;
         }
         else if (iv->iov_len == (PAGE_SIZE - page_offset))
         {
-            cur_copy_size = iv->iov_len;
+            cur_copy_size = PVFS_util_min(iv->iov_len, size - amt_copied);
             seg++;
             to_kaddr = iv->iov_base;
             inc_index = 1;
         }
         else 
         {
-            cur_copy_size = (PAGE_SIZE - page_offset);
+            cur_copy_size = PVFS_util_min(PAGE_SIZE - page_offset, size - amt_copied);
             to_kaddr = iv->iov_base;
             iv->iov_base += cur_copy_size;
             iv->iov_len  -= cur_copy_size;
diff -Naur --exclude doc pvfs-2.6.0/src/kernel/linux-2.6/pvfs2-bufmap.h /exit14/home/muraliv/pvfs-2.6.0/src/kernel/linux-2.6/pvfs2-bufmap.h
--- pvfs-2.6.0/src/kernel/linux-2.6/pvfs2-bufmap.h	2006-11-14 21:07:06.000000000 -0800
+++ /exit14/home/muraliv/pvfs-2.6.0/src/kernel/linux-2.6/pvfs2-bufmap.h	2006-11-29 18:20:53.072088000 -0800
@@ -9,6 +9,8 @@
 
 #include "pint-dev-shared.h"
 
+extern int32_t pvfs2_bufmap_desc_size;
+
 /* used to describe mapped buffers */
 struct pvfs_bufmap_desc
 {
@@ -18,8 +20,12 @@
     struct list_head list_link;
 };
 
-/* this would be a function call if the buffer sizes weren't hard coded */
-#define pvfs_bufmap_size_query() PVFS2_BUFMAP_DEFAULT_DESC_SIZE
+/* pvfs_bufmap_size_query is now an inline function because buffer
+   sizes are not hardcoded */
+static inline int pvfs_bufmap_size_query(void)
+{
+    return pvfs2_bufmap_desc_size;
+}
 
 int pvfs_bufmap_initialize(
     struct PVFS_dev_map_desc *user_desc);
diff -Naur --exclude doc pvfs-2.6.0/src/kernel/linux-2.6/pvfs2-kernel.h /exit14/home/muraliv/pvfs-2.6.0/src/kernel/linux-2.6/pvfs2-kernel.h
--- pvfs-2.6.0/src/kernel/linux-2.6/pvfs2-kernel.h	2006-11-14 21:07:06.000000000 -0800
+++ /exit14/home/muraliv/pvfs-2.6.0/src/kernel/linux-2.6/pvfs2-kernel.h	2006-11-29 18:16:15.774353000 -0800
@@ -905,6 +905,7 @@
 
 int pvfs2_normalize_to_errno(PVFS_error error_code);
 
+extern int32_t pvfs2_bufmap_desc_size, pvfs2_bufmap_desc_shift;
 extern struct semaphore devreq_semaphore;
 extern struct semaphore request_semaphore;
 extern int debug;
diff -Naur --exclude doc pvfs-2.6.0/src/kernel/linux-2.6/super.c /exit14/home/muraliv/pvfs-2.6.0/src/kernel/linux-2.6/super.c
--- pvfs-2.6.0/src/kernel/linux-2.6/super.c	2006-11-14 21:07:06.000000000 -0800
+++ /exit14/home/muraliv/pvfs-2.6.0/src/kernel/linux-2.6/super.c	2006-11-29 18:17:02.180723000 -0800
@@ -949,8 +949,8 @@
     sb->s_op = &pvfs2_s_ops;
     sb->s_type = &pvfs2_fs_type;
 
-    sb->s_blocksize = PVFS2_BUFMAP_DEFAULT_DESC_SIZE;
-    sb->s_blocksize_bits = PVFS2_BUFMAP_DEFAULT_DESC_SHIFT;
+    sb->s_blocksize = pvfs2_bufmap_desc_size;
+    sb->s_blocksize_bits = pvfs2_bufmap_desc_shift;
     sb->s_maxbytes = MAX_LFS_FILESIZE;
 
     root_object.handle = PVFS2_SB(sb)->root_handle;
@@ -1070,8 +1070,8 @@
     sb->s_op = &pvfs2_s_ops;
     sb->s_type = &pvfs2_fs_type;
 
-    sb->s_blocksize = PVFS2_BUFMAP_DEFAULT_DESC_SIZE;
-    sb->s_blocksize_bits = PVFS2_BUFMAP_DEFAULT_DESC_SHIFT;
+    sb->s_blocksize = pvfs2_bufmap_desc_size;
+    sb->s_blocksize_bits = pvfs2_bufmap_desc_shift;
     sb->s_maxbytes = MAX_LFS_FILESIZE;
 
     root_object.handle = PVFS2_SB(sb)->root_handle;
_______________________________________________
Pvfs2-developers mailing list
[email protected]
http://www.beowulf-underground.org/mailman/listinfo/pvfs2-developers

Reply via email to