[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