diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-05 17:35:57 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-05 17:35:57 -0400 |
| commit | 89fbf5384ddf666a595eb6562dc63fcbfeb8f6a5 (patch) | |
| tree | fc2de270b1dae61f850e9aff0784a672667e2acc /fs/read_write.c | |
| parent | 4be95131bf3bca97b6a7db9c6fb63db2cb94da06 (diff) | |
| parent | a4058c5bce8aded1a12a59990e84e481a96fb490 (diff) | |
Merge branch 'work.read_write' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull read/write updates from Al Viro:
"Christoph's fs/read_write.c series - consolidation and cleanups"
* 'work.read_write' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
nfsd: remove nfsd_vfs_read
nfsd: use vfs_iter_read/write
fs: implement vfs_iter_write using do_iter_write
fs: implement vfs_iter_read using do_iter_read
fs: move more code into do_iter_read/do_iter_write
fs: remove __do_readv_writev
fs: remove do_compat_readv_writev
fs: remove do_readv_writev
Diffstat (limited to 'fs/read_write.c')
| -rw-r--r-- | fs/read_write.c | 220 |
1 files changed, 91 insertions, 129 deletions
diff --git a/fs/read_write.c b/fs/read_write.c index d591eeed061f..a2cbc8303dae 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
| @@ -356,46 +356,6 @@ out_putf: | |||
| 356 | } | 356 | } |
| 357 | #endif | 357 | #endif |
| 358 | 358 | ||
| 359 | ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos) | ||
| 360 | { | ||
| 361 | struct kiocb kiocb; | ||
| 362 | ssize_t ret; | ||
| 363 | |||
| 364 | if (!file->f_op->read_iter) | ||
| 365 | return -EINVAL; | ||
| 366 | |||
| 367 | init_sync_kiocb(&kiocb, file); | ||
| 368 | kiocb.ki_pos = *ppos; | ||
| 369 | |||
| 370 | iter->type |= READ; | ||
| 371 | ret = call_read_iter(file, &kiocb, iter); | ||
| 372 | BUG_ON(ret == -EIOCBQUEUED); | ||
| 373 | if (ret > 0) | ||
| 374 | *ppos = kiocb.ki_pos; | ||
| 375 | return ret; | ||
| 376 | } | ||
| 377 | EXPORT_SYMBOL(vfs_iter_read); | ||
| 378 | |||
| 379 | ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos) | ||
| 380 | { | ||
| 381 | struct kiocb kiocb; | ||
| 382 | ssize_t ret; | ||
| 383 | |||
| 384 | if (!file->f_op->write_iter) | ||
| 385 | return -EINVAL; | ||
| 386 | |||
| 387 | init_sync_kiocb(&kiocb, file); | ||
| 388 | kiocb.ki_pos = *ppos; | ||
| 389 | |||
| 390 | iter->type |= WRITE; | ||
| 391 | ret = call_write_iter(file, &kiocb, iter); | ||
| 392 | BUG_ON(ret == -EIOCBQUEUED); | ||
| 393 | if (ret > 0) | ||
| 394 | *ppos = kiocb.ki_pos; | ||
| 395 | return ret; | ||
| 396 | } | ||
| 397 | EXPORT_SYMBOL(vfs_iter_write); | ||
| 398 | |||
| 399 | int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count) | 359 | int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count) |
| 400 | { | 360 | { |
| 401 | struct inode *inode; | 361 | struct inode *inode; |
| @@ -910,86 +870,114 @@ out: | |||
| 910 | } | 870 | } |
| 911 | #endif | 871 | #endif |
| 912 | 872 | ||
| 913 | static ssize_t __do_readv_writev(int type, struct file *file, | 873 | static ssize_t do_iter_read(struct file *file, struct iov_iter *iter, |
| 914 | struct iov_iter *iter, loff_t *pos, int flags) | 874 | loff_t *pos, int flags) |
| 915 | { | 875 | { |
| 916 | size_t tot_len; | 876 | size_t tot_len; |
| 917 | ssize_t ret = 0; | 877 | ssize_t ret = 0; |
| 918 | 878 | ||
| 879 | if (!(file->f_mode & FMODE_READ)) | ||
| 880 | return -EBADF; | ||
| 881 | if (!(file->f_mode & FMODE_CAN_READ)) | ||
| 882 | return -EINVAL; | ||
| 883 | |||
| 919 | tot_len = iov_iter_count(iter); | 884 | tot_len = iov_iter_count(iter); |
| 920 | if (!tot_len) | 885 | if (!tot_len) |
| 921 | goto out; | 886 | goto out; |
| 922 | ret = rw_verify_area(type, file, pos, tot_len); | 887 | ret = rw_verify_area(READ, file, pos, tot_len); |
| 923 | if (ret < 0) | 888 | if (ret < 0) |
| 924 | goto out; | 889 | return ret; |
| 925 | |||
| 926 | if (type != READ) | ||
| 927 | file_start_write(file); | ||
| 928 | 890 | ||
| 929 | if ((type == READ && file->f_op->read_iter) || | 891 | if (file->f_op->read_iter) |
| 930 | (type == WRITE && file->f_op->write_iter)) | 892 | ret = do_iter_readv_writev(file, iter, pos, READ, flags); |
| 931 | ret = do_iter_readv_writev(file, iter, pos, type, flags); | ||
| 932 | else | 893 | else |
| 933 | ret = do_loop_readv_writev(file, iter, pos, type, flags); | 894 | ret = do_loop_readv_writev(file, iter, pos, READ, flags); |
| 934 | |||
| 935 | if (type != READ) | ||
| 936 | file_end_write(file); | ||
| 937 | |||
| 938 | out: | 895 | out: |
| 939 | if ((ret + (type == READ)) > 0) { | 896 | if (ret >= 0) |
| 940 | if (type == READ) | 897 | fsnotify_access(file); |
| 941 | fsnotify_access(file); | ||
| 942 | else | ||
| 943 | fsnotify_modify(file); | ||
| 944 | } | ||
| 945 | return ret; | 898 | return ret; |
| 946 | } | 899 | } |
| 947 | 900 | ||
| 948 | static ssize_t do_readv_writev(int type, struct file *file, | 901 | ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos, |
| 949 | const struct iovec __user *uvector, | 902 | int flags) |
| 950 | unsigned long nr_segs, loff_t *pos, | ||
| 951 | int flags) | ||
| 952 | { | 903 | { |
| 953 | struct iovec iovstack[UIO_FASTIOV]; | 904 | if (!file->f_op->read_iter) |
| 954 | struct iovec *iov = iovstack; | 905 | return -EINVAL; |
| 955 | struct iov_iter iter; | 906 | return do_iter_read(file, iter, ppos, flags); |
| 956 | ssize_t ret; | 907 | } |
| 908 | EXPORT_SYMBOL(vfs_iter_read); | ||
| 909 | |||
| 910 | static ssize_t do_iter_write(struct file *file, struct iov_iter *iter, | ||
| 911 | loff_t *pos, int flags) | ||
| 912 | { | ||
| 913 | size_t tot_len; | ||
| 914 | ssize_t ret = 0; | ||
| 915 | |||
| 916 | if (!(file->f_mode & FMODE_WRITE)) | ||
| 917 | return -EBADF; | ||
| 918 | if (!(file->f_mode & FMODE_CAN_WRITE)) | ||
| 919 | return -EINVAL; | ||
| 957 | 920 | ||
| 958 | ret = import_iovec(type, uvector, nr_segs, | 921 | tot_len = iov_iter_count(iter); |
| 959 | ARRAY_SIZE(iovstack), &iov, &iter); | 922 | if (!tot_len) |
| 923 | return 0; | ||
| 924 | ret = rw_verify_area(WRITE, file, pos, tot_len); | ||
| 960 | if (ret < 0) | 925 | if (ret < 0) |
| 961 | return ret; | 926 | return ret; |
| 962 | 927 | ||
| 963 | ret = __do_readv_writev(type, file, &iter, pos, flags); | 928 | file_start_write(file); |
| 964 | kfree(iov); | 929 | if (file->f_op->write_iter) |
| 965 | 930 | ret = do_iter_readv_writev(file, iter, pos, WRITE, flags); | |
| 931 | else | ||
| 932 | ret = do_loop_readv_writev(file, iter, pos, WRITE, flags); | ||
| 933 | file_end_write(file); | ||
| 934 | if (ret > 0) | ||
| 935 | fsnotify_modify(file); | ||
| 966 | return ret; | 936 | return ret; |
| 967 | } | 937 | } |
| 968 | 938 | ||
| 939 | ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos, | ||
| 940 | int flags) | ||
| 941 | { | ||
| 942 | if (!file->f_op->write_iter) | ||
| 943 | return -EINVAL; | ||
| 944 | return do_iter_write(file, iter, ppos, flags); | ||
| 945 | } | ||
| 946 | EXPORT_SYMBOL(vfs_iter_write); | ||
| 947 | |||
| 969 | ssize_t vfs_readv(struct file *file, const struct iovec __user *vec, | 948 | ssize_t vfs_readv(struct file *file, const struct iovec __user *vec, |
| 970 | unsigned long vlen, loff_t *pos, int flags) | 949 | unsigned long vlen, loff_t *pos, int flags) |
| 971 | { | 950 | { |
| 972 | if (!(file->f_mode & FMODE_READ)) | 951 | struct iovec iovstack[UIO_FASTIOV]; |
| 973 | return -EBADF; | 952 | struct iovec *iov = iovstack; |
| 974 | if (!(file->f_mode & FMODE_CAN_READ)) | 953 | struct iov_iter iter; |
| 975 | return -EINVAL; | 954 | ssize_t ret; |
| 976 | 955 | ||
| 977 | return do_readv_writev(READ, file, vec, vlen, pos, flags); | 956 | ret = import_iovec(READ, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter); |
| 978 | } | 957 | if (ret >= 0) { |
| 958 | ret = do_iter_read(file, &iter, pos, flags); | ||
| 959 | kfree(iov); | ||
| 960 | } | ||
| 979 | 961 | ||
| 962 | return ret; | ||
| 963 | } | ||
| 980 | EXPORT_SYMBOL(vfs_readv); | 964 | EXPORT_SYMBOL(vfs_readv); |
| 981 | 965 | ||
| 982 | ssize_t vfs_writev(struct file *file, const struct iovec __user *vec, | 966 | ssize_t vfs_writev(struct file *file, const struct iovec __user *vec, |
| 983 | unsigned long vlen, loff_t *pos, int flags) | 967 | unsigned long vlen, loff_t *pos, int flags) |
| 984 | { | 968 | { |
| 985 | if (!(file->f_mode & FMODE_WRITE)) | 969 | struct iovec iovstack[UIO_FASTIOV]; |
| 986 | return -EBADF; | 970 | struct iovec *iov = iovstack; |
| 987 | if (!(file->f_mode & FMODE_CAN_WRITE)) | 971 | struct iov_iter iter; |
| 988 | return -EINVAL; | 972 | ssize_t ret; |
| 989 | 973 | ||
| 990 | return do_readv_writev(WRITE, file, vec, vlen, pos, flags); | 974 | ret = import_iovec(WRITE, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter); |
| 975 | if (ret >= 0) { | ||
| 976 | ret = do_iter_write(file, &iter, pos, flags); | ||
| 977 | kfree(iov); | ||
| 978 | } | ||
| 979 | return ret; | ||
| 991 | } | 980 | } |
| 992 | |||
| 993 | EXPORT_SYMBOL(vfs_writev); | 981 | EXPORT_SYMBOL(vfs_writev); |
| 994 | 982 | ||
| 995 | static ssize_t do_readv(unsigned long fd, const struct iovec __user *vec, | 983 | static ssize_t do_readv(unsigned long fd, const struct iovec __user *vec, |
| @@ -1137,44 +1125,20 @@ SYSCALL_DEFINE6(pwritev2, unsigned long, fd, const struct iovec __user *, vec, | |||
| 1137 | } | 1125 | } |
| 1138 | 1126 | ||
| 1139 | #ifdef CONFIG_COMPAT | 1127 | #ifdef CONFIG_COMPAT |
| 1140 | 1128 | static size_t compat_readv(struct file *file, | |
| 1141 | static ssize_t compat_do_readv_writev(int type, struct file *file, | 1129 | const struct compat_iovec __user *vec, |
| 1142 | const struct compat_iovec __user *uvector, | 1130 | unsigned long vlen, loff_t *pos, int flags) |
| 1143 | unsigned long nr_segs, loff_t *pos, | ||
| 1144 | int flags) | ||
| 1145 | { | 1131 | { |
| 1146 | struct iovec iovstack[UIO_FASTIOV]; | 1132 | struct iovec iovstack[UIO_FASTIOV]; |
| 1147 | struct iovec *iov = iovstack; | 1133 | struct iovec *iov = iovstack; |
| 1148 | struct iov_iter iter; | 1134 | struct iov_iter iter; |
| 1149 | ssize_t ret; | 1135 | ssize_t ret; |
| 1150 | 1136 | ||
| 1151 | ret = compat_import_iovec(type, uvector, nr_segs, | 1137 | ret = compat_import_iovec(READ, vec, vlen, UIO_FASTIOV, &iov, &iter); |
| 1152 | UIO_FASTIOV, &iov, &iter); | 1138 | if (ret >= 0) { |
| 1153 | if (ret < 0) | 1139 | ret = do_iter_read(file, &iter, pos, flags); |
| 1154 | return ret; | 1140 | kfree(iov); |
| 1155 | 1141 | } | |
| 1156 | ret = __do_readv_writev(type, file, &iter, pos, flags); | ||
| 1157 | kfree(iov); | ||
| 1158 | |||
| 1159 | return ret; | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | static size_t compat_readv(struct file *file, | ||
| 1163 | const struct compat_iovec __user *vec, | ||
| 1164 | unsigned long vlen, loff_t *pos, int flags) | ||
| 1165 | { | ||
| 1166 | ssize_t ret = -EBADF; | ||
| 1167 | |||
| 1168 | if (!(file->f_mode & FMODE_READ)) | ||
| 1169 | goto out; | ||
| 1170 | |||
| 1171 | ret = -EINVAL; | ||
| 1172 | if (!(file->f_mode & FMODE_CAN_READ)) | ||
| 1173 | goto out; | ||
| 1174 | |||
| 1175 | ret = compat_do_readv_writev(READ, file, vec, vlen, pos, flags); | ||
| 1176 | |||
| 1177 | out: | ||
| 1178 | if (ret > 0) | 1142 | if (ret > 0) |
| 1179 | add_rchar(current, ret); | 1143 | add_rchar(current, ret); |
| 1180 | inc_syscr(current); | 1144 | inc_syscr(current); |
| @@ -1270,18 +1234,16 @@ static size_t compat_writev(struct file *file, | |||
| 1270 | const struct compat_iovec __user *vec, | 1234 | const struct compat_iovec __user *vec, |
| 1271 | unsigned long vlen, loff_t *pos, int flags) | 1235 | unsigned long vlen, loff_t *pos, int flags) |
| 1272 | { | 1236 | { |
| 1273 | ssize_t ret = -EBADF; | 1237 | struct iovec iovstack[UIO_FASTIOV]; |
| 1274 | 1238 | struct iovec *iov = iovstack; | |
| 1275 | if (!(file->f_mode & FMODE_WRITE)) | 1239 | struct iov_iter iter; |
| 1276 | goto out; | 1240 | ssize_t ret; |
| 1277 | |||
| 1278 | ret = -EINVAL; | ||
| 1279 | if (!(file->f_mode & FMODE_CAN_WRITE)) | ||
| 1280 | goto out; | ||
| 1281 | |||
| 1282 | ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos, flags); | ||
| 1283 | 1241 | ||
| 1284 | out: | 1242 | ret = compat_import_iovec(WRITE, vec, vlen, UIO_FASTIOV, &iov, &iter); |
| 1243 | if (ret >= 0) { | ||
| 1244 | ret = do_iter_write(file, &iter, pos, flags); | ||
| 1245 | kfree(iov); | ||
| 1246 | } | ||
| 1285 | if (ret > 0) | 1247 | if (ret > 0) |
| 1286 | add_wchar(current, ret); | 1248 | add_wchar(current, ret); |
| 1287 | inc_syscw(current); | 1249 | inc_syscw(current); |
