[PVFS2-CVS] commit by slang in pvfs2/src/kernel/linux-2.6: xattr.c Makefile.in dcache.c devpvfs2-req.c dir.c downcall.h file.c inode.c namei.c pvfs2-bufmap.c pvfs2-bufmap.h pvfs2-cache.c pvfs2-dev-proto.h pvfs2-kernel.h pvfs2-mod.c pvfs2-utils.c super.c symlink.c upcall.h waitqueue.c

CVS commit program cvs at parl.clemson.edu
Thu Aug 25 17:38:31 EDT 2005


Update of /projects/cvsroot/pvfs2/src/kernel/linux-2.6
In directory parlweb:/tmp/cvs-serv7520/src/kernel/linux-2.6

Modified Files:
      Tag: slang-event-changes-branch
	Makefile.in dcache.c devpvfs2-req.c dir.c downcall.h file.c 
	inode.c namei.c pvfs2-bufmap.c pvfs2-bufmap.h pvfs2-cache.c 
	pvfs2-dev-proto.h pvfs2-kernel.h pvfs2-mod.c pvfs2-utils.c 
	super.c symlink.c upcall.h waitqueue.c 
Added Files:
      Tag: slang-event-changes-branch
	xattr.c 
Log Message:
updates to my event changes to bring them inline with trunk


--- /dev/null	2003-01-30 05:24:37.000000000 -0500
+++ xattr.c	2005-08-25 16:38:31.000000000 -0400
@@ -0,0 +1,80 @@
+/*
+ * (C) 2001 Clemson University and The University of Chicago
+ *
+ * See COPYING in top-level directory.
+ */
+
+/** \file
+ *  \ingroup pvfs2linux
+ *
+ *  Linux VFS extended attribute operations.
+ */
+
+#include "pvfs2-kernel.h"
+#include "pvfs2-bufmap.h"
+
+#ifdef HAVE_XATTR
+#include <linux/xattr.h>
+
+/* All pointers are in kernel-space */
+int pvfs2_setxattr(struct dentry *dentry, const char *name,
+		const void *value, size_t size, int flags)
+{
+    struct inode *inode = dentry->d_inode;
+    int internal_flag = 0;
+
+    /* VFS does a whole bunch of checks, but we still do
+    *  some here */
+    if (name == NULL || value == NULL ||
+            size < 0 || size >= PVFS_MAX_XATTR_VALUELEN)
+    {
+        pvfs2_error("pvfs2_setxattr: invalid parameters\n");
+        return -EINVAL;
+    }
+    /* Attribute must exist! */
+    if (flags & XATTR_REPLACE)
+    {
+        internal_flag = PVFS_XATTR_REPLACE;
+    }
+    /* Attribute must not exist */
+    else if (flags & XATTR_CREATE)
+    {
+        internal_flag = PVFS_XATTR_CREATE;
+    }
+    return pvfs2_inode_setxattr(inode, name, value, size, internal_flag);
+}
+
+ssize_t pvfs2_getxattr(struct dentry *dentry, const char *name,
+		         void *buffer, size_t size)
+{
+    struct inode *inode = dentry->d_inode;
+    return pvfs2_inode_getxattr(inode, name, buffer, size);
+}
+
+ssize_t pvfs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+    /* 
+     * FIXME: The reason I am returning this value here is because 
+     * we need server-side support for this, and I need to talk
+     * to Walt and RobR about this...
+     * Should not be too hard, but nonetheless a pain to get this
+     * right.
+     */
+    return -EOPNOTSUPP;
+}
+
+int pvfs2_removexattr(struct dentry *dentry, const char *name)
+{
+    struct inode *inode = dentry->d_inode;
+    return pvfs2_inode_removexattr(inode, name);
+}
+
+#endif
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ * End:
+ *
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */

Index: Makefile.in
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/Makefile.in,v
diff -p -u -r1.15 -r1.15.4.1
--- Makefile.in	23 Mar 2005 21:58:23 -0000	1.15
+++ Makefile.in	25 Aug 2005 20:38:29 -0000	1.15.4.1
@@ -44,6 +44,7 @@ csrc = \
     pvfs2-mod.c \
     pvfs2-bufmap.c \
     symlink.c \
+	 xattr.c \
     waitqueue.c
 hsrc = \
     pvfs2-kernel.h \
@@ -67,6 +68,7 @@ EXTRA_CFLAGS = \
     -I$(absolute_src_dir)/src/common/quickhash
 
 EXTRA_CFLAGS += @MMAP_RA_CACHE@
+EXTRA_CFLAGS += -DPVFS2_VERSION="\"@PVFS2_VERSION@\""
 
 # uncomment the following line for kernel specific
 # debugging output or features

Index: dcache.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/dcache.c,v
diff -p -u -r1.22 -r1.22.6.1
--- dcache.c	11 Jan 2005 17:45:03 -0000	1.22
+++ dcache.c	25 Aug 2005 20:38:29 -0000	1.22.6.1
@@ -12,20 +12,90 @@
 
 #include "pvfs2-kernel.h"
 
+extern int debug;
+extern kmem_cache_t *pvfs2_inode_cache;
+extern struct list_head pvfs2_request_list;
+extern spinlock_t pvfs2_request_list_lock;
+extern wait_queue_head_t pvfs2_request_list_waitq;
+
 /* should return 1 if dentry can still be trusted, else 0 */
-#ifdef PVFS2_LINUX_KERNEL_2_4
-int pvfs2_d_revalidate(
-    struct dentry *dentry,
-    int flags)
+static int pvfs2_d_revalidate_common(struct dentry* dentry)
 {
     int ret = 0;
     struct inode *inode = (dentry ? dentry->d_inode : NULL);
+    struct inode *parent_inode = NULL; 
+    pvfs2_kernel_op_t *new_op = NULL;
+    pvfs2_inode_t *parent = NULL;
+    int retries = PVFS2_OP_RETRY_COUNT, error_exit = 0;
 
-    pvfs2_print("pvfs2_d_revalidate: called on dentry %p", dentry);
-    if (inode)
+    pvfs2_print("pvfs2_d_revalidate: called on dentry %p.\n", dentry);
+
+    /* find parent inode */
+    if(dentry && dentry->d_parent)
+    {
+        pvfs2_print("pvfs2_d_revalidate: parent found.\n");
+        parent_inode = dentry->d_parent->d_inode;
+    }
+    else
     {
+        pvfs2_print("pvfs2_d_revalidate: parent not found.\n");
+    }
+    
+    if (inode && parent_inode)
+    {
+        /* first perform a lookup to make sure that the object not only
+         * exists, but is still in the expected place in the name space 
+         */
+        if(!(PVFS2_SB(inode->i_sb)->root_handle ==
+            pvfs2_ino_to_handle(inode->i_ino)))
+        {
+            pvfs2_print("pvfs2_d_revalidate: attempting lookup.\n");
+            new_op = op_alloc();
+            if (!new_op)
+            {
+                return 0;
+            }
+            new_op->upcall.type = PVFS2_VFS_OP_LOOKUP;
+            new_op->upcall.req.lookup.sym_follow = PVFS2_LOOKUP_LINK_NO_FOLLOW;
+            parent = PVFS2_I(parent_inode);
+            if (parent && parent->refn.handle && parent->refn.fs_id)
+            {
+                new_op->upcall.req.lookup.parent_refn = parent->refn;
+            }
+            else
+            {
+                new_op->upcall.req.lookup.parent_refn.handle =
+                    pvfs2_ino_to_handle(parent_inode->i_ino);
+                new_op->upcall.req.lookup.parent_refn.fs_id =
+                    PVFS2_SB(parent_inode->i_sb)->fs_id;
+            }
+            strncpy(new_op->upcall.req.lookup.d_name,
+                    dentry->d_name.name, PVFS2_NAME_LEN);
+
+            service_error_exit_op_with_timeout_retry(
+                new_op, "pvfs2_lookup", retries, error_exit,
+                PVFS2_SB(parent_inode->i_sb)->mnt_options.intr);
+
+            if((new_op->downcall.status != 0) ||
+               (new_op->downcall.resp.lookup.refn.handle !=
+               pvfs2_ino_to_handle(inode->i_ino)))
+            {
+                pvfs2_print("pvfs2_d_revalidate: lookup failure or no match.\n");
+                op_release(new_op);
+                return(0);
+            }
+            
+            op_release(new_op);
+        }
+        else
+        {
+            pvfs2_print("pvfs2_d_revalidate: root handle, lookup skipped.\n");
+        }
+
+        /* now perform revalidation */
         pvfs2_print(" (inode %Lu)\n",
                     Lu(pvfs2_ino_to_handle(inode->i_ino)));
+        pvfs2_print("pvfs2_d_revalidate: calling pvfs2_internal_revalidate().\n");
         ret = pvfs2_internal_revalidate(inode);
     }
     else
@@ -33,6 +103,20 @@ int pvfs2_d_revalidate(
         pvfs2_print("\n");
     }
     return ret;
+
+error_exit:
+    pvfs2_print("pvfs2_d_revalidate: error_exit path.\n");
+    op_release(new_op);
+    return 0;
+}
+
+/* should return 1 if dentry can still be trusted, else 0 */
+#ifdef PVFS2_LINUX_KERNEL_2_4
+int pvfs2_d_revalidate(
+    struct dentry *dentry,
+    int flags)
+{
+    return(pvfs2_d_revalidate_common(dentry));
 }
 
 #else
@@ -43,28 +127,15 @@ int pvfs2_d_revalidate(
     struct dentry *dentry,
     struct nameidata *nd)
 {
-    int ret = 0;
-    struct inode *inode = (dentry ? dentry->d_inode : NULL);
 
-    pvfs2_print("pvfs2_d_revalidate: called on dentry %p", dentry);
     if (nd && (nd->flags & LOOKUP_FOLLOW) &&
         (!nd->flags & LOOKUP_CREATE))
     {
         pvfs2_print("\npvfs2_d_revalidate: Trusting intent; "
                     "skipping getattr\n");
-        ret = 1;
+        return 1;
     }
-    else if (inode)
-    {
-        pvfs2_print(" (inode %Lu)\n",
-                    Lu(pvfs2_ino_to_handle(inode->i_ino)));
-        ret = pvfs2_internal_revalidate(inode);
-    }
-    else
-    {
-        pvfs2_print("\n");
-    }
-    return ret;
+    return(pvfs2_d_revalidate_common(dentry));
 }
 
 #endif /* PVFS2_LINUX_KERNEL_2_4 */

Index: devpvfs2-req.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/devpvfs2-req.c,v
diff -p -u -r1.45 -r1.45.6.1
--- devpvfs2-req.c	22 Nov 2004 18:14:05 -0000	1.45
+++ devpvfs2-req.c	25 Aug 2005 20:38:29 -0000	1.45.6.1
@@ -19,6 +19,7 @@ extern struct qhash_table *htable_ops_in
 extern struct file_system_type pvfs2_fs_type;
 extern struct semaphore devreq_semaphore;
 extern struct semaphore request_semaphore;
+extern int debug;
 
 /* defined in super.c */
 extern struct list_head pvfs2_superblocks;

Index: dir.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/dir.c,v
diff -p -u -r1.32 -r1.32.6.1
--- dir.c	11 Jan 2005 17:45:03 -0000	1.32
+++ dir.c	25 Aug 2005 20:38:29 -0000	1.32.6.1
@@ -16,6 +16,7 @@
 extern struct list_head pvfs2_request_list;
 extern spinlock_t pvfs2_request_list_lock;
 extern wait_queue_head_t pvfs2_request_list_waitq;
+extern int debug;
 
 /* shared file/dir operations defined in file.c */
 extern int pvfs2_file_open(
@@ -60,7 +61,7 @@ static int pvfs2_readdir(
                 "retry=%d, v=%Lu)\n", dentry->d_name.name, (int)pos,
                 (int)pvfs2_inode->readdir_token_adjustment,
                 (int)pvfs2_inode->num_readdir_retries,
-                pvfs2_inode->directory_version);
+                Lu(pvfs2_inode->directory_version));
 
     switch (pos)
     {

Index: downcall.h
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/downcall.h,v
diff -p -u -r1.23 -r1.23.6.1
--- downcall.h	11 Jan 2005 17:24:18 -0000	1.23
+++ downcall.h	25 Aug 2005 20:38:29 -0000	1.23.6.1
@@ -98,6 +98,30 @@ typedef struct
 {
 } pvfs2_fs_umount_response_t;
 
+/* the getxattr response is the attribute value */
+
+typedef struct {
+    size_t val_sz;
+    char val[PVFS_MAX_XATTR_VALUELEN];
+} pvfs2_getxattr_response_t;
+
+/* the setxattr response is a blank downcall */
+
+typedef struct {
+} pvfs2_setxattr_response_t;
+
+/* the listxattr response is an array of attribute names, values */
+
+typedef struct {
+    PVFS_keyval_pair keyvals[PVFS_MAX_XATTR_LISTLEN];
+} pvfs2_listxattr_response_t;
+
+/* the removexattr response is a blank downcall */
+
+typedef struct {
+} pvfs2_removexattr_response_t;
+
+
 /* the cancel response is a blank downcall */
 typedef struct
 {
@@ -129,6 +153,10 @@ typedef struct
 /* 	pvfs2_truncate_response_t truncate; */
         pvfs2_fs_mount_response_t fs_mount;
 /* 	pvfs2_fs_umount_response_t fs_umount; */
+        pvfs2_getxattr_response_t getxattr;
+/*      pvfs2_setxattr_response_t setxattr */
+/*        pvfs2_listxattr_response_t listxattr; */ /* NOT IMPLEMENTED YET */
+/*      pvfs2_removexattr_response_t removexattr; */
 /* 	pvfs2_cancel_response_t cancel; */
 /* 	pvfs2_fsync_response_t fsync; */
     } resp;

Index: file.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/file.c,v
diff -p -u -r1.89 -r1.89.6.1
--- file.c	11 Jan 2005 17:24:18 -0000	1.89
+++ file.c	25 Aug 2005 20:38:30 -0000	1.89.6.1
@@ -16,10 +16,15 @@
 extern struct list_head pvfs2_request_list;
 extern spinlock_t pvfs2_request_list_lock;
 extern wait_queue_head_t pvfs2_request_list_waitq;
+extern int debug;
 
 extern struct address_space_operations pvfs2_address_operations;
 extern struct backing_dev_info pvfs2_backing_dev_info;
 
+#ifdef PVFS2_LINUX_KERNEL_2_4
+static int pvfs2_precheck_file_write(struct file *file, struct inode *inode,
+    size_t *count, loff_t *ppos);
+#endif
 
 #define wake_up_device_for_return(op)             \
 do {                                              \
@@ -102,6 +107,10 @@ ssize_t pvfs2_inode_read(
     loff_t original_offset = *offset;
     int retries = PVFS2_OP_RETRY_COUNT;
     pvfs2_inode_t *pvfs2_inode = PVFS2_I(inode);
+    int dc_status;
+
+    if (copy_to_user && (!access_ok(VERIFY_WRITE, buf, count)))
+        return -EFAULT;
 
     while(total_count < count)
     {
@@ -134,13 +143,14 @@ ssize_t pvfs2_inode_read(
         new_op->upcall.req.io.count = each_count;
         new_op->upcall.req.io.offset = *offset;
 
+        dc_status = 0;  /* macro may jump to error_exit below */
         service_error_exit_op_with_timeout_retry(
             new_op, "pvfs2_inode_read", retries, error_exit,
             get_interruptible_flag(inode));
 
         if (new_op->downcall.status != 0)
         {
-            int dc_status = new_op->downcall.status;
+            dc_status = new_op->downcall.status;
 
           error_exit:
             /* this macro is defined in pvfs2-kernel.h */
@@ -186,8 +196,11 @@ ssize_t pvfs2_inode_read(
 
             if (ret)
             {
-                pvfs2_error("Failed to copy user buffer.  Please make "
-                            "sure that the pvfs2-client is running.\n");
+                pvfs2_print("Failed to copy user buffer.\n");
+                /* put error code in downcall so that handle_io_error()
+                 * preserves properly
+                 */
+                new_op->downcall.status = -PVFS_EFAULT;
                 goto error_exit;
             }
         }
@@ -256,16 +269,34 @@ static ssize_t pvfs2_file_write(
     struct inode *inode = file->f_dentry->d_inode;
     pvfs2_inode_t *pvfs2_inode = PVFS2_I(inode);
     size_t amt_complete = 0;
+    int dc_status;
 
     pvfs2_print("pvfs2_file_write: called on %s\n",
                 (file && file->f_dentry && file->f_dentry->d_name.name ?
                  (char *)file->f_dentry->d_name.name : "UNKNOWN"));
 
+    if (!access_ok(VERIFY_READ, buf, count))
+        return -EFAULT;
+
+    /* perform generic linux kernel tests for sanity of write arguments */
+    /* NOTE: this is particularly helpful in handling fsize rlimit properly */
+#ifdef PVFS2_LINUX_KERNEL_2_4
+    ret = pvfs2_precheck_file_write(file, inode, &count, offset);
+#else
+    ret = generic_write_checks(file, offset, &count, S_ISBLK(inode->i_mode));
+#endif
+    if (ret != 0 || count == 0)
+    {
+        pvfs2_print("pvfs2_file_write: failed generic argument checks.\n");
+        return(ret);
+    }
+
     while(total_count < count)
     {
         new_op = op_alloc();
         if (!new_op)
         {
+            *offset = original_offset;
             return -ENOMEM;
         }
 
@@ -294,24 +325,25 @@ static ssize_t pvfs2_file_write(
         new_op->upcall.req.io.offset = *offset;
 
         /* copy data from application */
-        if (pvfs_bufmap_copy_from_user(
-                buffer_index, current_buf, each_count))
+        ret = pvfs_bufmap_copy_from_user(
+            buffer_index, current_buf, each_count);
+        if(ret < 0)
         {
-            pvfs2_error("Failed to copy user buffer.  Please make sure "
-                        "that the pvfs2-client is running.\n");
+            pvfs2_print("Failed to copy user buffer.\n");
             op_release(new_op);
             pvfs_bufmap_put(buffer_index);
             *offset = original_offset;
-            return -EIO;
+            return ret;
         }
 
+        dc_status = 0;
         service_error_exit_op_with_timeout_retry(
             new_op, "pvfs2_file_write", retries, error_exit,
             get_interruptible_flag(inode));
 
         if (new_op->downcall.status != 0)
         {
-            int dc_status = new_op->downcall.status;
+            dc_status = new_op->downcall.status;
 
           error_exit:
             /* this macro is defined in pvfs2-kernel.h */
@@ -330,7 +362,7 @@ static ssize_t pvfs2_file_write(
             else
             {
                 pvfs2_error(
-                    "pvfs2_inode_write: error writing to handle %Lu, "
+                    "pvfs2_file_write: error writing to handle %Lu, "
                     "FILE: %s\n  -- downcall status is %d, returning %d "
                     "(error_exit=%d)\n",
                     Lu(pvfs2_ino_to_handle(inode->i_ino)),
@@ -338,6 +370,7 @@ static ssize_t pvfs2_file_write(
                      (char *)file->f_dentry->d_name.name : "UNKNOWN"),
                     dc_status, ret, error_exit);
             }
+            *offset = original_offset;
             return ret;
         }
 
@@ -372,6 +405,637 @@ static ssize_t pvfs2_file_write(
     return total_count;
 }
 
+/*
+ * The reason we need to do this is to be able to support readv() and writev()
+ * of larger than PVFS_DEFAULT_DESC_SIZE (4 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
+ * and 0 in case of success.
+ * 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 max_new_nr_segs value is computed by the caller and returned.
+ * (It will be (count of all iov_len/ block_size) + 1).
+ */
+static int split_iovecs(unsigned long max_new_nr_segs,  /* IN */
+        unsigned long nr_segs,              /* IN */
+        const struct iovec *original_iovec, /* IN */
+        unsigned long *new_nr_segs, struct iovec **new_vec,  /* OUT */
+        unsigned int *seg_count, unsigned int **seg_array)   /* OUT */
+{
+    int seg, count = 0, begin_seg, tmpnew_nr_segs = 0;
+    struct iovec *new_iovec = NULL, *orig_iovec;
+    unsigned int *sizes = NULL, sizes_count = 0;
+
+    if (nr_segs <= 0 || original_iovec == NULL 
+            || new_nr_segs == NULL || new_vec == NULL
+            || seg_count == NULL || seg_array == NULL || max_new_nr_segs <= 0)
+    {
+        pvfs2_error("Invalid parameters to split_iovecs\n");
+        return -EINVAL;
+    }
+    *new_nr_segs = 0;
+    *new_vec = NULL;
+    *seg_count = 0;
+    *seg_array = NULL;
+    /* copy the passed in iovec descriptor to a temp structure */
+    orig_iovec = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec),
+            PVFS2_BUFMAP_GFP_FLAGS);
+    if (orig_iovec == NULL)
+    {
+        pvfs2_error("split_iovecs: Could not allocate memory for %lu bytes!\n", 
+                (unsigned long)(nr_segs * sizeof(struct iovec)));
+        return -ENOMEM;
+    }
+    new_iovec = (struct iovec *) kmalloc(max_new_nr_segs * sizeof(struct iovec), 
+            PVFS2_BUFMAP_GFP_FLAGS);
+    if (new_iovec == NULL)
+    {
+        kfree(orig_iovec);
+        pvfs2_error("split_iovecs: Could not allocate memory for %lu bytes!\n", 
+                (unsigned long)(max_new_nr_segs * sizeof(struct iovec)));
+        return -ENOMEM;
+    }
+    sizes = (int *) kmalloc(max_new_nr_segs * sizeof(int), 
+            PVFS2_BUFMAP_GFP_FLAGS);
+    if (sizes == NULL)
+    {
+        kfree(new_iovec);
+        kfree(orig_iovec);
+        pvfs2_error("split_iovecs: Could not allocate memory for %lu bytes!\n", 
+                (unsigned long)(max_new_nr_segs * sizeof(int)));
+        return -ENOMEM;
+    }
+    /* copy the passed in iovec to a temp structure */
+    memcpy(orig_iovec, original_iovec, nr_segs * sizeof(struct iovec));
+    memset(new_iovec, 0, max_new_nr_segs * sizeof(struct iovec));
+    memset(sizes, 0, max_new_nr_segs * sizeof(int));
+    begin_seg = 0;
+repeat:
+    for (seg = begin_seg; seg < nr_segs; seg++)
+    {
+        if (count + orig_iovec[seg].iov_len <= pvfs_bufmap_size_query())
+        {
+            count += orig_iovec[seg].iov_len;
+            if (tmpnew_nr_segs >= max_new_nr_segs)
+            {
+                kfree(sizes);
+                kfree(orig_iovec);
+                kfree(new_iovec);
+                pvfs2_error("split_iovecs: exceeded the index limit (%d)\n", 
+                        tmpnew_nr_segs);
+                return -EINVAL;
+            }
+            memcpy(&new_iovec[tmpnew_nr_segs], &orig_iovec[seg], 
+                    sizeof(struct iovec));
+            tmpnew_nr_segs++;
+            sizes[sizes_count]++;
+        }
+        else
+        {
+            if (tmpnew_nr_segs >= max_new_nr_segs)
+            {
+                kfree(sizes);
+                kfree(orig_iovec);
+                kfree(new_iovec);
+                pvfs2_error("split_iovecs: exceeded the index limit (%d)\n", 
+                        tmpnew_nr_segs);
+                return -EINVAL;
+            }
+            new_iovec[tmpnew_nr_segs].iov_base = orig_iovec[seg].iov_base;
+            new_iovec[tmpnew_nr_segs].iov_len = 
+                (pvfs_bufmap_size_query() - count);
+            tmpnew_nr_segs++;
+            if (sizes_count >= max_new_nr_segs)
+            {
+                kfree(sizes);
+                kfree(orig_iovec);
+                kfree(new_iovec);
+                pvfs2_error("split_iovecs: exceeded the size limit (%d)\n", 
+                        sizes_count);
+                return -EINVAL;
+            }
+            sizes[sizes_count]++;
+            sizes_count++;
+            begin_seg = seg;
+            orig_iovec[seg].iov_base += (pvfs_bufmap_size_query() - count);
+            orig_iovec[seg].iov_len  -= (pvfs_bufmap_size_query() - count);
+            count = 0;
+            break;
+        }
+    }
+    if (seg != nr_segs) {
+        goto repeat;
+    }
+    else
+    {
+        sizes_count++;
+    }
+    *new_nr_segs = tmpnew_nr_segs;
+    /* new_iovec is freed by the caller */
+    *new_vec = new_iovec;
+    *seg_count = sizes_count;
+    /* seg_array is also freed by the caller */
+    *seg_array = sizes;
+    kfree(orig_iovec);
+    return 0;
+}
+
+
+/** Reads data to several contiguous user buffers (an iovec) from a file at a
+ * specified offset.
+ */
+static ssize_t pvfs2_file_readv(
+    struct file *file,
+    const struct iovec *iov,
+    unsigned long nr_segs,
+    loff_t *offset)
+{
+    int ret = -1, retries = PVFS2_OP_RETRY_COUNT;
+    pvfs2_kernel_op_t *new_op = NULL;
+    struct iovec *iovecptr = NULL, *ptr = NULL;
+    loff_t original_offset = *offset;
+    int buffer_index = -1, error_exit = 0;
+    struct inode *inode = file->f_dentry->d_inode;
+    pvfs2_inode_t *pvfs2_inode = PVFS2_I(inode);
+    size_t amt_complete = 0;
+    size_t total_count = 0, count = 0, each_count = 0;
+    unsigned int seg, to_free = 0;
+    unsigned long new_nr_segs = 0, max_new_nr_segs = 0;
+    unsigned int  seg_count, *seg_array = NULL;
+
+
+    /* Calculate the total length to read by adding up the length of each io
+     * segment */
+    for (seg = 0; seg < nr_segs; seg++)
+    {
+	const struct iovec *iv = &iov[seg];
+	count += iv->iov_len;
+	if (unlikely((ssize_t)(count|iv->iov_len) < 0))
+	    return -EINVAL;
+        if (total_count + iv->iov_len < pvfs_bufmap_size_query())
+        {
+            total_count += iv->iov_len;
+            max_new_nr_segs++;
+        }
+        else {
+            total_count = (total_count + iv->iov_len - 
+                    pvfs_bufmap_size_query());
+            max_new_nr_segs+=2;
+        }
+    }
+    total_count = 0;
+    /*
+     * if the total size of data transfer requested is greater than
+     * the kernel-set blocksize of PVFS2, then we split the iovecs
+     * such that no iovec description straddles a block size limit
+     */
+    if (count > pvfs_bufmap_size_query())
+    {
+        /*
+         * Split up the given iovec description such that
+         * no iovec descriptor straddles over the block-size limitation.
+         * This makes us our job easier to stage the I/O.
+         * In addition, this function will also compute an array with seg_count
+         * entries that will store the number of segments that straddle the
+         * block-size boundaries.
+         */
+        if ((ret = split_iovecs(max_new_nr_segs, nr_segs, iov, /* IN */
+                        &new_nr_segs, &iovecptr, /* OUT */
+                        &seg_count, &seg_array)  /* OUT */ ) < 0)
+        {
+            pvfs2_error("Failed to split iovecs to satisfy larger "
+                    " than blocksize readv request %d\n", ret);
+            return ret;
+        }
+        pvfs2_print("pvfs_file_readv: Splitting iovecs from %lu to %lu [max_new %lu]\n", 
+                nr_segs, new_nr_segs, max_new_nr_segs);
+        /* We must free seg_array and iovecptr */
+        to_free = 1;
+    }
+    else {
+        new_nr_segs = nr_segs;
+        /* use the given iovec description */
+        iovecptr = (struct iovec *) iov;
+        /* There is only 1 element in the seg_array */
+        seg_count = 1;
+        /* and its value is the number of segments passed in */
+        seg_array = (unsigned int *) &nr_segs;
+        /* We dont have to free up anything */
+        to_free = 0;
+    }
+    ptr = iovecptr;
+    pvfs2_print("pvfs2_file_readv reading %d@%Lu\n", count, *offset);
+    pvfs2_print("pvfs2_file_readv: new_nr_segs: %lu, seg_count: %u\n", 
+            new_nr_segs, seg_count);
+    for (seg = 0; seg < new_nr_segs; seg++)
+    {
+        pvfs2_print("pvfs2_file_readv: %d) %p to %p [%d bytes]\n", 
+                seg + 1, iovecptr[seg].iov_base, 
+                iovecptr[seg].iov_base + iovecptr[seg].iov_len, 
+                iovecptr[seg].iov_len);
+    }
+    for (seg = 0; seg < seg_count; seg++)
+    {
+        pvfs2_print("pvfs2_file_readv: %d) %u\n", seg + 1, seg_array[seg]);
+    }
+    seg = 0;
+    while (total_count < count)
+    {
+        new_op = op_alloc();
+        if (!new_op)
+        {
+            *offset = original_offset;
+            if (to_free) {
+                kfree(iovecptr);
+                kfree(seg_array);
+            }
+            return -ENOMEM;
+        }
+
+        new_op->upcall.type = PVFS2_VFS_OP_FILE_IO;
+        /* disable read-ahead */
+        new_op->upcall.req.io.readahead_size = 0;
+        new_op->upcall.req.io.io_type = PVFS_IO_READ;
+        new_op->upcall.req.io.refn = pvfs2_inode->refn;
+
+        ret = pvfs_bufmap_get(&buffer_index);
+        if (ret < 0)
+        {
+            pvfs2_error("pvfs2_file_readv: pvfs_bufmap_get() "
+                        "failure (%d)\n", ret);
+            op_release(new_op);
+            *offset = original_offset;
+            if (to_free) {
+                kfree(iovecptr);
+                kfree(seg_array);
+            }
+            return ret;
+        }
+
+        /* how much to transfer in this loop iteration */
+        each_count = (((count - total_count) > pvfs_bufmap_size_query()) ?
+                      pvfs_bufmap_size_query() : (count - total_count));
+
+        new_op->upcall.req.io.buf_index = buffer_index;
+        new_op->upcall.req.io.count = each_count;
+        new_op->upcall.req.io.offset = *offset;
+
+
+        service_error_exit_op_with_timeout_retry(
+            new_op, "pvfs2_file_readv", retries, error_exit,
+            get_interruptible_flag(inode));
+
+        if (new_op->downcall.status != 0)
+        {
+            int dc_status = new_op->downcall.status;
+
+            error_exit:
+              /* this macro is defined in pvfs2-kernel.h */
+              handle_io_error();
+
+              /*
+                don't write an error to syslog on signaled operation
+                termination unless we've got debugging turned on, as
+                this can happen regularly (i.e. ctrl-c)
+              */
+              if ((error_exit == 1) && (ret == -EINTR))
+              {
+                  pvfs2_print("pvfs2_file_readv: returning error %d "
+                              "(error_exit=%d)\n", ret, error_exit);
+              }
+              else
+              {
+                  pvfs2_error(
+                        "pvfs2_file_readv: error writing to handle %Lu, "
+                        "FILE: %s\n  -- downcall status is %d, returning %d "
+                        "(error_exit=%d)\n",
+                        Lu(pvfs2_ino_to_handle(inode->i_ino)),
+                        (file && file->f_dentry && file->f_dentry->d_name.name ?
+                         (char *)file->f_dentry->d_name.name : "UNKNOWN"),
+                        dc_status, ret, error_exit);
+              }
+              *offset = original_offset;
+              if (to_free) {
+                  kfree(seg_array);
+                  kfree(iovecptr);
+              }
+              return ret;
+        }
+        pvfs2_print("pvfs2_file_readv nr_segs %u, offset: %Lu each_count:%d\n",
+                seg_array[seg], *offset, each_count);
+        /*
+         * copy data to application by pushing it out to the iovec.
+         * Number of segments to copy so that we don't
+         * overflow the block-size is set in seg_array[], and
+         * ptr points to the appropriate beginning of the
+         * iovec from where data needs to be copied to, and
+         * new_op->downcall.resp.io.amt_complete indicates
+         * the size in bytes that needs to be pushed out
+         */
+        if (new_op->downcall.resp.io.amt_complete)
+        {
+            ret = pvfs_bufmap_copy_to_user_iovec(
+                    buffer_index, ptr, seg_array[seg],
+                    new_op->downcall.resp.io.amt_complete);
+            if (ret < 0)
+            {
+                pvfs2_error("Failed to copy user buffer.  Please make sure "
+                            "that the pvfs2-client is running.\n");
+                /* put error codes in downcall so that handle_io_error()
+                 * preserves it properly */
+                new_op->downcall.status = -PVFS_EFAULT;
+                goto error_exit;
+            }
+        }
+        /* advance the iovec pointer */
+        ptr += seg_array[seg];
+        seg++;
+        *offset += new_op->downcall.resp.io.amt_complete;
+        total_count += new_op->downcall.resp.io.amt_complete;
+        amt_complete = new_op->downcall.resp.io.amt_complete;
+
+        /*
+          tell the device file owner waiting on I/O that this read has
+          completed and it can return now.  in this exact case, on
+          wakeup the device will free the op, so we *cannot* touch it
+          after this.
+        */
+        wake_up_device_for_return(new_op);
+        pvfs_bufmap_put(buffer_index);
+
+        /* if we got a short write, fall out and return what we got so
+         * far 
+         */
+        if (amt_complete < each_count)
+        {
+            break;
+        }
+    }
+
+    if (to_free) {
+        kfree(iovecptr);
+        kfree(seg_array);
+    }
+    return total_count;
+}
+
+
+/** Write data from a several contiguous user buffers (an iovec) into a file at
+ * a specified offset.
+ */
+static ssize_t pvfs2_file_writev(
+    struct file *file,
+    const struct iovec *iov,
+    unsigned long nr_segs,
+    loff_t *offset)
+{
+    int ret = -1, retries = PVFS2_OP_RETRY_COUNT;
+    pvfs2_kernel_op_t *new_op = NULL;
+    struct iovec *iovecptr = NULL, *ptr = NULL;
+    loff_t original_offset = *offset;
+    int buffer_index = -1, error_exit = 0;
+    struct inode *inode = file->f_dentry->d_inode;
+    pvfs2_inode_t *pvfs2_inode = PVFS2_I(inode);
+    size_t amt_complete = 0;
+    size_t total_count = 0, count = 0, each_count = 0;
+    unsigned int seg, to_free = 0;
+    unsigned long new_nr_segs = 0, max_new_nr_segs = 0;
+    unsigned int  seg_count, *seg_array = NULL;
+
+
+    /* Calculate the total length to write by adding up the length of each io
+     * segment */
+    for (seg = 0; seg < nr_segs; seg++)
+    {
+	const struct iovec *iv = &iov[seg];
+	count += iv->iov_len;
+	if (unlikely((ssize_t)(count|iv->iov_len) < 0))
+	    return -EINVAL;
+        if (total_count + iv->iov_len < pvfs_bufmap_size_query())
+        {
+            total_count += iv->iov_len;
+            max_new_nr_segs++;
+        }
+        else {
+            total_count = (total_count + iv->iov_len - pvfs_bufmap_size_query());
+            max_new_nr_segs+=2;
+        }
+
+    }
+    /* perform generic linux kernel tests for sanity of write arguments */
+    /* NOTE: this is particularly helpful in handling fsize rlimit properly */
+#ifdef PVFS2_LINUX_KERNEL_2_4
+    ret = pvfs2_precheck_file_write(file, inode, &count, offset);
+#else
+    ret = generic_write_checks(file, offset, &count, S_ISBLK(inode->i_mode));
+#endif
+    if (ret != 0 || count == 0)
+    {
+        pvfs2_print("pvfs2_file_writev: failed generic argument checks.\n");
+        return(ret);
+    }
+
+    total_count = 0;
+    /*
+     * if the total size of data transfer requested is greater than
+     * the kernel-set blocksize of PVFS2, then we split the iovecs
+     * such that no iovec description straddles this block size
+     * limitation.
+     */
+    if (count > pvfs_bufmap_size_query())
+    {
+        /*
+         * Split up the given iovec description such that
+         * no iovec descriptor straddles over the block-size limitation.
+         * This makes us our job easier to stage the I/O.
+         * In addition, this function will also compute an array with seg_count
+         * entries that will store the number of segments that straddle the
+         * block-size boundaries.
+         */
+        if ((ret = split_iovecs(max_new_nr_segs, nr_segs, iov, /* IN */
+                        &new_nr_segs, &iovecptr, /* OUT */
+                        &seg_count, &seg_array) /* OUT */ ) < 0)
+        {
+            pvfs2_error("Failed to split iovecs to satisfy larger than blocksize writev request %d\n", ret);
+            return ret;
+        }
+        pvfs2_print("pvfs_file_writev: Splitting iovecs from %lu to %lu [max_new %lu]\n", 
+                nr_segs, new_nr_segs, max_new_nr_segs);
+        /* We must free seg_array and iovecptr */
+        to_free = 1;
+    }
+    else {
+        /* Number of segments dont change! */
+        new_nr_segs = nr_segs;
+         /* use the given iovec description */
+        iovecptr = (struct iovec *) iov;
+        /* There is only 1 element in the seg_array */
+        seg_count = 1;
+        /* and its value is the number of segments passed in */
+        seg_array = (unsigned int *) &nr_segs;
+        /* We dont have to free up anything */
+        to_free = 0;
+    }
+    ptr = iovecptr;
+    pvfs2_print("pvfs2_file_writev writing %d@%Lu\n", count, *offset);
+    pvfs2_print("pvfs2_file_writev: new_nr_segs: %lu, seg_count: %u\n", 
+            new_nr_segs, seg_count);
+    for (seg = 0; seg < new_nr_segs; seg++)
+    {
+        pvfs2_print("pvfs2_file_writev: %d) %p to %p [%d bytes]\n", 
+                seg + 1, iovecptr[seg].iov_base, 
+                iovecptr[seg].iov_base + iovecptr[seg].iov_len, 
+                iovecptr[seg].iov_len);
+    }
+    for (seg = 0; seg < seg_count; seg++)
+    {
+        pvfs2_print("pvfs2_file_writev: %d) %u\n", seg + 1, seg_array[seg]);
+    }
+    seg = 0;
+    while (total_count < count)
+    {
+        new_op = op_alloc();
+        if (!new_op)
+        {
+            *offset = original_offset;
+            if (to_free) {
+                kfree(iovecptr);
+                kfree(seg_array);
+            }
+            return -ENOMEM;
+        }
+
+        new_op->upcall.type = PVFS2_VFS_OP_FILE_IO;
+        new_op->upcall.req.io.io_type = PVFS_IO_WRITE;
+        new_op->upcall.req.io.refn = pvfs2_inode->refn;
+
+        ret = pvfs_bufmap_get(&buffer_index);
+        if (ret < 0)
+        {
+            pvfs2_error("pvfs2_file_writev: pvfs_bufmap_get() "
+                        "failure (%d)\n", ret);
+            op_release(new_op);
+            *offset = original_offset;
+            if (to_free) {
+                kfree(iovecptr);
+                kfree(seg_array);
+            }
+            return ret;
+        }
+
+        /* how much to transfer in this loop iteration */
+        each_count = (((count - total_count) > pvfs_bufmap_size_query()) ?
+                      pvfs_bufmap_size_query() : (count - total_count));
+
+        new_op->upcall.req.io.buf_index = buffer_index;
+        new_op->upcall.req.io.count = each_count;
+        new_op->upcall.req.io.offset = *offset;
+        pvfs2_print("pvfs2_file_writev nr_segs %u, offset: %Lu each_count: %d\n",
+                seg_array[seg], *offset, each_count);
+
+        /* 
+         * copy data from application by pulling it out  of the iovec.
+         * Number of segments to copy so that we don't overflow the block-size
+         * is set in seg_array[], and ptr points to the appropriate
+         * beginning of the iovec from where data needs to be copied out,
+         * and each_count indicates the size in bytes that needs to be pulled
+         * out.  */
+        ret = pvfs_bufmap_copy_iovec_from_user(
+                buffer_index, ptr, seg_array[seg], each_count);
+        if (ret < 0)
+        {
+            pvfs2_error("Failed to copy user buffer.  Please make sure "
+                        "that the pvfs2-client is running. %d\n", ret);
+            op_release(new_op);
+            pvfs_bufmap_put(buffer_index);
+            *offset = original_offset;
+            if (to_free) {
+                kfree(seg_array);
+                kfree(iovecptr);
+            }
+            return ret;
+        }
+
+        service_error_exit_op_with_timeout_retry(
+            new_op, "pvfs2_file_writev", retries, error_exit,
+            get_interruptible_flag(inode));
+
+        if (new_op->downcall.status != 0)
+        {
+            int dc_status = new_op->downcall.status;
+
+            error_exit:
+              /* this macro is defined in pvfs2-kernel.h */
+              handle_io_error();
+
+              /*
+                don't write an error to syslog on signaled operation
+                termination unless we've got debugging turned on, as
+                this can happen regularly (i.e. ctrl-c)
+              */
+              if ((error_exit == 1) && (ret == -EINTR))
+              {
+                  pvfs2_print("pvfs2_file_writev: returning error %d "
+                              "(error_exit=%d)\n", ret, error_exit);
+              }
+              else
+              {
+                  pvfs2_error(
+                        "pvfs2_file_writev: error writing to handle %Lu, "
+                        "FILE: %s\n  -- downcall status is %d, returning %d "
+                        "(error_exit=%d)\n",
+                        Lu(pvfs2_ino_to_handle(inode->i_ino)),
+                        (file && file->f_dentry && file->f_dentry->d_name.name ?
+                         (char *)file->f_dentry->d_name.name : "UNKNOWN"),
+                        dc_status, ret, error_exit);
+              }
+              *offset = original_offset;
+              if (to_free) {
+                  kfree(seg_array);
+                  kfree(iovecptr);
+              }
+              return ret;
+        }
+        /* advance the iovec pointer */
+        ptr += seg_array[seg];
+        seg++;
+        *offset += new_op->downcall.resp.io.amt_complete;
+        total_count += new_op->downcall.resp.io.amt_complete;
+        amt_complete = new_op->downcall.resp.io.amt_complete;
+
+        /*
+          tell the device file owner waiting on I/O that this read has
+          completed and it can return now.  in this exact case, on
+          wakeup the device will free the op, so we *cannot* touch it
+          after this.
+        */
+        wake_up_device_for_return(new_op);
+        pvfs_bufmap_put(buffer_index);
+
+        /* if we got a short write, fall out and return what we got so
+         * far TODO: define semantics here- kind of depends on pvfs2
+         * semantics that don't really exist yet
+         */
+        if (amt_complete < each_count)
+        {
+            break;
+        }
+    }
+
+    if (to_free) {
+        kfree(iovecptr);
+        kfree(seg_array);
+    }
+    if (total_count)
+    {
+        update_atime(inode);
+    }
+    return total_count;
+}
+
 /** Perform a miscellaneous operation on a file.
  */
 int pvfs2_ioctl(
@@ -468,9 +1132,6 @@ int pvfs2_fsync(
     pvfs2_inode_t *pvfs2_inode = PVFS2_I(file->f_dentry->d_inode);
     pvfs2_kernel_op_t *new_op = NULL;
 
-    pvfs2_print("pvfs2_fsync called on %s (must block? %s\n",
-                pvfs2_inode->refn.handle, pvfs2_inode->refn.fs_id);
-
     new_op = op_alloc();
     if (!new_op)
     {
@@ -534,6 +1195,8 @@ struct file_operations pvfs2_file_operat
     llseek : pvfs2_file_llseek,
     read : pvfs2_file_read,
     write : pvfs2_file_write,
+    readv : pvfs2_file_readv,
+    writev : pvfs2_file_writev,
     ioctl : pvfs2_ioctl,
     mmap : pvfs2_file_mmap,
     open : pvfs2_file_open,
@@ -543,6 +1206,8 @@ struct file_operations pvfs2_file_operat
     .llseek = pvfs2_file_llseek,
     .read = pvfs2_file_read,
     .write = pvfs2_file_write,
+    .readv = pvfs2_file_readv,
+    .writev = pvfs2_file_writev,
     .ioctl = pvfs2_ioctl,
     .mmap = pvfs2_file_mmap,
     .open = pvfs2_file_open,
@@ -550,6 +1215,113 @@ struct file_operations pvfs2_file_operat
     .fsync = pvfs2_fsync
 #endif
 };
+
+#ifdef PVFS2_LINUX_KERNEL_2_4
+/*
+ * pvfs2_precheck_file_write():
+ * Check the conditions on a file descriptor prior to beginning a write
+ * on it.  Contains the common precheck code for both buffered and direct
+ * IO.
+ *
+ * NOTE: this function is a modified version of precheck_file_write() from
+ * 2.4.x.  precheck_file_write() is not exported so we are forced to
+ * duplicate it here.
+ */
+static int pvfs2_precheck_file_write(struct file *file, struct inode *inode,
+    size_t *count, loff_t *ppos)
+{
+    ssize_t       err;
+    unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+    loff_t        pos = *ppos;
+    
+    err = -EINVAL;
+    if (pos < 0)
+        goto out;
+
+    err = file->f_error;
+    if (err) {
+        file->f_error = 0;
+        goto out;
+    }
+
+    /* FIXME: this is for backwards compatibility with 2.4 */
+    if (!S_ISBLK(inode->i_mode) && (file->f_flags & O_APPEND))
+        *ppos = pos = inode->i_size;
+
+    /*
+     * Check whether we've reached the file size limit.
+     */
+    err = -EFBIG;
+    
+    if (!S_ISBLK(inode->i_mode) && limit != RLIM_INFINITY) {
+        if (pos >= limit) {
+            send_sig(SIGXFSZ, current, 0);
+            goto out;
+        }
+        if (pos > 0xFFFFFFFFULL || *count > limit - (u32)pos) {
+            /* send_sig(SIGXFSZ, current, 0); */
+            *count = limit - (u32)pos;
+        }
+    }
+
+    /*
+     *    LFS rule 
+     */
+    if ( pos + *count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) {
+        if (pos >= MAX_NON_LFS) {
+            send_sig(SIGXFSZ, current, 0);
+            goto out;
+        }
+        if (*count > MAX_NON_LFS - (u32)pos) {
+            /* send_sig(SIGXFSZ, current, 0); */
+            *count = MAX_NON_LFS - (u32)pos;
+        }
+    }
+
+    /*
+     *    Are we about to exceed the fs block limit ?
+     *
+     *    If we have written data it becomes a short write
+     *    If we have exceeded without writing data we send
+     *    a signal and give them an EFBIG.
+     *
+     *    Linus frestrict idea will clean these up nicely..
+     */
+     
+    if (!S_ISBLK(inode->i_mode)) {
+        if (pos >= inode->i_sb->s_maxbytes)
+        {
+            if (*count || pos > inode->i_sb->s_maxbytes) {
+                send_sig(SIGXFSZ, current, 0);
+                err = -EFBIG;
+                goto out;
+            }
+            /* zero-length writes at ->s_maxbytes are OK */
+        }
+
+        if (pos + *count > inode->i_sb->s_maxbytes)
+            *count = inode->i_sb->s_maxbytes - pos;
+    } else {
+        if (is_read_only(inode->i_rdev)) {
+            err = -EPERM;
+            goto out;
+        }
+        if (pos >= inode->i_size) {
+            if (*count || pos > inode->i_size) {
+                err = -ENOSPC;
+                goto out;
+            }
+        }
+
+        if (pos + *count > inode->i_size)
+            *count = inode->i_size - pos;
+    }
+
+    err = 0;
+out:
+    return err;
+}
+#endif
 
 /*
  * Local variables:

Index: inode.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/inode.c,v
diff -p -u -r1.53 -r1.53.4.1
--- inode.c	23 Mar 2005 21:57:14 -0000	1.53
+++ inode.c	25 Aug 2005 20:38:30 -0000	1.53.4.1
@@ -26,6 +26,7 @@ extern struct file_operations pvfs2_file
 extern struct inode_operations pvfs2_symlink_inode_operations;
 extern struct inode_operations pvfs2_dir_inode_operations;
 extern struct file_operations pvfs2_dir_operations;
+extern int debug;
 
 
 /** Read page-sized blocks from file.  This code is only used in the mmap
@@ -147,7 +148,7 @@ static int pvfs2_get_blocks(
 
         if (bytes_read < 0)
         {
-            pvfs2_print("pvfs_get_blocks: failed to read page block %d\n",
+            pvfs2_print("pvfs2_get_blocks: failed to read page block %d\n",
                         (int)page->index);
             pvfs2_inode->last_failed_block_index_read = page->index;
         }
@@ -258,9 +259,14 @@ static int pvfs2_releasepage(struct page
 struct backing_dev_info pvfs2_backing_dev_info =
 {
     .ra_pages = 1024,
+#ifdef HAVE_BDI_MEMORY_BACKED
+    /* old interface, up through 2.6.11 */
     .memory_backed = 1 /* does not contribute to dirty memory */
+#else
+    .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
+#endif
 };
-#endif /* PVFS2_LINUX_KERNEL_2_4 */
+#endif /* !PVFS2_LINUX_KERNEL_2_4 */
 
 /** PVFS2 implementation of address space operations */
 struct address_space_operations pvfs2_address_operations =
@@ -360,11 +366,21 @@ struct inode_operations pvfs2_file_inode
 #ifdef PVFS2_LINUX_KERNEL_2_4
     truncate : pvfs2_truncate,
     setattr : pvfs2_setattr,
-    revalidate : pvfs2_revalidate
+    revalidate : pvfs2_revalidate,
+#ifdef HAVE_XATTR
+    setxattr : pvfs2_setxattr, 
+    getxattr : pvfs2_getxattr,
+/*    listxattr : pvfs2_listxattr, */
+    removexattr: pvfs2_removexattr, 
+#endif
 #else
     .truncate = pvfs2_truncate,
     .setattr = pvfs2_setattr,
-    .getattr = pvfs2_getattr
+    .getattr = pvfs2_getattr,
+    .setxattr = pvfs2_setxattr,
+    .getxattr = pvfs2_getxattr,
+/*    .listxattr = pvfs2_listxattr,*/
+    .removexattr = pvfs2_removexattr,
 #endif
 };
 

Index: namei.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/namei.c,v
diff -p -u -r1.60 -r1.60.6.1
--- namei.c	13 Jan 2005 18:42:27 -0000	1.60
+++ namei.c	25 Aug 2005 20:38:30 -0000	1.60.6.1
@@ -15,6 +15,7 @@
 extern struct list_head pvfs2_request_list;
 extern spinlock_t pvfs2_request_list_lock;
 extern wait_queue_head_t pvfs2_request_list_waitq;
+extern int debug;
 
 extern struct dentry_operations pvfs2_dentry_operations;
 
@@ -140,7 +141,7 @@ struct dentry *pvfs2_lookup(
 
     pvfs2_print("pvfs2_lookup: doing lookup on %s\n  under %Lu,%d "
                 "(follow=%s)\n", new_op->upcall.req.lookup.d_name,
-                new_op->upcall.req.lookup.parent_refn.handle,
+                Lu(new_op->upcall.req.lookup.parent_refn.handle),
                 new_op->upcall.req.lookup.parent_refn.fs_id,
                 ((new_op->upcall.req.lookup.sym_follow ==
                   PVFS2_LOOKUP_LINK_FOLLOW) ? "yes" : "no"));
@@ -152,7 +153,7 @@ struct dentry *pvfs2_lookup(
     ret = pvfs2_kernel_error_code_convert(new_op->downcall.status);
 
     pvfs2_print("Lookup Got %Lu, fsid %d (ret=%d)\n",
-                new_op->downcall.resp.lookup.refn.handle,
+                Lu(new_op->downcall.resp.lookup.refn.handle),
                 new_op->downcall.resp.lookup.refn.fs_id, ret);
 
     /* lookup inode matching name (or add if not there) */
@@ -236,6 +237,39 @@ static int pvfs2_unlink(
     return ret;
 }
 
+/* pvfs2_link() is only implemented here to make sure that we return a
+ * reasonable error code (the kernel will return a misleading EPERM
+ * otherwise).  PVFS2 does not support hard links.
+ */
+static int pvfs2_link(
+    struct dentry * old_dentry, 
+    struct inode * dir,
+    struct dentry *dentry)
+{
+    return(-EOPNOTSUPP);
+}
+
+/* pvfs2_mknod() is only implemented here to make sure that we return a
+ * reasonable error code (the kernel will return a misleading EPERM
+ * otherwise).  PVFS2 does not support special files such as fifos or devices.
+ */
+#ifdef PVFS2_LINUX_KERNEL_2_4
+static int pvfs2_mknod(
+    struct inode *dir,
+    struct dentry *dentry,
+    int mode,
+    int rdev)
+#else
+static int pvfs2_mknod(
+    struct inode *dir,
+    struct dentry *dentry,
+    int mode,
+    dev_t rdev)
+#endif
+{
+    return(-EOPNOTSUPP);
+}
+
 static int pvfs2_symlink(
     struct inode *dir,
     struct dentry *dentry,
@@ -270,7 +304,12 @@ static int pvfs2_mkdir(
 
     if (inode)
     {
+#if 0
+        /* NOTE: we have no good way to keep nlink consistent for directories
+         * across clients; keep constant at 1  -Phil
+         */
 	dir->i_nlink++;
+#endif
         pvfs2_update_inode_time(dir);
 	ret = 0;
     }
@@ -287,8 +326,13 @@ static int pvfs2_rmdir(
     ret = pvfs2_unlink(dir, dentry);
     if (ret == 0)
     {
-        inode->i_nlink--;
+        inode->i_nlink--; 
+#if 0
+        /* NOTE: we have no good way to keep nlink consistent for directories
+         * across clients; keep constant at 1  -Phil
+         */
 	dir->i_nlink--;
+#endif
         pvfs2_update_inode_time(dir);
     }
     return ret;
@@ -312,6 +356,10 @@ static int pvfs2_rename(
                 atomic_read(&new_dentry->d_count));
 
     are_directories = S_ISDIR(old_dentry->d_inode->i_mode);
+#if 0
+    /* NOTE: we have no good way to keep nlink consistent for directories
+     * across clients; keep constant at 1  -Phil
+     */
     if (are_directories && (new_dir->i_nlink >= PVFS2_LINK_MAX))
     {
         pvfs2_error("pvfs2_rename: directory %s surpassed "
@@ -319,6 +367,7 @@ static int pvfs2_rename(
                     new_dentry->d_name.name);
         return -EMLINK;
     }
+#endif
 
     new_op = op_alloc();
     if (!new_op)
@@ -378,16 +427,26 @@ static int pvfs2_rename(
     if (new_dentry->d_inode)
     {
         new_dentry->d_inode->i_ctime = CURRENT_TIME;
+#if 0
+        /* NOTE: we have no good way to keep nlink consistent for directories
+         * across clients; keep constant at 1  -Phil
+         */
         if (are_directories)
         {
             new_dentry->d_inode->i_nlink--;
         }
+#endif
     }
+#if 0
+    /* NOTE: we have no good way to keep nlink consistent for directories
+     * across clients; keep constant at 1  -Phil
+     */
     else if (are_directories)
     {
         new_dir->i_nlink++;
         old_dir->i_nlink--;
     }
+#endif
 
   error_exit:
     translate_error_if_wait_failed(ret, 0, 0);
@@ -408,23 +467,37 @@ struct inode_operations pvfs2_dir_inode_
 #ifdef PVFS2_LINUX_KERNEL_2_4
     create : pvfs2_create,
     lookup : pvfs2_lookup,
+    link : pvfs2_link,
     unlink : pvfs2_unlink,
     symlink : pvfs2_symlink,
     mkdir : pvfs2_mkdir,
     rmdir : pvfs2_rmdir,
+    mknod : pvfs2_mknod,
     rename : pvfs2_rename,
     setattr : pvfs2_setattr,
-    revalidate : pvfs2_revalidate
+    revalidate : pvfs2_revalidate,
+#ifdef HAVE_XATTR
+    getxattr: pvfs2_getxattr,
+    setxattr: pvfs2_setxattr,
+/*    listxattr: pvfs2_listxattr,*/
+    removexattr: pvfs2_removexattr,
+#endif
 #else
     .create = pvfs2_create,
     .lookup = pvfs2_lookup,
+    .link = pvfs2_link,
     .unlink = pvfs2_unlink,
     .symlink = pvfs2_symlink,
     .mkdir = pvfs2_mkdir,
     .rmdir = pvfs2_rmdir,
+    .mknod = pvfs2_mknod,
     .rename = pvfs2_rename,
     .setattr = pvfs2_setattr,
-    .getattr = pvfs2_getattr
+    .getattr = pvfs2_getattr,
+    .getxattr = pvfs2_getxattr,
+    .setxattr = pvfs2_setxattr,
+/*    .listxattr = pvfs2_listxattr,*/
+    .removexattr = pvfs2_removexattr,
 #endif
 };
 

Index: pvfs2-bufmap.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/pvfs2-bufmap.c,v
diff -p -u -r1.33 -r1.33.6.1
--- pvfs2-bufmap.c	3 Dec 2004 19:16:10 -0000	1.33
+++ pvfs2-bufmap.c	25 Aug 2005 20:38:30 -0000	1.33.6.1
@@ -10,6 +10,7 @@
 #define BUFMAP_PAGE_COUNT (PVFS2_BUFMAP_TOTAL_SIZE/PAGE_SIZE)
 #define PAGES_PER_DESC (PVFS2_BUFMAP_DEFAULT_DESC_SIZE/PAGE_SIZE)
 
+extern int debug;
 static int bufmap_init = 0;
 
 static struct page **bufmap_page_array = NULL;
@@ -289,9 +290,10 @@ int pvfs_bufmap_copy_to_user(void __user
 
     if (bufmap_init == 0)
     {
-        pvfs2_print("pvfs2_bufmap_copy_to_user: not yet "
-                    "initialized; returning\n");
-        return 1;
+        pvfs2_error("pvfs2_bufmap_copy_to_user: not yet "
+                    "initialized.\n");
+        pvfs2_error("pvfs2: please confirm that pvfs2-client daemon is running.\n");
+        return -EIO;
     }
 
     while(amt_copied < size)
@@ -306,8 +308,8 @@ int pvfs_bufmap_copy_to_user(void __user
 
         if (ret)
         {
-            pvfs2_error("Failed to copy data to user space\n");
-            return -EIO;
+            pvfs2_print("Failed to copy data to user space\n");
+            return -EFAULT;
         }
 
         offset += cur_copy_size;
@@ -330,9 +332,10 @@ int pvfs_bufmap_copy_to_kernel(
 
     if (bufmap_init == 0)
     {
-        pvfs2_print("pvfs2_bufmap_copy_to_kernel: not yet "
-                    "initialized; returning\n");
-        return 1;
+        pvfs2_error("pvfs2_bufmap_copy_to_kernel: not yet "
+                    "initialized.\n");
+        pvfs2_error("pvfs2: please confirm that pvfs2-client daemon is running.\n");
+        return -EIO;
     }
 
     while(amt_copied < size)
@@ -372,9 +375,10 @@ int pvfs_bufmap_copy_from_user(
 
     if (bufmap_init == 0)
     {
-        pvfs2_print("pvfs2_bufmap_copy_from_user: not yet "
-                    "initialized; returning\n");
-        return 1;
+        pvfs2_error("pvfs2_bufmap_copy_from_user: not yet "
+                    "initialized.\n");
+        pvfs2_error("pvfs2: please confirm that pvfs2-client daemon is running.\n");
+        return -EIO;
     }
 
     while(amt_copied < size)
@@ -389,14 +393,262 @@ int pvfs_bufmap_copy_from_user(
 
         if (ret)
         {
-            pvfs2_error("Failed to copy data from user space\n");
-            return -EIO;
+            pvfs2_print("Failed to copy data from user space\n");
+            return -EFAULT;
         }
 
         offset += cur_copy_size;
         amt_copied += cur_copy_size;
         index++;
     }
+    return 0;
+}
+
+/* pvfs_bufmap_copy_iovec_from_user()
+ *
+ * copies data from several user space address's in an iovec
+ * to a mapped buffer
+ *
+ * Note that the mapped buffer is a series of pages and therefore
+ * the copies have to be split by PAGE_SIZE bytes at a time.
+ * Note that this routine checks that summation of iov_len
+ * across all the elements of iov is equal to size.
+ *
+ * returns 0 on success, -errno on failure
+ */
+int pvfs_bufmap_copy_iovec_from_user(
+    int buffer_index,
+    const struct iovec *iov,
+    unsigned long nr_segs,
+    int size)
+{
+    int ret = 0, amt_copied = 0; 
+    int cur_copy_size = 0, index = 0;
+    void *to_kaddr = NULL;
+    void __user *from_addr = NULL;
+    struct iovec *copied_iovec = NULL;
+    struct pvfs_bufmap_desc *to = &desc_array[buffer_index];
+    unsigned int seg, page_offset = 0;
+
+    pvfs2_print("pvfs_bufmap_copy_iovec_from_user: index %d, "
+                "size %d\n", buffer_index, size);
+
+    if (bufmap_init == 0)
+    {
+        pvfs2_print("pvfs2_bufmap_copy_iovec_from_user: not yet "
+                    "initialized; returning\n");
+        return 1;
+    }
+    /*
+     * copy the passed in iovec so that we can change some of its fields
+     */
+    copied_iovec = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec),
+            PVFS2_BUFMAP_GFP_FLAGS);
+    if (copied_iovec == NULL)
+    {
+        pvfs2_error("pvfs2_bufmap_copy_iovec_from_user: failed allocating memory\n");
+        return -ENOMEM;
+    }
+    memcpy(copied_iovec, iov, nr_segs * sizeof(struct iovec));
+    /*
+     * Go through each segment in the iovec and make sure that
+     * the summation of iov_len matches the given size.
+     */
+    for (seg = 0, amt_copied = 0; seg < nr_segs; seg++)
+    {
+        amt_copied += copied_iovec[seg].iov_len;
+    }
+    if (amt_copied != size)
+    {
+        pvfs2_error("pvfs2_bufmap_copy_iovec_from_user: computed total (%d) is not equal to (%d)\n",
+                amt_copied, size);
+        kfree(copied_iovec);
+        return -EINVAL;
+    }
+
+    index = 0;
+    amt_copied = 0;
+    seg = 0;
+    page_offset = 0;
+    /* Go through each segment in the iovec and copy its
+     * buffer into the mapped buffer one page at a time though
+     */
+    while (amt_copied < size)
+    {
+	struct iovec *iv = &copied_iovec[seg];
+        int inc_index = 0;
+
+        if (iv->iov_len < (PAGE_SIZE - page_offset)) 
+        {
+            cur_copy_size = iv->iov_len;
+            seg++;
+            from_addr = iv->iov_base;
+            inc_index = 0;
+        }
+        else if (iv->iov_len == (PAGE_SIZE - page_offset))
+        {
+            cur_copy_size = iv->iov_len;
+            seg++;
+            from_addr = iv->iov_base;
+            inc_index = 1;
+        }
+        else 
+        {
+            cur_copy_size = (PAGE_SIZE - page_offset);
+            from_addr = iv->iov_base;
+            iv->iov_base += cur_copy_size;
+            iv->iov_len -= cur_copy_size;
+            inc_index = 1;
+        }
+        to_kaddr = pvfs2_kmap(to->page_array[index]);
+        ret = copy_from_user(to_kaddr + page_offset, from_addr, cur_copy_size);
+        pvfs2_kunmap(to->page_array[index]);
+#if 0
+        pvfs2_print("pvfs2_bufmap_copy_iovec_from_user: copying from user %p to kernel %p %d bytes (to_kddr: %p,page_offset: %d)\n",
+                from_addr, to_kaddr + page_offset, cur_copy_size, to_kaddr, page_offset); 
+#endif
+        if (ret)
+        {
+            pvfs2_error("Failed to copy data from user space\n");
+            kfree(copied_iovec);
+            return -EFAULT;
+        }
+
+        amt_copied += cur_copy_size;
+        if (inc_index) {
+            page_offset = 0;
+            index++;
+        }
+        else {
+            page_offset += cur_copy_size;
+        }
+    }
+    kfree(copied_iovec);
+    if (amt_copied != size)
+    {
+	pvfs2_error("Failed to copy all the data from user space [%d instead of %d]\n",
+                amt_copied, size);
+	return -EIO;
+    }
+    return 0;
+}
+
+/* pvfs_bufmap_copy_to_user_iovec()
+ *
+ * copies data to several user space address's in an iovec
+ * from a mapped buffer
+ *
+ * returns 0 on success, -errno on failure
+ */
+int pvfs_bufmap_copy_to_user_iovec(
+    int buffer_index,
+    const struct iovec *iov,
+    unsigned long nr_segs,
+    int size)
+{
+    int ret = 0, amt_copied = 0;
+    int cur_copy_size = 0, index = 0;
+    void *from_kaddr = NULL;
+    void __user *to_addr = NULL;
+    struct iovec *copied_iovec = NULL;
+    struct pvfs_bufmap_desc *from = &desc_array[buffer_index];
+    unsigned int seg, page_offset = 0;
+
+    pvfs2_print("pvfs_bufmap_copy_to_user_iovec: index %d, "
+                "size %d\n", buffer_index, size);
+
+    if (bufmap_init == 0)
+    {
+        pvfs2_print("pvfs2_bufmap_copy_to_user_iovec: not yet "
+                    "initialized; returning\n");
+        return 1;
+    }
+    /*
+     * copy the passed in iovec so that we can change some of its fields
+     */
+    copied_iovec = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec),
+            PVFS2_BUFMAP_GFP_FLAGS);
+    if (copied_iovec == NULL)
+    {
+        pvfs2_error("pvfs2_bufmap_copy_to_user_iovec: failed allocating memory\n");
+        return -ENOMEM;
+    }
+    memcpy(copied_iovec, iov, nr_segs * sizeof(struct iovec));
+    /*
+     * Go through each segment in the iovec and make sure that
+     * the summation of iov_len is greater than the given size.
+     */
+    for (seg = 0, amt_copied = 0; seg < nr_segs; seg++)
+    {
+        amt_copied += copied_iovec[seg].iov_len;
+    }
+    if (amt_copied < size)
+    {
+        pvfs2_error("pvfs2_bufmap_copy_to_user_iovec: computed total (%d) is less than (%d)\n",
+                amt_copied, size);
+        kfree(copied_iovec);
+        return -EINVAL;
+    }
+
+    index = 0;
+    amt_copied = 0;
+    seg = 0;
+    page_offset = 0;
+    /* 
+     * Go through each segment in the iovec and copy from the mapper buffer,
+     * but make sure that we do so one page at a time.
+     */
+    while (amt_copied < size)
+    {
+	struct iovec *iv = &copied_iovec[seg];
+        int inc_index = 0;
+
+        if (iv->iov_len < (PAGE_SIZE - page_offset))
+        {
+            cur_copy_size = iv->iov_len;
+            seg++;
+            to_addr = iv->iov_base;
+            inc_index = 0;
+        }
+        else if (iv->iov_len == (PAGE_SIZE - page_offset))
+        {
+            cur_copy_size = iv->iov_len;
+            seg++;
+            to_addr = iv->iov_base;
+            inc_index = 1;
+        }
+        else 
+        {
+            cur_copy_size = (PAGE_SIZE - page_offset);
+            to_addr = iv->iov_base;
+            iv->iov_base += cur_copy_size;
+            iv->iov_len  -= cur_copy_size;
+            inc_index = 1;
+        }
+        from_kaddr = pvfs2_kmap(from->page_array[index]);
+        ret = copy_to_user(to_addr, from_kaddr + page_offset, cur_copy_size);
+        pvfs2_kunmap(from->page_array[index]);
+#if 0
+        pvfs2_print("pvfs2_bufmap_copy_to_user_iovec: copying to user %p from kernel %p %d bytes (from_kaddr:%p, page_offset:%d)\n",
+                to_addr, from_kaddr + page_offset, cur_copy_size, from_kaddr, page_offset); 
+#endif
+        if (ret)
+        {
+            pvfs2_error("Failed to copy data to user space\n");
+            kfree(copied_iovec);
+            return -EFAULT;
+        }
+
+        amt_copied += cur_copy_size;
+        if (inc_index) {
+            page_offset = 0;
+            index++;
+        }
+        else {
+            page_offset += cur_copy_size;
+        }
+    }
+    kfree(copied_iovec);
     return 0;
 }
 

Index: pvfs2-bufmap.h
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/pvfs2-bufmap.h,v
diff -p -u -r1.10 -r1.10.6.1
--- pvfs2-bufmap.h	22 Nov 2004 18:14:05 -0000	1.10
+++ pvfs2-bufmap.h	25 Aug 2005 20:38:30 -0000	1.10.6.1
@@ -37,9 +37,21 @@ int pvfs_bufmap_copy_from_user(
     void __user *from,
     int size);
 
+int pvfs_bufmap_copy_iovec_from_user(
+    int buffer_index,
+    const struct iovec *iov,
+    unsigned long nr_segs,
+    int size);
+
 int pvfs_bufmap_copy_to_user(
     void __user *to,
     int buffer_index,
+    int size);
+
+int pvfs_bufmap_copy_to_user_iovec(
+    int buffer_index,
+    const struct iovec *iov,
+    unsigned long nr_segs,
     int size);
 
 int pvfs_bufmap_copy_to_kernel(

Index: pvfs2-cache.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/pvfs2-cache.c,v
diff -p -u -r1.24 -r1.24.6.1
--- pvfs2-cache.c	8 Sep 2004 19:59:03 -0000	1.24
+++ pvfs2-cache.c	25 Aug 2005 20:38:30 -0000	1.24.6.1
@@ -18,6 +18,7 @@ extern kmem_cache_t *dev_req_cache;
 /* a cache for pvfs2-inode objects (i.e. pvfs2 inode private data) */
 extern kmem_cache_t *pvfs2_inode_cache;
 
+extern int debug;
 extern int pvfs2_gen_credentials(
     PVFS_credentials *credentials);
 

Index: pvfs2-dev-proto.h
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/pvfs2-dev-proto.h,v
diff -p -u -r1.15 -r1.15.6.1
--- pvfs2-dev-proto.h	3 Dec 2004 19:16:10 -0000	1.15
+++ pvfs2-dev-proto.h	25 Aug 2005 20:38:30 -0000	1.15.6.1
@@ -27,6 +27,10 @@
 #define PVFS2_VFS_OP_MMAP_RA_FLUSH     0xFF00000D
 #define PVFS2_VFS_OP_FS_MOUNT          0xFF00000E
 #define PVFS2_VFS_OP_FS_UMOUNT         0xFF00000F
+#define PVFS2_VFS_OP_GETXATTR          0xFF000010
+#define PVFS2_VFS_OP_SETXATTR          0xFF000011
+#define PVFS2_VFS_OP_LISTXATTR         0xFF000012
+#define PVFS2_VFS_OP_REMOVEXATTR       0xFF000013
 #define PVFS2_VFS_OP_CANCEL            0xFF00EE00
 #define PVFS2_VFS_OP_FSYNC             0xFF00EE01
 

Index: pvfs2-kernel.h
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/pvfs2-kernel.h,v
diff -p -u -r1.88 -r1.88.4.1
--- pvfs2-kernel.h	29 Mar 2005 16:33:13 -0000	1.88
+++ pvfs2-kernel.h	25 Aug 2005 20:38:30 -0000	1.88.4.1
@@ -24,6 +24,12 @@
 
 #ifdef PVFS2_LINUX_KERNEL_2_4
 
+/* the 2.4 kernel requires us to manually set up modversions if needed */
+#if CONFIG_MODVERSIONS==1
+#define MODVERSIONS
+#include <linux/modversions.h>
+#endif 
+
 #define __NO_VERSION__
 #include <linux/version.h>
 #include <linux/module.h>
@@ -86,7 +92,9 @@ do {                                    
     panic(msg);                                                \
 } while(0)
 #else
-#define pvfs2_print(...)
+#define pvfs2_print(format...) do{                             \
+    if(debug) printk(format);                                  \
+}while(0)
 #define pvfs2_panic(msg)                                       \
 do {                                                           \
     pvfs2_error("BUG! Please contact pvfs2-developers at beowulf-"\
@@ -362,6 +370,16 @@ int pvfs2_getattr(
 #endif
 
 /****************************
+ * defined in xattr.c
+ ****************************/
+int pvfs2_setxattr(struct dentry *dentry, const char *name,
+		const void *value, size_t size, int flags);
+ssize_t pvfs2_getxattr(struct dentry *dentry, const char *name,
+		         void *buffer, size_t size);
+ssize_t pvfs2_listxattr(struct dentry *dentry, char *buffer, size_t size);
+int pvfs2_removexattr(struct dentry *dentry, const char *name);
+
+/****************************
  * defined in namei.c
  ****************************/
 #ifdef PVFS2_LINUX_KERNEL_2_4
@@ -381,6 +399,14 @@ struct dentry *pvfs2_lookup(
 int pvfs2_gen_credentials(
     PVFS_credentials *credentials);
 
+ssize_t pvfs2_inode_getxattr(
+        struct inode *inode, const char *name, void *buffer, size_t size);
+int pvfs2_inode_setxattr(struct inode *inode, const char *name,
+        const void *value, size_t size, int flags);
+int pvfs2_inode_removexattr(struct inode *inode, const char *name);
+/*int pvfs2_inode_listxattr(
+        struct inode *inode); */
+
 int pvfs2_inode_getattr(
     struct inode *inode);
 
@@ -599,8 +625,8 @@ do {                                    
  *  this allows us to know if we've reached the error_exit code path
  *  from here or elsewhere
  *
- *  \note used in namei.c:lookup(), file.c:pvfs2_inode_read(), and
- *  file.c:pvfs2_file_write()
+ *  \note used in namei.c:lookup(), file.c:pvfs2_inode_read[v](), and
+ *  file.c:pvfs2_file_write[v]()
  */
 #define service_error_exit_op_with_timeout_retry(op,meth,num,e,intr)\
 do {                                                                \

Index: pvfs2-mod.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/pvfs2-mod.c,v
diff -p -u -r1.26 -r1.26.6.1
--- pvfs2-mod.c	13 Sep 2004 20:52:52 -0000	1.26
+++ pvfs2-mod.c	25 Aug 2005 20:38:30 -0000	1.26.6.1
@@ -6,24 +6,48 @@
 
 #include "pvfs2-kernel.h"
 
-extern struct file_operations pvfs2_devreq_file_operations;
+#ifndef PVFS2_VERSION
+#define PVFS2_VERSION "Unknown"
+#endif
 
+extern struct file_operations pvfs2_devreq_file_operations;
 extern void pvfs2_kill_sb(struct super_block *sb);
 
 static int hash_func(void *key, int table_size);
 static int hash_compare(void *key, struct qhash_head *link);
 
-
 /*************************************
  * global variables declared here
  *************************************/
 
 /* the size of the hash tables for ops in progress */
 static int hash_table_size = 509;
+int debug = 0;
+
+#ifdef CONFIG_SYSCTL
+/* setup information for proc/sys/pvfs2 entries */
+#include <linux/sysctl.h>
+static struct ctl_table_header *fs_table_header = NULL;
+#define FS_PVFS2 1    /* pvfs2 file system */
+#define PVFS2_DEBUG 1 /* ctl debugging level */
+static int min_debug[] = {0}, max_debug[] = {1};
+static ctl_table pvfs2_table[] = {
+    {PVFS2_DEBUG, "debug", &debug, sizeof(int), 0644, NULL,
+        &proc_dointvec_minmax, &sysctl_intvec,
+        NULL, &min_debug, &max_debug},
+    {0}
+};
+static ctl_table fs_table[] = {
+    {FS_PVFS2, "pvfs2", NULL, 0, 0555, pvfs2_table},
+    {0}
+};
+#endif
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("PVFS2 Development Team");
 MODULE_DESCRIPTION("The Linux Kernel VFS interface to PVFS2");
+MODULE_PARM_DESC(debug, "debugging level (0 for none, 1 for verbose)");
+MODULE_PARM_DESC(hash_table_size, "size of hash table for operations in progress");
 
 #ifdef PVFS2_LINUX_KERNEL_2_4
 /*
@@ -33,6 +57,7 @@ MODULE_DESCRIPTION("The Linux Kernel VFS
 DECLARE_FSTYPE(pvfs2_fs_type, "pvfs2", pvfs2_get_sb, 0);
 
 MODULE_PARM(hash_table_size, "i");
+MODULE_PARM(debug, "i");
 
 #else /* !PVFS2_LINUX_KERNEL_2_4 */
 
@@ -52,6 +77,7 @@ struct file_system_type pvfs2_fs_type =
 };
 
 module_param(hash_table_size, int, 0);
+module_param(debug, bool, 0);
 
 #endif /* PVFS2_LINUX_KERNEL_2_4 */
 
@@ -88,8 +114,15 @@ DECLARE_WAIT_QUEUE_HEAD(pvfs2_request_li
 
 static int __init pvfs2_init(void)
 {
+    int ret = -1;
     pvfs2_print("pvfs2: pvfs2_init called\n");
 
+    if(debug)
+    {
+        debug=1; /* normalize any non-zero value to 1 */
+        pvfs2_error("pvfs2: verbose debug mode\n");
+    }
+
     /* register pvfs2-req device  */
     pvfs2_dev_major = register_chrdev(0, PVFS2_REQDEVICE_NAME,
                                       &pvfs2_devreq_file_operations);
@@ -118,7 +151,18 @@ static int __init pvfs2_init(void)
     {
 	panic("Failed to initialize op hashtable");
     }
-    return register_filesystem(&pvfs2_fs_type);
+    ret = register_filesystem(&pvfs2_fs_type);
+
+#ifdef CONFIG_SYSCTL
+    if (!fs_table_header)
+        fs_table_header = register_sysctl_table(fs_table, 0);
+#endif
+
+    if(ret == 0)
+    {
+        printk("pvfs2: module version %s loaded\n", PVFS2_VERSION);
+    }
+    return(ret);
 }
 
 static void __exit pvfs2_exit(void)
@@ -129,6 +173,13 @@ static void __exit pvfs2_exit(void)
 
     pvfs2_print("pvfs2: pvfs2_exit called\n");
 
+#ifdef CONFIG_SYSCTL
+    if ( fs_table_header ) {
+        unregister_sysctl_table(fs_table_header);
+        fs_table_header = NULL;
+    }
+#endif
+
     /* clear out all pending upcall op requests */
     spin_lock(&pvfs2_request_list_lock);
     while (!list_empty(&pvfs2_request_list))
@@ -170,6 +221,8 @@ static void __exit pvfs2_exit(void)
                 PVFS2_REQDEVICE_NAME);
 
     unregister_filesystem(&pvfs2_fs_type);
+
+    printk("pvfs2: module version %s unloaded\n", PVFS2_VERSION);
 }
 
 static int hash_func(void *key, int table_size)

Index: pvfs2-utils.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/pvfs2-utils.c,v
diff -p -u -r1.95 -r1.95.6.1
--- pvfs2-utils.c	3 Dec 2004 19:16:10 -0000	1.95
+++ pvfs2-utils.c	25 Aug 2005 20:38:30 -0000	1.95.6.1
@@ -21,6 +21,7 @@ extern struct inode_operations pvfs2_sym
 extern struct inode_operations pvfs2_dir_inode_operations;
 extern struct file_operations pvfs2_dir_operations;
 extern struct dentry_operations pvfs2_dentry_operations;
+extern int debug;
 
 
 int pvfs2_gen_credentials(
@@ -156,6 +157,9 @@ static inline int copy_attributes_to_ino
         if (attrs->perms & PVFS_U_READ)
             perm_mode |= S_IRUSR;
 
+        if (attrs->perms & PVFS_G_SGID)
+            perm_mode |= S_ISGID;
+
         inode->i_mode |= perm_mode;
 
         switch (attrs->objtype)
@@ -170,6 +174,11 @@ static inline int copy_attributes_to_ino
                 inode->i_mode |= S_IFDIR;
                 inode->i_op = &pvfs2_dir_inode_operations;
                 inode->i_fop = &pvfs2_dir_operations;
+                /* NOTE: we have no good way to keep nlink consistent for 
+                 * directories across clients; keep constant at 1.  Why 1?  If
+                 * we go with 2, then find(1) gets confused and won't work
+                 * properly withouth the -noleaf option */
+                inode->i_nlink = 1;
                 ret = 0;
                 break;
             case PVFS_TYPE_SYMLINK:
@@ -214,21 +223,8 @@ static inline void convert_attribute_mod
     pvfs2_print("mode is %d | translated perms is %d\n", mode,
                 attrs->perms);
 
-    switch(mode & S_IFMT)
-    {
-        case S_IFREG:
-            attrs->objtype = PVFS_TYPE_METAFILE;
-            attrs->mask |= PVFS_ATTR_SYS_TYPE;
-            break;
-        case S_IFDIR:
-            attrs->objtype = PVFS_TYPE_DIRECTORY;
-            attrs->mask |= PVFS_ATTR_SYS_TYPE;
-            break;
-        case S_IFLNK:
-            attrs->objtype = PVFS_TYPE_SYMLINK;
-            attrs->mask |= PVFS_ATTR_SYS_TYPE;
-            break;
-    }
+    /* NOTE: this function only called during setattr.  Setattr must not mess
+     * with object type */
 }
 
 /*
@@ -275,23 +271,38 @@ static inline int copy_attributes_from_i
              pvfs2_convert_time_field((void *)&inode->i_ctime));
         attrs->mask |= PVFS_ATTR_SYS_CTIME;
 
-        attrs->size = ((iattr && (iattr->ia_valid & ATTR_SIZE)) ?
-                       iattr->ia_size : inode->i_size);
-        attrs->mask |= PVFS_ATTR_SYS_SIZE;
+        /* PVFS2 cannot set size with a setattr operation.  Probably not likely
+         * to be requested through the VFS, but just in case, don't worry about
+         * ATTR_SIZE */
 
         if (iattr && (iattr->ia_valid & ATTR_MODE))
         {
             pvfs2_print("[1] converting attr mode %d\n", iattr->ia_mode);
+            if((iattr->ia_mode & (S_ISUID|S_ISVTX)) != 0)
+            {
+                pvfs2_print("User attempted to set setuid or sticky bit; "
+                    "returning EINVAL.\n");
+                return(-EINVAL);
+            }
             convert_attribute_mode_to_pvfs_sys_attr(
                 iattr->ia_mode, attrs);
         }
         else
         {
-            pvfs2_print("[2] converting attr mode %d\n", inode->i_mode);
+            pvfs2_print("[2] converting attr mode %d\n", inode->i_mode); 
+            if((inode->i_mode & (S_ISUID|S_ISVTX)) != 0)
+            {
+                pvfs2_print("User attempted to set setuid or sticky bit; "
+                    "returning EINVAL.\n");
+                return(-EINVAL);
+            }
             convert_attribute_mode_to_pvfs_sys_attr(
                 inode->i_mode, attrs);
         }
-        attrs->mask = PVFS_ATTR_SYS_ALL_SETABLE;
+
+        /* we carefully selected which bits to set in attrs->mask above, so
+         * don't undo all that work by setting attrs->mask to
+         * PVFS_ATTR_SYS_ALL_SETABLE */
 
         ret = 0;
     }
@@ -378,7 +389,7 @@ int pvfs2_inode_getattr(struct inode *in
       copy_attr_failure:
         pvfs2_print("Getattr on handle %Lu, fsid %d\n  (inode ct = %d) "
                     "returned %d (error_exit = %d)\n",
-                    pvfs2_inode->refn.handle, pvfs2_inode->refn.fs_id,
+                    Lu(pvfs2_inode->refn.handle), pvfs2_inode->refn.fs_id,
                     (int)atomic_read(&inode->i_count), ret, error_exit);
 
         op_release(new_op);
@@ -419,8 +430,13 @@ int pvfs2_inode_setattr(
             new_op->upcall.req.lookup.parent_refn.fs_id =
                 PVFS2_SB(sb)->fs_id;
         }
-        copy_attributes_from_inode(
+        ret = copy_attributes_from_inode(
             inode, &new_op->upcall.req.setattr.attributes, iattr);
+        if(ret < 0)
+        {
+            op_release(new_op);
+            return(ret);
+        }
 
         service_error_exit_op_with_timeout_retry(
             new_op, "pvfs2_inode_setattr", retries, error_exit,
@@ -438,6 +454,234 @@ int pvfs2_inode_setattr(
     return ret;
 }
 
+
+/* Extended attributes helper functions */
+/*
+ * Tries to get a specified key's attributes of a given
+ * file into a user-specified buffer. Note that the getxattr
+ * interface allows for the users to probe the size of an
+ * extended attribute by passing in a value of 0 to size.
+ * Thus our return value is always the size of the attribute
+ * unless the key does not exist for the file and/or if
+ * there were errors in fetching the attribute value.
+ */
+ssize_t pvfs2_inode_getxattr(struct inode *inode, const char *name, 
+        void *buffer, size_t size)
+{
+    ssize_t ret = -ENOMEM;
+    int retries = PVFS2_OP_RETRY_COUNT, error_exit = 0;
+    pvfs2_kernel_op_t *new_op = NULL;
+    pvfs2_inode_t *pvfs2_inode = NULL;
+    ssize_t length = 0;
+
+    if (size < 0 || strlen(name) >= PVFS_MAX_XATTR_NAMELEN)
+    {
+        pvfs2_error("Invalid size (%d) or key length (%d)\n", 
+                size, strlen(name));
+        return -EINVAL;
+    }
+    if (inode)
+    {
+        pvfs2_inode = PVFS2_I(inode);
+
+        new_op = op_alloc();
+        if (!new_op)
+        {
+            return ret;
+        }
+
+        new_op->upcall.type = PVFS2_VFS_OP_GETXATTR;
+        new_op->upcall.req.getxattr.refn = pvfs2_inode->refn;
+        strncpy(new_op->upcall.req.getxattr.key, name, PVFS_MAX_XATTR_NAMELEN);
+        /* 
+         * NOTE: Although keys are meant to be NULL terminated textual strings,
+         * I am going to explicitly pass the length just in case we change this
+         * later on...
+         */
+        new_op->upcall.req.getxattr.key_sz = 
+            strlen(new_op->upcall.req.getxattr.key) + 1;
+        pvfs2_print("pvfs2_inode_getxattr: key %s, key_sz %d\n", 
+                name, new_op->upcall.req.getxattr.key_sz);
+
+        service_error_exit_op_with_timeout_retry(
+            new_op, "pvfs2_inode_getxattr", retries, error_exit,
+            get_interruptible_flag(inode));
+
+      error_exit:
+        ret = (error_exit ? -EINTR :
+               pvfs2_kernel_error_code_convert(new_op->downcall.status));
+        /* Upon success, we need to get the value length
+         * from downcall and return that.
+         * and also copy the value out to the requester
+         */
+        if (ret == 0)
+        {
+            length = new_op->downcall.resp.getxattr.val_sz;
+            /* Just return the length of the queried attribute after
+             * subtracting the \0 thingie */
+            if (size == 0)
+            {
+                ret = length - 1;
+            }
+            else
+            {
+                /* check to see if key length is > provided buffer size */
+                if (length - 1 > size)
+                {
+                    ret = -ERANGE;
+                }
+                else
+                {
+                    /* No size problems. At present using strncpy means that
+                     * val is also textual not binary */
+                    memset(buffer, 0, size);
+                    strncpy(buffer, new_op->downcall.resp.getxattr.val, 
+                            length - 1);
+                    ret = length - 1;
+                    pvfs2_print("pvfs2_getxattr: key: %s, val_length: %d, val: %s\n",
+                            name, ret, (char *) buffer);
+                }
+            }
+        }
+        else if (ret == -ENOENT)
+        {
+            ret = -ENODATA; /* if no such keys exists we set this to be errno */
+        }
+        pvfs2_print("pvfs2_inode_getxattr: returning %d\n", ret);
+
+        /* when request is serviced properly, free req op struct */
+        op_release(new_op);
+    }
+    return ret;
+}
+
+/*
+ * tries to set an attribute for a given key on a file.
+ * Returns a -ve number on error and 0 on success.
+ * Note that value is treated like text and not like binary!
+ */
+int pvfs2_inode_setxattr(struct inode *inode, const char *name,
+        const void *value, size_t size, int flags)
+{
+    int ret = -ENOMEM, retries = PVFS2_OP_RETRY_COUNT, error_exit = 0;
+    pvfs2_kernel_op_t *new_op = NULL;
+    pvfs2_inode_t *pvfs2_inode = NULL;
+
+    if (size <= 0 || size >= PVFS_MAX_XATTR_VALUELEN || flags < 0)
+    {
+        pvfs2_error("pvfs2_inode_setxattr: bogus values of size(%d), flags(%d)\n", 
+                size, flags);
+        return -EINVAL;
+    }
+    if (strlen(name) >= PVFS_MAX_XATTR_NAMELEN)
+    {
+        pvfs2_error("pvfs2_inode_setxattr: bogus key size (%d)\n", 
+                strlen(name));
+        return -EINVAL;
+    }
+    if (inode)
+    {
+        pvfs2_inode = PVFS2_I(inode);
+
+        new_op = op_alloc();
+        if (!new_op)
+        {
+            return ret;
+        }
+
+        new_op->upcall.type = PVFS2_VFS_OP_SETXATTR;
+        new_op->upcall.req.setxattr.refn = pvfs2_inode->refn;
+        new_op->upcall.req.setxattr.flags = flags;
+        /* 
+         * NOTE: Although keys are meant to be NULL terminated textual strings,
+         * I am going to explicitly pass the length just in case we change this
+         * later on...
+         */
+        strncpy(new_op->upcall.req.setxattr.keyval.key, 
+                name, PVFS_MAX_XATTR_NAMELEN);
+        new_op->upcall.req.setxattr.keyval.key_sz = 
+            strlen(new_op->upcall.req.setxattr.keyval.key) + 1;
+        strncpy(new_op->upcall.req.setxattr.keyval.val, value, size);
+        /* For some reason, val_sz should include the \0 at the end as well */
+        new_op->upcall.req.setxattr.keyval.val_sz = size + 1;
+
+        service_error_exit_op_with_timeout_retry(
+            new_op, "pvfs2_inode_setxattr", retries, error_exit,
+            get_interruptible_flag(inode));
+
+      error_exit:
+        ret = (error_exit ? -EINTR :
+               pvfs2_kernel_error_code_convert(new_op->downcall.status));
+
+        pvfs2_print("pvfs2_inode_setxattr: returning %d\n", ret);
+
+        /* when request is serviced properly, free req op struct */
+        op_release(new_op);
+    }
+    return ret;
+}
+
+int pvfs2_inode_removexattr(struct inode *inode, const char *name)
+{
+    int ret = -ENOMEM, retries = PVFS2_OP_RETRY_COUNT, error_exit = 0;
+    pvfs2_kernel_op_t *new_op = NULL;
+    pvfs2_inode_t *pvfs2_inode = NULL;
+
+    if (strlen(name) >= PVFS_MAX_XATTR_NAMELEN)
+    {
+        pvfs2_error("pvfs2_inode_removexattr: Invalid key length(%d)\n", 
+                strlen(name));
+        return -EINVAL;
+    }
+    if (inode)
+    {
+        pvfs2_inode = PVFS2_I(inode);
+
+        new_op = op_alloc();
+        if (!new_op)
+        {
+            return ret;
+        }
+
+        new_op->upcall.type = PVFS2_VFS_OP_REMOVEXATTR;
+        new_op->upcall.req.removexattr.refn = pvfs2_inode->refn;
+        /* 
+         * NOTE: Although keys are meant to be NULL terminated textual strings,
+         * I am going to explicitly pass the length just in case we change this
+         * later on...
+         */
+        strncpy(new_op->upcall.req.removexattr.key, name, 
+                PVFS_MAX_XATTR_NAMELEN);
+        new_op->upcall.req.removexattr.key_sz = 
+            strlen(new_op->upcall.req.removexattr.key) + 1;
+
+        service_error_exit_op_with_timeout_retry(
+            new_op, "pvfs2_inode_removexattr", retries, error_exit,
+            get_interruptible_flag(inode));
+
+      error_exit:
+        ret = (error_exit ? -EINTR :
+               pvfs2_kernel_error_code_convert(new_op->downcall.status));
+
+        if (ret == -ENOENT)
+        {
+            ret = -ENODATA;
+        }
+        pvfs2_print("pvfs2_inode_removexattr: returning %d\n", ret);
+
+        /* when request is serviced properly, free req op struct */
+        op_release(new_op);
+    }
+    return ret;
+}
+
+/*
+ * FIXME: NOT IMPLEMENTED YET!
+int pvfs2_inode_listxattr(struct inode *inode, char *buffer, size_t size)
+{
+}
+*/
+
 static inline struct inode *pvfs2_create_file(
     struct inode *dir,
     struct dentry *dentry,
@@ -484,7 +728,7 @@ static inline struct inode *pvfs2_create
     ret = pvfs2_kernel_error_code_convert(new_op->downcall.status);
 
     pvfs2_print("Create Got PVFS2 handle %Lu on fsid %d (ret=%d)\n",
-                new_op->downcall.resp.create.refn.handle,
+                Lu(new_op->downcall.resp.create.refn.handle),
                 new_op->downcall.resp.create.refn.fs_id, ret);
 
     if (ret > -1)
@@ -573,7 +817,7 @@ static inline struct inode *pvfs2_create
         get_interruptible_flag(dir));
 
     pvfs2_print("Mkdir Got PVFS2 handle %Lu on fsid %d\n",
-                new_op->downcall.resp.mkdir.refn.handle,
+                Lu(new_op->downcall.resp.mkdir.refn.handle),
                 new_op->downcall.resp.mkdir.refn.fs_id);
 
     if (new_op->downcall.status > -1)
@@ -666,7 +910,7 @@ static inline struct inode *pvfs2_create
     ret = pvfs2_kernel_error_code_convert(new_op->downcall.status);
 
     pvfs2_print("Symlink Got PVFS2 handle %Lu on fsid %d (ret=%d)\n",
-                new_op->downcall.resp.sym.refn.handle,
+                Lu(new_op->downcall.resp.sym.refn.handle),
                 new_op->downcall.resp.sym.refn.fs_id, ret);
 
     if (ret > -1)
@@ -769,7 +1013,7 @@ int pvfs2_remove_entry(
     {
         pvfs2_print("pvfs2_remove_entry: called on %s\n  (inode %d): "
                     "Parent is %Lu | fs_id %d\n", dentry->d_name.name,
-                    (int)inode->i_ino, parent->refn.handle,
+                    (int)inode->i_ino, Lu(parent->refn.handle),
                     parent->refn.fs_id);
 
         new_op = op_alloc();
@@ -830,7 +1074,7 @@ int pvfs2_truncate_inode(
 
     pvfs2_print("pvfs2: pvfs2_truncate_inode %d: "
                 "Handle is %Lu | fs_id %d | size is %lu\n",
-                (int)inode->i_ino, pvfs2_inode->refn.handle,
+                (int)inode->i_ino, Lu(pvfs2_inode->refn.handle),
                 pvfs2_inode->refn.fs_id, (unsigned long)size);
 
     new_op = op_alloc();

Index: super.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/super.c,v
diff -p -u -r1.58 -r1.58.4.1
--- super.c	29 Mar 2005 16:33:13 -0000	1.58
+++ super.c	25 Aug 2005 20:38:31 -0000	1.58.4.1
@@ -16,6 +16,7 @@ extern spinlock_t pvfs2_request_list_loc
 extern wait_queue_head_t pvfs2_request_list_waitq;
 
 extern void pvfs2_kill_sb(struct super_block *sb);
+extern int debug;
 
 /* list for storing pvfs2 specific superblocks in use */
 LIST_HEAD(pvfs2_superblocks);
@@ -129,7 +130,7 @@ static int parse_mount_options(
                 }
                 else
                 {
-                    pvfs2_error("pvfs2: multiple device names specified: "
+                    pvfs2_print("pvfs2: multiple device names specified: "
                                 "ignoring %s\n", options[i]);
                 }
             }
@@ -542,7 +543,7 @@ struct super_block* pvfs2_get_sb(
     service_operation(new_op, "pvfs2_get_sb", 0);
     ret = pvfs2_kernel_error_code_convert(new_op->downcall.status);
 
-    pvfs2_print("pvfs2_remount: mount got return value of %d\n", ret);
+    pvfs2_print("%s: mount got return value of %d\n", __func__, ret);
     if (ret)
     {
         goto error_exit;

Index: symlink.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/symlink.c,v
diff -p -u -r1.9 -r1.9.6.1
--- symlink.c	22 Nov 2004 18:14:05 -0000	1.9
+++ symlink.c	25 Aug 2005 20:38:31 -0000	1.9.6.1
@@ -10,6 +10,7 @@
 extern struct list_head pvfs2_request_list;
 extern spinlock_t pvfs2_request_list_lock;
 extern struct dentry_operations pvfs2_dentry_operations;
+extern int debug;
 
 static int pvfs2_readlink(
     struct dentry *dentry, char __user *buffer, int buflen)

Index: upcall.h
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/upcall.h,v
diff -p -u -r1.27 -r1.27.6.1
--- upcall.h	3 Dec 2004 19:16:10 -0000	1.27
+++ upcall.h	25 Aug 2005 20:38:31 -0000	1.27.6.1
@@ -108,6 +108,32 @@ typedef struct
     PVFS_fs_id fs_id;
 } pvfs2_fs_umount_request_t;
 
+typedef struct 
+{
+    PVFS_object_ref refn;
+    char key[PVFS_MAX_XATTR_NAMELEN];
+    int key_sz;
+} pvfs2_getxattr_request_t;
+
+typedef struct
+{
+    PVFS_object_ref refn;
+    int   flags;
+    PVFS_keyval_pair keyval;
+} pvfs2_setxattr_request_t;
+
+typedef struct 
+{
+    PVFS_object_ref refn;
+} pvfs2_listxattr_request_t;
+
+typedef struct 
+{
+    PVFS_object_ref refn;
+    char key[PVFS_MAX_XATTR_NAMELEN];
+    int key_sz;
+} pvfs2_removexattr_request_t;
+
 typedef struct
 {
     uint64_t op_tag;
@@ -140,6 +166,10 @@ typedef struct
         pvfs2_mmap_ra_cache_flush_request_t ra_cache_flush;
         pvfs2_fs_mount_request_t fs_mount;
         pvfs2_fs_umount_request_t fs_umount;
+        pvfs2_getxattr_request_t getxattr;
+        pvfs2_setxattr_request_t setxattr;
+/*        pvfs2_listxattr_request_t listxattr; */ /* NOT IMPLEMENTED YET */
+        pvfs2_removexattr_request_t removexattr;
         pvfs2_op_cancel_t cancel;
         pvfs2_fsync_request_t fsync;
     } req;

Index: waitqueue.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/kernel/linux-2.6/waitqueue.c,v
diff -p -u -r1.15 -r1.15.6.1
--- waitqueue.c	11 Jan 2005 17:24:19 -0000	1.15
+++ waitqueue.c	25 Aug 2005 20:38:31 -0000	1.15.6.1
@@ -15,6 +15,7 @@
 extern struct list_head pvfs2_request_list;
 extern spinlock_t pvfs2_request_list_lock;
 extern struct qhash_table *htable_ops_in_progress;
+extern int debug;
 
 static inline void clean_up_interrupted_operation(
     pvfs2_kernel_op_t * op)



More information about the PVFS2-CVS mailing list