diff options
Diffstat (limited to 'fs/read_write.c')
| -rw-r--r-- | fs/read_write.c | 65 |
1 files changed, 51 insertions, 14 deletions
diff --git a/fs/read_write.c b/fs/read_write.c index 2cefa417be34..122a3846d9e1 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
| @@ -41,8 +41,19 @@ static inline int unsigned_offsets(struct file *file) | |||
| 41 | return file->f_mode & FMODE_UNSIGNED_OFFSET; | 41 | return file->f_mode & FMODE_UNSIGNED_OFFSET; |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | static loff_t lseek_execute(struct file *file, struct inode *inode, | 44 | /** |
| 45 | loff_t offset, loff_t maxsize) | 45 | * vfs_setpos - update the file offset for lseek |
| 46 | * @file: file structure in question | ||
| 47 | * @offset: file offset to seek to | ||
| 48 | * @maxsize: maximum file size | ||
| 49 | * | ||
| 50 | * This is a low-level filesystem helper for updating the file offset to | ||
| 51 | * the value specified by @offset if the given offset is valid and it is | ||
| 52 | * not equal to the current file offset. | ||
| 53 | * | ||
| 54 | * Return the specified offset on success and -EINVAL on invalid offset. | ||
| 55 | */ | ||
| 56 | loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize) | ||
| 46 | { | 57 | { |
| 47 | if (offset < 0 && !unsigned_offsets(file)) | 58 | if (offset < 0 && !unsigned_offsets(file)) |
| 48 | return -EINVAL; | 59 | return -EINVAL; |
| @@ -55,6 +66,7 @@ static loff_t lseek_execute(struct file *file, struct inode *inode, | |||
| 55 | } | 66 | } |
| 56 | return offset; | 67 | return offset; |
| 57 | } | 68 | } |
| 69 | EXPORT_SYMBOL(vfs_setpos); | ||
| 58 | 70 | ||
| 59 | /** | 71 | /** |
| 60 | * generic_file_llseek_size - generic llseek implementation for regular files | 72 | * generic_file_llseek_size - generic llseek implementation for regular files |
| @@ -76,8 +88,6 @@ loff_t | |||
| 76 | generic_file_llseek_size(struct file *file, loff_t offset, int whence, | 88 | generic_file_llseek_size(struct file *file, loff_t offset, int whence, |
| 77 | loff_t maxsize, loff_t eof) | 89 | loff_t maxsize, loff_t eof) |
| 78 | { | 90 | { |
| 79 | struct inode *inode = file->f_mapping->host; | ||
| 80 | |||
| 81 | switch (whence) { | 91 | switch (whence) { |
| 82 | case SEEK_END: | 92 | case SEEK_END: |
| 83 | offset += eof; | 93 | offset += eof; |
| @@ -97,8 +107,7 @@ generic_file_llseek_size(struct file *file, loff_t offset, int whence, | |||
| 97 | * like SEEK_SET. | 107 | * like SEEK_SET. |
| 98 | */ | 108 | */ |
| 99 | spin_lock(&file->f_lock); | 109 | spin_lock(&file->f_lock); |
| 100 | offset = lseek_execute(file, inode, file->f_pos + offset, | 110 | offset = vfs_setpos(file, file->f_pos + offset, maxsize); |
| 101 | maxsize); | ||
| 102 | spin_unlock(&file->f_lock); | 111 | spin_unlock(&file->f_lock); |
| 103 | return offset; | 112 | return offset; |
| 104 | case SEEK_DATA: | 113 | case SEEK_DATA: |
| @@ -120,7 +129,7 @@ generic_file_llseek_size(struct file *file, loff_t offset, int whence, | |||
| 120 | break; | 129 | break; |
| 121 | } | 130 | } |
| 122 | 131 | ||
| 123 | return lseek_execute(file, inode, offset, maxsize); | 132 | return vfs_setpos(file, offset, maxsize); |
| 124 | } | 133 | } |
| 125 | EXPORT_SYMBOL(generic_file_llseek_size); | 134 | EXPORT_SYMBOL(generic_file_llseek_size); |
| 126 | 135 | ||
| @@ -145,6 +154,26 @@ loff_t generic_file_llseek(struct file *file, loff_t offset, int whence) | |||
| 145 | EXPORT_SYMBOL(generic_file_llseek); | 154 | EXPORT_SYMBOL(generic_file_llseek); |
| 146 | 155 | ||
| 147 | /** | 156 | /** |
| 157 | * fixed_size_llseek - llseek implementation for fixed-sized devices | ||
| 158 | * @file: file structure to seek on | ||
| 159 | * @offset: file offset to seek to | ||
| 160 | * @whence: type of seek | ||
| 161 | * @size: size of the file | ||
| 162 | * | ||
| 163 | */ | ||
| 164 | loff_t fixed_size_llseek(struct file *file, loff_t offset, int whence, loff_t size) | ||
| 165 | { | ||
| 166 | switch (whence) { | ||
| 167 | case SEEK_SET: case SEEK_CUR: case SEEK_END: | ||
| 168 | return generic_file_llseek_size(file, offset, whence, | ||
| 169 | size, size); | ||
| 170 | default: | ||
| 171 | return -EINVAL; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | EXPORT_SYMBOL(fixed_size_llseek); | ||
| 175 | |||
| 176 | /** | ||
| 148 | * noop_llseek - No Operation Performed llseek implementation | 177 | * noop_llseek - No Operation Performed llseek implementation |
| 149 | * @file: file structure to seek on | 178 | * @file: file structure to seek on |
| 150 | * @offset: file offset to seek to | 179 | * @offset: file offset to seek to |
| @@ -296,7 +325,7 @@ out_putf: | |||
| 296 | * them to something that fits in "int" so that others | 325 | * them to something that fits in "int" so that others |
| 297 | * won't have to do range checks all the time. | 326 | * won't have to do range checks all the time. |
| 298 | */ | 327 | */ |
| 299 | int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count) | 328 | int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count) |
| 300 | { | 329 | { |
| 301 | struct inode *inode; | 330 | struct inode *inode; |
| 302 | loff_t pos; | 331 | loff_t pos; |
| @@ -477,7 +506,8 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) | |||
| 477 | if (f.file) { | 506 | if (f.file) { |
| 478 | loff_t pos = file_pos_read(f.file); | 507 | loff_t pos = file_pos_read(f.file); |
| 479 | ret = vfs_read(f.file, buf, count, &pos); | 508 | ret = vfs_read(f.file, buf, count, &pos); |
| 480 | file_pos_write(f.file, pos); | 509 | if (ret >= 0) |
| 510 | file_pos_write(f.file, pos); | ||
| 481 | fdput(f); | 511 | fdput(f); |
| 482 | } | 512 | } |
| 483 | return ret; | 513 | return ret; |
| @@ -492,7 +522,8 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, | |||
| 492 | if (f.file) { | 522 | if (f.file) { |
| 493 | loff_t pos = file_pos_read(f.file); | 523 | loff_t pos = file_pos_read(f.file); |
| 494 | ret = vfs_write(f.file, buf, count, &pos); | 524 | ret = vfs_write(f.file, buf, count, &pos); |
| 495 | file_pos_write(f.file, pos); | 525 | if (ret >= 0) |
| 526 | file_pos_write(f.file, pos); | ||
| 496 | fdput(f); | 527 | fdput(f); |
| 497 | } | 528 | } |
| 498 | 529 | ||
| @@ -780,7 +811,8 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, | |||
| 780 | if (f.file) { | 811 | if (f.file) { |
| 781 | loff_t pos = file_pos_read(f.file); | 812 | loff_t pos = file_pos_read(f.file); |
| 782 | ret = vfs_readv(f.file, vec, vlen, &pos); | 813 | ret = vfs_readv(f.file, vec, vlen, &pos); |
| 783 | file_pos_write(f.file, pos); | 814 | if (ret >= 0) |
| 815 | file_pos_write(f.file, pos); | ||
| 784 | fdput(f); | 816 | fdput(f); |
| 785 | } | 817 | } |
| 786 | 818 | ||
| @@ -799,7 +831,8 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, | |||
| 799 | if (f.file) { | 831 | if (f.file) { |
| 800 | loff_t pos = file_pos_read(f.file); | 832 | loff_t pos = file_pos_read(f.file); |
| 801 | ret = vfs_writev(f.file, vec, vlen, &pos); | 833 | ret = vfs_writev(f.file, vec, vlen, &pos); |
| 802 | file_pos_write(f.file, pos); | 834 | if (ret >= 0) |
| 835 | file_pos_write(f.file, pos); | ||
| 803 | fdput(f); | 836 | fdput(f); |
| 804 | } | 837 | } |
| 805 | 838 | ||
| @@ -959,7 +992,8 @@ COMPAT_SYSCALL_DEFINE3(readv, unsigned long, fd, | |||
| 959 | return -EBADF; | 992 | return -EBADF; |
| 960 | pos = f.file->f_pos; | 993 | pos = f.file->f_pos; |
| 961 | ret = compat_readv(f.file, vec, vlen, &pos); | 994 | ret = compat_readv(f.file, vec, vlen, &pos); |
| 962 | f.file->f_pos = pos; | 995 | if (ret >= 0) |
| 996 | f.file->f_pos = pos; | ||
| 963 | fdput(f); | 997 | fdput(f); |
| 964 | return ret; | 998 | return ret; |
| 965 | } | 999 | } |
| @@ -1025,7 +1059,8 @@ COMPAT_SYSCALL_DEFINE3(writev, unsigned long, fd, | |||
| 1025 | return -EBADF; | 1059 | return -EBADF; |
| 1026 | pos = f.file->f_pos; | 1060 | pos = f.file->f_pos; |
| 1027 | ret = compat_writev(f.file, vec, vlen, &pos); | 1061 | ret = compat_writev(f.file, vec, vlen, &pos); |
| 1028 | f.file->f_pos = pos; | 1062 | if (ret >= 0) |
| 1063 | f.file->f_pos = pos; | ||
| 1029 | fdput(f); | 1064 | fdput(f); |
| 1030 | return ret; | 1065 | return ret; |
| 1031 | } | 1066 | } |
| @@ -1129,7 +1164,9 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
| 1129 | if (in.file->f_flags & O_NONBLOCK) | 1164 | if (in.file->f_flags & O_NONBLOCK) |
| 1130 | fl = SPLICE_F_NONBLOCK; | 1165 | fl = SPLICE_F_NONBLOCK; |
| 1131 | #endif | 1166 | #endif |
| 1167 | file_start_write(out.file); | ||
| 1132 | retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl); | 1168 | retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl); |
| 1169 | file_end_write(out.file); | ||
| 1133 | 1170 | ||
| 1134 | if (retval > 0) { | 1171 | if (retval > 0) { |
| 1135 | add_rchar(current, retval); | 1172 | add_rchar(current, retval); |
