aboutsummaryrefslogtreecommitdiffstats
path: root/fs/read_write.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/read_write.c')
-rw-r--r--fs/read_write.c65
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
44static 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 */
56loff_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}
69EXPORT_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
76generic_file_llseek_size(struct file *file, loff_t offset, int whence, 88generic_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}
125EXPORT_SYMBOL(generic_file_llseek_size); 134EXPORT_SYMBOL(generic_file_llseek_size);
126 135
@@ -145,6 +154,26 @@ loff_t generic_file_llseek(struct file *file, loff_t offset, int whence)
145EXPORT_SYMBOL(generic_file_llseek); 154EXPORT_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 */
164loff_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}
174EXPORT_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 */
299int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count) 328int 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);