[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