diff options
Diffstat (limited to 'fs/read_write.c')
-rw-r--r-- | fs/read_write.c | 54 |
1 files changed, 40 insertions, 14 deletions
diff --git a/fs/read_write.c b/fs/read_write.c index edc5746a902a..932bb3414a96 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -264,10 +264,36 @@ 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 | /* | ||
268 | * We only lock f_pos if we have threads or if the file might be | ||
269 | * shared with another process. In both cases we'll have an elevated | ||
270 | * file count (done either by fdget() or by fork()). | ||
271 | */ | ||
272 | static inline struct fd fdget_pos(int fd) | ||
273 | { | ||
274 | struct fd f = fdget(fd); | ||
275 | struct file *file = f.file; | ||
276 | |||
277 | if (file && (file->f_mode & FMODE_ATOMIC_POS)) { | ||
278 | if (file_count(file) > 1) { | ||
279 | f.flags |= FDPUT_POS_UNLOCK; | ||
280 | mutex_lock(&file->f_pos_lock); | ||
281 | } | ||
282 | } | ||
283 | return f; | ||
284 | } | ||
285 | |||
286 | static inline void fdput_pos(struct fd f) | ||
287 | { | ||
288 | if (f.flags & FDPUT_POS_UNLOCK) | ||
289 | mutex_unlock(&f.file->f_pos_lock); | ||
290 | fdput(f); | ||
291 | } | ||
292 | |||
267 | SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) | 293 | SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) |
268 | { | 294 | { |
269 | off_t retval; | 295 | off_t retval; |
270 | struct fd f = fdget(fd); | 296 | struct fd f = fdget_pos(fd); |
271 | if (!f.file) | 297 | if (!f.file) |
272 | return -EBADF; | 298 | return -EBADF; |
273 | 299 | ||
@@ -278,7 +304,7 @@ SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) | |||
278 | if (res != (loff_t)retval) | 304 | if (res != (loff_t)retval) |
279 | retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ | 305 | retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ |
280 | } | 306 | } |
281 | fdput(f); | 307 | fdput_pos(f); |
282 | return retval; | 308 | return retval; |
283 | } | 309 | } |
284 | 310 | ||
@@ -498,7 +524,7 @@ static inline void file_pos_write(struct file *file, loff_t pos) | |||
498 | 524 | ||
499 | SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) | 525 | SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) |
500 | { | 526 | { |
501 | struct fd f = fdget(fd); | 527 | struct fd f = fdget_pos(fd); |
502 | ssize_t ret = -EBADF; | 528 | ssize_t ret = -EBADF; |
503 | 529 | ||
504 | if (f.file) { | 530 | if (f.file) { |
@@ -506,7 +532,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) | |||
506 | ret = vfs_read(f.file, buf, count, &pos); | 532 | ret = vfs_read(f.file, buf, count, &pos); |
507 | if (ret >= 0) | 533 | if (ret >= 0) |
508 | file_pos_write(f.file, pos); | 534 | file_pos_write(f.file, pos); |
509 | fdput(f); | 535 | fdput_pos(f); |
510 | } | 536 | } |
511 | return ret; | 537 | return ret; |
512 | } | 538 | } |
@@ -514,7 +540,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) | |||
514 | SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, | 540 | SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, |
515 | size_t, count) | 541 | size_t, count) |
516 | { | 542 | { |
517 | struct fd f = fdget(fd); | 543 | struct fd f = fdget_pos(fd); |
518 | ssize_t ret = -EBADF; | 544 | ssize_t ret = -EBADF; |
519 | 545 | ||
520 | if (f.file) { | 546 | if (f.file) { |
@@ -522,7 +548,7 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, | |||
522 | ret = vfs_write(f.file, buf, count, &pos); | 548 | ret = vfs_write(f.file, buf, count, &pos); |
523 | if (ret >= 0) | 549 | if (ret >= 0) |
524 | file_pos_write(f.file, pos); | 550 | file_pos_write(f.file, pos); |
525 | fdput(f); | 551 | fdput_pos(f); |
526 | } | 552 | } |
527 | 553 | ||
528 | return ret; | 554 | return ret; |
@@ -797,7 +823,7 @@ EXPORT_SYMBOL(vfs_writev); | |||
797 | SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, | 823 | SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, |
798 | unsigned long, vlen) | 824 | unsigned long, vlen) |
799 | { | 825 | { |
800 | struct fd f = fdget(fd); | 826 | struct fd f = fdget_pos(fd); |
801 | ssize_t ret = -EBADF; | 827 | ssize_t ret = -EBADF; |
802 | 828 | ||
803 | if (f.file) { | 829 | if (f.file) { |
@@ -805,7 +831,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, | |||
805 | ret = vfs_readv(f.file, vec, vlen, &pos); | 831 | ret = vfs_readv(f.file, vec, vlen, &pos); |
806 | if (ret >= 0) | 832 | if (ret >= 0) |
807 | file_pos_write(f.file, pos); | 833 | file_pos_write(f.file, pos); |
808 | fdput(f); | 834 | fdput_pos(f); |
809 | } | 835 | } |
810 | 836 | ||
811 | if (ret > 0) | 837 | if (ret > 0) |
@@ -817,7 +843,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, | |||
817 | SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, | 843 | SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, |
818 | unsigned long, vlen) | 844 | unsigned long, vlen) |
819 | { | 845 | { |
820 | struct fd f = fdget(fd); | 846 | struct fd f = fdget_pos(fd); |
821 | ssize_t ret = -EBADF; | 847 | ssize_t ret = -EBADF; |
822 | 848 | ||
823 | if (f.file) { | 849 | if (f.file) { |
@@ -825,7 +851,7 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, | |||
825 | ret = vfs_writev(f.file, vec, vlen, &pos); | 851 | ret = vfs_writev(f.file, vec, vlen, &pos); |
826 | if (ret >= 0) | 852 | if (ret >= 0) |
827 | file_pos_write(f.file, pos); | 853 | file_pos_write(f.file, pos); |
828 | fdput(f); | 854 | fdput_pos(f); |
829 | } | 855 | } |
830 | 856 | ||
831 | if (ret > 0) | 857 | if (ret > 0) |
@@ -968,7 +994,7 @@ COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd, | |||
968 | const struct compat_iovec __user *,vec, | 994 | const struct compat_iovec __user *,vec, |
969 | compat_ulong_t, vlen) | 995 | compat_ulong_t, vlen) |
970 | { | 996 | { |
971 | struct fd f = fdget(fd); | 997 | struct fd f = fdget_pos(fd); |
972 | ssize_t ret; | 998 | ssize_t ret; |
973 | loff_t pos; | 999 | loff_t pos; |
974 | 1000 | ||
@@ -978,7 +1004,7 @@ COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd, | |||
978 | ret = compat_readv(f.file, vec, vlen, &pos); | 1004 | ret = compat_readv(f.file, vec, vlen, &pos); |
979 | if (ret >= 0) | 1005 | if (ret >= 0) |
980 | f.file->f_pos = pos; | 1006 | f.file->f_pos = pos; |
981 | fdput(f); | 1007 | fdput_pos(f); |
982 | return ret; | 1008 | return ret; |
983 | } | 1009 | } |
984 | 1010 | ||
@@ -1035,7 +1061,7 @@ COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd, | |||
1035 | const struct compat_iovec __user *, vec, | 1061 | const struct compat_iovec __user *, vec, |
1036 | compat_ulong_t, vlen) | 1062 | compat_ulong_t, vlen) |
1037 | { | 1063 | { |
1038 | struct fd f = fdget(fd); | 1064 | struct fd f = fdget_pos(fd); |
1039 | ssize_t ret; | 1065 | ssize_t ret; |
1040 | loff_t pos; | 1066 | loff_t pos; |
1041 | 1067 | ||
@@ -1045,7 +1071,7 @@ COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd, | |||
1045 | ret = compat_writev(f.file, vec, vlen, &pos); | 1071 | ret = compat_writev(f.file, vec, vlen, &pos); |
1046 | if (ret >= 0) | 1072 | if (ret >= 0) |
1047 | f.file->f_pos = pos; | 1073 | f.file->f_pos = pos; |
1048 | fdput(f); | 1074 | fdput_pos(f); |
1049 | return ret; | 1075 | return ret; |
1050 | } | 1076 | } |
1051 | 1077 | ||