[PVFS2-CVS] commit by robl in pvfs2-1/src/kernel/linux-2.6: file.c pvfs2-bufmap.c

CVS commit program cvs at parl.clemson.edu
Mon Jul 11 19:36:40 EDT 2005


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

Modified Files:
	file.c pvfs2-bufmap.c 
Log Message:
[pcarns]: This fixes some fairly important problems in the kernel module
read/write path:

- adds some extra write() argument checking that most stock file systems get
  for free (honors rlimits, LFS limits (if applicable), semantics of writing
  beyond eof, read only protection)
- the 2.6 kernel calls an exported function to handle the above bullet, but the
  2.4 kernel must duplicate a function from the kernel to get this.
- new access_ok() checks to catch bad memory access early
- propigation of error codes out of bufmap component, rather than hardcoded
  error msgs/codes


Index: file.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/kernel/linux-2.6/file.c,v
diff -u -w -p -u -r1.91 -r1.92
--- file.c	7 Jul 2005 21:38:42 -0000	1.91
+++ file.c	11 Jul 2005 22:36:40 -0000	1.92
@@ -21,6 +21,10 @@ 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 {                                              \
@@ -105,6 +109,9 @@ ssize_t pvfs2_inode_read(
     pvfs2_inode_t *pvfs2_inode = PVFS2_I(inode);
     int dc_status;
 
+    if (!access_ok(VERIFY_WRITE, buf, count))
+        return -EFAULT;
+
     while(total_count < count)
     {
         new_op = op_alloc();
@@ -189,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;
             }
         }
@@ -265,6 +275,22 @@ static ssize_t pvfs2_file_write(
                 (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();
@@ -298,15 +324,15 @@ 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;
@@ -552,6 +578,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: pvfs2-bufmap.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/kernel/linux-2.6/pvfs2-bufmap.c,v
diff -u -w -p -u -r1.34 -r1.35
--- pvfs2-bufmap.c	7 Jul 2005 21:38:42 -0000	1.34
+++ pvfs2-bufmap.c	11 Jul 2005 22:36:40 -0000	1.35
@@ -290,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)
@@ -307,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;
@@ -331,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)
@@ -373,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)
@@ -390,8 +393,8 @@ 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;



More information about the PVFS2-CVS mailing list