diff options
Diffstat (limited to 'fs/read_write.c')
-rw-r--r-- | fs/read_write.c | 89 |
1 files changed, 67 insertions, 22 deletions
diff --git a/fs/read_write.c b/fs/read_write.c index 03430008704e..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 | } |
@@ -1064,6 +1099,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
1064 | struct fd in, out; | 1099 | struct fd in, out; |
1065 | struct inode *in_inode, *out_inode; | 1100 | struct inode *in_inode, *out_inode; |
1066 | loff_t pos; | 1101 | loff_t pos; |
1102 | loff_t out_pos; | ||
1067 | ssize_t retval; | 1103 | ssize_t retval; |
1068 | int fl; | 1104 | int fl; |
1069 | 1105 | ||
@@ -1077,12 +1113,14 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
1077 | if (!(in.file->f_mode & FMODE_READ)) | 1113 | if (!(in.file->f_mode & FMODE_READ)) |
1078 | goto fput_in; | 1114 | goto fput_in; |
1079 | retval = -ESPIPE; | 1115 | retval = -ESPIPE; |
1080 | if (!ppos) | 1116 | if (!ppos) { |
1081 | ppos = &in.file->f_pos; | 1117 | pos = in.file->f_pos; |
1082 | else | 1118 | } else { |
1119 | pos = *ppos; | ||
1083 | if (!(in.file->f_mode & FMODE_PREAD)) | 1120 | if (!(in.file->f_mode & FMODE_PREAD)) |
1084 | goto fput_in; | 1121 | goto fput_in; |
1085 | retval = rw_verify_area(READ, in.file, ppos, count); | 1122 | } |
1123 | retval = rw_verify_area(READ, in.file, &pos, count); | ||
1086 | if (retval < 0) | 1124 | if (retval < 0) |
1087 | goto fput_in; | 1125 | goto fput_in; |
1088 | count = retval; | 1126 | count = retval; |
@@ -1099,7 +1137,8 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
1099 | retval = -EINVAL; | 1137 | retval = -EINVAL; |
1100 | in_inode = file_inode(in.file); | 1138 | in_inode = file_inode(in.file); |
1101 | out_inode = file_inode(out.file); | 1139 | out_inode = file_inode(out.file); |
1102 | retval = rw_verify_area(WRITE, out.file, &out.file->f_pos, count); | 1140 | out_pos = out.file->f_pos; |
1141 | retval = rw_verify_area(WRITE, out.file, &out_pos, count); | ||
1103 | if (retval < 0) | 1142 | if (retval < 0) |
1104 | goto fput_out; | 1143 | goto fput_out; |
1105 | count = retval; | 1144 | count = retval; |
@@ -1107,7 +1146,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
1107 | if (!max) | 1146 | if (!max) |
1108 | max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); | 1147 | max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); |
1109 | 1148 | ||
1110 | pos = *ppos; | ||
1111 | if (unlikely(pos + count > max)) { | 1149 | if (unlikely(pos + count > max)) { |
1112 | retval = -EOVERFLOW; | 1150 | retval = -EOVERFLOW; |
1113 | if (pos >= max) | 1151 | if (pos >= max) |
@@ -1126,18 +1164,25 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
1126 | if (in.file->f_flags & O_NONBLOCK) | 1164 | if (in.file->f_flags & O_NONBLOCK) |
1127 | fl = SPLICE_F_NONBLOCK; | 1165 | fl = SPLICE_F_NONBLOCK; |
1128 | #endif | 1166 | #endif |
1129 | retval = do_splice_direct(in.file, ppos, out.file, count, fl); | 1167 | file_start_write(out.file); |
1168 | retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl); | ||
1169 | file_end_write(out.file); | ||
1130 | 1170 | ||
1131 | if (retval > 0) { | 1171 | if (retval > 0) { |
1132 | add_rchar(current, retval); | 1172 | add_rchar(current, retval); |
1133 | add_wchar(current, retval); | 1173 | add_wchar(current, retval); |
1134 | fsnotify_access(in.file); | 1174 | fsnotify_access(in.file); |
1135 | fsnotify_modify(out.file); | 1175 | fsnotify_modify(out.file); |
1176 | out.file->f_pos = out_pos; | ||
1177 | if (ppos) | ||
1178 | *ppos = pos; | ||
1179 | else | ||
1180 | in.file->f_pos = pos; | ||
1136 | } | 1181 | } |
1137 | 1182 | ||
1138 | inc_syscr(current); | 1183 | inc_syscr(current); |
1139 | inc_syscw(current); | 1184 | inc_syscw(current); |
1140 | if (*ppos > max) | 1185 | if (pos > max) |
1141 | retval = -EOVERFLOW; | 1186 | retval = -EOVERFLOW; |
1142 | 1187 | ||
1143 | fput_out: | 1188 | fput_out: |