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); |