diff options
Diffstat (limited to 'fs/read_write.c')
-rw-r--r-- | fs/read_write.c | 100 |
1 files changed, 64 insertions, 36 deletions
diff --git a/fs/read_write.c b/fs/read_write.c index 58e440df1bc6..31c6efa43183 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -264,10 +264,22 @@ loff_t vfs_llseek(struct file *file, loff_t offset, int whence) | |||
264 | } | 264 | } |
265 | EXPORT_SYMBOL(vfs_llseek); | 265 | EXPORT_SYMBOL(vfs_llseek); |
266 | 266 | ||
267 | static inline struct fd fdget_pos(int fd) | ||
268 | { | ||
269 | return __to_fd(__fdget_pos(fd)); | ||
270 | } | ||
271 | |||
272 | static inline void fdput_pos(struct fd f) | ||
273 | { | ||
274 | if (f.flags & FDPUT_POS_UNLOCK) | ||
275 | mutex_unlock(&f.file->f_pos_lock); | ||
276 | fdput(f); | ||
277 | } | ||
278 | |||
267 | SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) | 279 | SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) |
268 | { | 280 | { |
269 | off_t retval; | 281 | off_t retval; |
270 | struct fd f = fdget(fd); | 282 | struct fd f = fdget_pos(fd); |
271 | if (!f.file) | 283 | if (!f.file) |
272 | return -EBADF; | 284 | return -EBADF; |
273 | 285 | ||
@@ -278,7 +290,7 @@ SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) | |||
278 | if (res != (loff_t)retval) | 290 | if (res != (loff_t)retval) |
279 | retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ | 291 | retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ |
280 | } | 292 | } |
281 | fdput(f); | 293 | fdput_pos(f); |
282 | return retval; | 294 | return retval; |
283 | } | 295 | } |
284 | 296 | ||
@@ -295,7 +307,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high, | |||
295 | unsigned int, whence) | 307 | unsigned int, whence) |
296 | { | 308 | { |
297 | int retval; | 309 | int retval; |
298 | struct fd f = fdget(fd); | 310 | struct fd f = fdget_pos(fd); |
299 | loff_t offset; | 311 | loff_t offset; |
300 | 312 | ||
301 | if (!f.file) | 313 | if (!f.file) |
@@ -315,7 +327,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high, | |||
315 | retval = 0; | 327 | retval = 0; |
316 | } | 328 | } |
317 | out_putf: | 329 | out_putf: |
318 | fdput(f); | 330 | fdput_pos(f); |
319 | return retval; | 331 | return retval; |
320 | } | 332 | } |
321 | #endif | 333 | #endif |
@@ -498,7 +510,7 @@ static inline void file_pos_write(struct file *file, loff_t pos) | |||
498 | 510 | ||
499 | SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) | 511 | SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) |
500 | { | 512 | { |
501 | struct fd f = fdget(fd); | 513 | struct fd f = fdget_pos(fd); |
502 | ssize_t ret = -EBADF; | 514 | ssize_t ret = -EBADF; |
503 | 515 | ||
504 | if (f.file) { | 516 | if (f.file) { |
@@ -506,7 +518,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) | |||
506 | ret = vfs_read(f.file, buf, count, &pos); | 518 | ret = vfs_read(f.file, buf, count, &pos); |
507 | if (ret >= 0) | 519 | if (ret >= 0) |
508 | file_pos_write(f.file, pos); | 520 | file_pos_write(f.file, pos); |
509 | fdput(f); | 521 | fdput_pos(f); |
510 | } | 522 | } |
511 | return ret; | 523 | return ret; |
512 | } | 524 | } |
@@ -514,7 +526,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) | |||
514 | SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, | 526 | SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, |
515 | size_t, count) | 527 | size_t, count) |
516 | { | 528 | { |
517 | struct fd f = fdget(fd); | 529 | struct fd f = fdget_pos(fd); |
518 | ssize_t ret = -EBADF; | 530 | ssize_t ret = -EBADF; |
519 | 531 | ||
520 | if (f.file) { | 532 | if (f.file) { |
@@ -522,7 +534,7 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, | |||
522 | ret = vfs_write(f.file, buf, count, &pos); | 534 | ret = vfs_write(f.file, buf, count, &pos); |
523 | if (ret >= 0) | 535 | if (ret >= 0) |
524 | file_pos_write(f.file, pos); | 536 | file_pos_write(f.file, pos); |
525 | fdput(f); | 537 | fdput_pos(f); |
526 | } | 538 | } |
527 | 539 | ||
528 | return ret; | 540 | return ret; |
@@ -797,7 +809,7 @@ EXPORT_SYMBOL(vfs_writev); | |||
797 | SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, | 809 | SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, |
798 | unsigned long, vlen) | 810 | unsigned long, vlen) |
799 | { | 811 | { |
800 | struct fd f = fdget(fd); | 812 | struct fd f = fdget_pos(fd); |
801 | ssize_t ret = -EBADF; | 813 | ssize_t ret = -EBADF; |
802 | 814 | ||
803 | if (f.file) { | 815 | if (f.file) { |
@@ -805,7 +817,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, | |||
805 | ret = vfs_readv(f.file, vec, vlen, &pos); | 817 | ret = vfs_readv(f.file, vec, vlen, &pos); |
806 | if (ret >= 0) | 818 | if (ret >= 0) |
807 | file_pos_write(f.file, pos); | 819 | file_pos_write(f.file, pos); |
808 | fdput(f); | 820 | fdput_pos(f); |
809 | } | 821 | } |
810 | 822 | ||
811 | if (ret > 0) | 823 | if (ret > 0) |
@@ -817,7 +829,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, | |||
817 | SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, | 829 | SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, |
818 | unsigned long, vlen) | 830 | unsigned long, vlen) |
819 | { | 831 | { |
820 | struct fd f = fdget(fd); | 832 | struct fd f = fdget_pos(fd); |
821 | ssize_t ret = -EBADF; | 833 | ssize_t ret = -EBADF; |
822 | 834 | ||
823 | if (f.file) { | 835 | if (f.file) { |
@@ -825,7 +837,7 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, | |||
825 | ret = vfs_writev(f.file, vec, vlen, &pos); | 837 | ret = vfs_writev(f.file, vec, vlen, &pos); |
826 | if (ret >= 0) | 838 | if (ret >= 0) |
827 | file_pos_write(f.file, pos); | 839 | file_pos_write(f.file, pos); |
828 | fdput(f); | 840 | fdput_pos(f); |
829 | } | 841 | } |
830 | 842 | ||
831 | if (ret > 0) | 843 | if (ret > 0) |
@@ -901,10 +913,6 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, | |||
901 | io_fn_t fn; | 913 | io_fn_t fn; |
902 | iov_fn_t fnv; | 914 | iov_fn_t fnv; |
903 | 915 | ||
904 | ret = -EFAULT; | ||
905 | if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector))) | ||
906 | goto out; | ||
907 | |||
908 | ret = compat_rw_copy_check_uvector(type, uvector, nr_segs, | 916 | ret = compat_rw_copy_check_uvector(type, uvector, nr_segs, |
909 | UIO_FASTIOV, iovstack, &iov); | 917 | UIO_FASTIOV, iovstack, &iov); |
910 | if (ret <= 0) | 918 | if (ret <= 0) |
@@ -968,11 +976,11 @@ out: | |||
968 | return ret; | 976 | return ret; |
969 | } | 977 | } |
970 | 978 | ||
971 | COMPAT_SYSCALL_DEFINE3(readv, unsigned long, fd, | 979 | COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd, |
972 | const struct compat_iovec __user *,vec, | 980 | const struct compat_iovec __user *,vec, |
973 | unsigned long, vlen) | 981 | compat_ulong_t, vlen) |
974 | { | 982 | { |
975 | struct fd f = fdget(fd); | 983 | struct fd f = fdget_pos(fd); |
976 | ssize_t ret; | 984 | ssize_t ret; |
977 | loff_t pos; | 985 | loff_t pos; |
978 | 986 | ||
@@ -982,13 +990,13 @@ COMPAT_SYSCALL_DEFINE3(readv, unsigned long, fd, | |||
982 | ret = compat_readv(f.file, vec, vlen, &pos); | 990 | ret = compat_readv(f.file, vec, vlen, &pos); |
983 | if (ret >= 0) | 991 | if (ret >= 0) |
984 | f.file->f_pos = pos; | 992 | f.file->f_pos = pos; |
985 | fdput(f); | 993 | fdput_pos(f); |
986 | return ret; | 994 | return ret; |
987 | } | 995 | } |
988 | 996 | ||
989 | COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd, | 997 | static long __compat_sys_preadv64(unsigned long fd, |
990 | const struct compat_iovec __user *,vec, | 998 | const struct compat_iovec __user *vec, |
991 | unsigned long, vlen, loff_t, pos) | 999 | unsigned long vlen, loff_t pos) |
992 | { | 1000 | { |
993 | struct fd f; | 1001 | struct fd f; |
994 | ssize_t ret; | 1002 | ssize_t ret; |
@@ -1005,12 +1013,22 @@ COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd, | |||
1005 | return ret; | 1013 | return ret; |
1006 | } | 1014 | } |
1007 | 1015 | ||
1008 | COMPAT_SYSCALL_DEFINE5(preadv, unsigned long, fd, | 1016 | #ifdef __ARCH_WANT_COMPAT_SYS_PREADV64 |
1017 | COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd, | ||
1009 | const struct compat_iovec __user *,vec, | 1018 | const struct compat_iovec __user *,vec, |
1010 | unsigned long, vlen, u32, pos_low, u32, pos_high) | 1019 | unsigned long, vlen, loff_t, pos) |
1020 | { | ||
1021 | return __compat_sys_preadv64(fd, vec, vlen, pos); | ||
1022 | } | ||
1023 | #endif | ||
1024 | |||
1025 | COMPAT_SYSCALL_DEFINE5(preadv, compat_ulong_t, fd, | ||
1026 | const struct compat_iovec __user *,vec, | ||
1027 | compat_ulong_t, vlen, u32, pos_low, u32, pos_high) | ||
1011 | { | 1028 | { |
1012 | loff_t pos = ((loff_t)pos_high << 32) | pos_low; | 1029 | loff_t pos = ((loff_t)pos_high << 32) | pos_low; |
1013 | return compat_sys_preadv64(fd, vec, vlen, pos); | 1030 | |
1031 | return __compat_sys_preadv64(fd, vec, vlen, pos); | ||
1014 | } | 1032 | } |
1015 | 1033 | ||
1016 | static size_t compat_writev(struct file *file, | 1034 | static size_t compat_writev(struct file *file, |
@@ -1035,11 +1053,11 @@ out: | |||
1035 | return ret; | 1053 | return ret; |
1036 | } | 1054 | } |
1037 | 1055 | ||
1038 | COMPAT_SYSCALL_DEFINE3(writev, unsigned long, fd, | 1056 | COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd, |
1039 | const struct compat_iovec __user *, vec, | 1057 | const struct compat_iovec __user *, vec, |
1040 | unsigned long, vlen) | 1058 | compat_ulong_t, vlen) |
1041 | { | 1059 | { |
1042 | struct fd f = fdget(fd); | 1060 | struct fd f = fdget_pos(fd); |
1043 | ssize_t ret; | 1061 | ssize_t ret; |
1044 | loff_t pos; | 1062 | loff_t pos; |
1045 | 1063 | ||
@@ -1049,13 +1067,13 @@ COMPAT_SYSCALL_DEFINE3(writev, unsigned long, fd, | |||
1049 | ret = compat_writev(f.file, vec, vlen, &pos); | 1067 | ret = compat_writev(f.file, vec, vlen, &pos); |
1050 | if (ret >= 0) | 1068 | if (ret >= 0) |
1051 | f.file->f_pos = pos; | 1069 | f.file->f_pos = pos; |
1052 | fdput(f); | 1070 | fdput_pos(f); |
1053 | return ret; | 1071 | return ret; |
1054 | } | 1072 | } |
1055 | 1073 | ||
1056 | COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd, | 1074 | static long __compat_sys_pwritev64(unsigned long fd, |
1057 | const struct compat_iovec __user *,vec, | 1075 | const struct compat_iovec __user *vec, |
1058 | unsigned long, vlen, loff_t, pos) | 1076 | unsigned long vlen, loff_t pos) |
1059 | { | 1077 | { |
1060 | struct fd f; | 1078 | struct fd f; |
1061 | ssize_t ret; | 1079 | ssize_t ret; |
@@ -1072,12 +1090,22 @@ COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd, | |||
1072 | return ret; | 1090 | return ret; |
1073 | } | 1091 | } |
1074 | 1092 | ||
1075 | COMPAT_SYSCALL_DEFINE5(pwritev, unsigned long, fd, | 1093 | #ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64 |
1094 | COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd, | ||
1095 | const struct compat_iovec __user *,vec, | ||
1096 | unsigned long, vlen, loff_t, pos) | ||
1097 | { | ||
1098 | return __compat_sys_pwritev64(fd, vec, vlen, pos); | ||
1099 | } | ||
1100 | #endif | ||
1101 | |||
1102 | COMPAT_SYSCALL_DEFINE5(pwritev, compat_ulong_t, fd, | ||
1076 | const struct compat_iovec __user *,vec, | 1103 | const struct compat_iovec __user *,vec, |
1077 | unsigned long, vlen, u32, pos_low, u32, pos_high) | 1104 | compat_ulong_t, vlen, u32, pos_low, u32, pos_high) |
1078 | { | 1105 | { |
1079 | loff_t pos = ((loff_t)pos_high << 32) | pos_low; | 1106 | loff_t pos = ((loff_t)pos_high << 32) | pos_low; |
1080 | return compat_sys_pwritev64(fd, vec, vlen, pos); | 1107 | |
1108 | return __compat_sys_pwritev64(fd, vec, vlen, pos); | ||
1081 | } | 1109 | } |
1082 | #endif | 1110 | #endif |
1083 | 1111 | ||