]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/read_write.c
don't call file_pos_write() if vfs_{read,write}{,v}() fails
[karo-tx-linux.git] / fs / read_write.c
index 03430008704e68fd74470e8dbb9fcb637dce3f97..f646c8b565b913d5cbe02a5dafb2aba5a4b163ef 100644 (file)
@@ -477,7 +477,8 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
        if (f.file) {
                loff_t pos = file_pos_read(f.file);
                ret = vfs_read(f.file, buf, count, &pos);
-               file_pos_write(f.file, pos);
+               if (ret >= 0)
+                       file_pos_write(f.file, pos);
                fdput(f);
        }
        return ret;
@@ -492,7 +493,8 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
        if (f.file) {
                loff_t pos = file_pos_read(f.file);
                ret = vfs_write(f.file, buf, count, &pos);
-               file_pos_write(f.file, pos);
+               if (ret >= 0)
+                       file_pos_write(f.file, pos);
                fdput(f);
        }
 
@@ -780,7 +782,8 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
        if (f.file) {
                loff_t pos = file_pos_read(f.file);
                ret = vfs_readv(f.file, vec, vlen, &pos);
-               file_pos_write(f.file, pos);
+               if (ret >= 0)
+                       file_pos_write(f.file, pos);
                fdput(f);
        }
 
@@ -799,7 +802,8 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
        if (f.file) {
                loff_t pos = file_pos_read(f.file);
                ret = vfs_writev(f.file, vec, vlen, &pos);
-               file_pos_write(f.file, pos);
+               if (ret >= 0)
+                       file_pos_write(f.file, pos);
                fdput(f);
        }
 
@@ -959,7 +963,8 @@ COMPAT_SYSCALL_DEFINE3(readv, unsigned long, fd,
                return -EBADF;
        pos = f.file->f_pos;
        ret = compat_readv(f.file, vec, vlen, &pos);
-       f.file->f_pos = pos;
+       if (ret >= 0)
+               f.file->f_pos = pos;
        fdput(f);
        return ret;
 }
@@ -1025,7 +1030,8 @@ COMPAT_SYSCALL_DEFINE3(writev, unsigned long, fd,
                return -EBADF;
        pos = f.file->f_pos;
        ret = compat_writev(f.file, vec, vlen, &pos);
-       f.file->f_pos = pos;
+       if (ret >= 0)
+               f.file->f_pos = pos;
        fdput(f);
        return ret;
 }
@@ -1064,6 +1070,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
        struct fd in, out;
        struct inode *in_inode, *out_inode;
        loff_t pos;
+       loff_t out_pos;
        ssize_t retval;
        int fl;
 
@@ -1077,12 +1084,14 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
        if (!(in.file->f_mode & FMODE_READ))
                goto fput_in;
        retval = -ESPIPE;
-       if (!ppos)
-               ppos = &in.file->f_pos;
-       else
+       if (!ppos) {
+               pos = in.file->f_pos;
+       } else {
+               pos = *ppos;
                if (!(in.file->f_mode & FMODE_PREAD))
                        goto fput_in;
-       retval = rw_verify_area(READ, in.file, ppos, count);
+       }
+       retval = rw_verify_area(READ, in.file, &pos, count);
        if (retval < 0)
                goto fput_in;
        count = retval;
@@ -1099,7 +1108,8 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
        retval = -EINVAL;
        in_inode = file_inode(in.file);
        out_inode = file_inode(out.file);
-       retval = rw_verify_area(WRITE, out.file, &out.file->f_pos, count);
+       out_pos = out.file->f_pos;
+       retval = rw_verify_area(WRITE, out.file, &out_pos, count);
        if (retval < 0)
                goto fput_out;
        count = retval;
@@ -1107,7 +1117,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
        if (!max)
                max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
 
-       pos = *ppos;
        if (unlikely(pos + count > max)) {
                retval = -EOVERFLOW;
                if (pos >= max)
@@ -1126,18 +1135,25 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
        if (in.file->f_flags & O_NONBLOCK)
                fl = SPLICE_F_NONBLOCK;
 #endif
-       retval = do_splice_direct(in.file, ppos, out.file, count, fl);
+       file_start_write(out.file);
+       retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl);
+       file_end_write(out.file);
 
        if (retval > 0) {
                add_rchar(current, retval);
                add_wchar(current, retval);
                fsnotify_access(in.file);
                fsnotify_modify(out.file);
+               out.file->f_pos = out_pos;
+               if (ppos)
+                       *ppos = pos;
+               else
+                       in.file->f_pos = pos;
        }
 
        inc_syscr(current);
        inc_syscw(current);
-       if (*ppos > max)
+       if (pos > max)
                retval = -EOVERFLOW;
 
 fput_out: