aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/file.c56
-rw-r--r--fs/file_table.c1
-rw-r--r--fs/namei.c2
-rw-r--r--fs/ocfs2/file.c8
-rw-r--r--fs/open.c4
-rw-r--r--fs/read_write.c40
-rw-r--r--include/linux/file.h27
-rw-r--r--include/linux/fs.h8
-rw-r--r--net/socket.c13
9 files changed, 107 insertions, 52 deletions
diff --git a/fs/file.c b/fs/file.c
index db25c2bdfe46..60a45e9f5323 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -683,35 +683,65 @@ EXPORT_SYMBOL(fget_raw);
683 * The fput_needed flag returned by fget_light should be passed to the 683 * The fput_needed flag returned by fget_light should be passed to the
684 * corresponding fput_light. 684 * corresponding fput_light.
685 */ 685 */
686struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed) 686static unsigned long __fget_light(unsigned int fd, fmode_t mask)
687{ 687{
688 struct files_struct *files = current->files; 688 struct files_struct *files = current->files;
689 struct file *file; 689 struct file *file;
690 690
691 *fput_needed = 0;
692 if (atomic_read(&files->count) == 1) { 691 if (atomic_read(&files->count) == 1) {
693 file = __fcheck_files(files, fd); 692 file = __fcheck_files(files, fd);
694 if (file && (file->f_mode & mask)) 693 if (!file || unlikely(file->f_mode & mask))
695 file = NULL; 694 return 0;
695 return (unsigned long)file;
696 } else { 696 } else {
697 file = __fget(fd, mask); 697 file = __fget(fd, mask);
698 if (file) 698 if (!file)
699 *fput_needed = 1; 699 return 0;
700 return FDPUT_FPUT | (unsigned long)file;
700 } 701 }
701
702 return file;
703} 702}
704struct file *fget_light(unsigned int fd, int *fput_needed) 703unsigned long __fdget(unsigned int fd)
705{ 704{
706 return __fget_light(fd, FMODE_PATH, fput_needed); 705 return __fget_light(fd, FMODE_PATH);
707} 706}
708EXPORT_SYMBOL(fget_light); 707EXPORT_SYMBOL(__fdget);
709 708
710struct file *fget_raw_light(unsigned int fd, int *fput_needed) 709unsigned long __fdget_raw(unsigned int fd)
711{ 710{
712 return __fget_light(fd, 0, fput_needed); 711 return __fget_light(fd, 0);
712}
713
714unsigned long __fdget_pos(unsigned int fd)
715{
716 struct files_struct *files = current->files;
717 struct file *file;
718 unsigned long v;
719
720 if (atomic_read(&files->count) == 1) {
721 file = __fcheck_files(files, fd);
722 v = 0;
723 } else {
724 file = __fget(fd, 0);
725 v = FDPUT_FPUT;
726 }
727 if (!file)
728 return 0;
729
730 if (file->f_mode & FMODE_ATOMIC_POS) {
731 if (file_count(file) > 1) {
732 v |= FDPUT_POS_UNLOCK;
733 mutex_lock(&file->f_pos_lock);
734 }
735 }
736 return v | (unsigned long)file;
713} 737}
714 738
739/*
740 * We only lock f_pos if we have threads or if the file might be
741 * shared with another process. In both cases we'll have an elevated
742 * file count (done either by fdget() or by fork()).
743 */
744
715void set_close_on_exec(unsigned int fd, int flag) 745void set_close_on_exec(unsigned int fd, int flag)
716{ 746{
717 struct files_struct *files = current->files; 747 struct files_struct *files = current->files;
diff --git a/fs/file_table.c b/fs/file_table.c
index 5fff9030be34..5b24008ea4f6 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -135,6 +135,7 @@ struct file *get_empty_filp(void)
135 atomic_long_set(&f->f_count, 1); 135 atomic_long_set(&f->f_count, 1);
136 rwlock_init(&f->f_owner.lock); 136 rwlock_init(&f->f_owner.lock);
137 spin_lock_init(&f->f_lock); 137 spin_lock_init(&f->f_lock);
138 mutex_init(&f->f_pos_lock);
138 eventpoll_init_file(f); 139 eventpoll_init_file(f);
139 /* f->f_version: 0 */ 140 /* f->f_version: 0 */
140 return f; 141 return f;
diff --git a/fs/namei.c b/fs/namei.c
index 385f7817bfcc..2f730ef9b4b3 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1884,7 +1884,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
1884 1884
1885 nd->path = f.file->f_path; 1885 nd->path = f.file->f_path;
1886 if (flags & LOOKUP_RCU) { 1886 if (flags & LOOKUP_RCU) {
1887 if (f.need_put) 1887 if (f.flags & FDPUT_FPUT)
1888 *fp = f.file; 1888 *fp = f.file;
1889 nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); 1889 nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
1890 rcu_read_lock(); 1890 rcu_read_lock();
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 8450262bcf2a..51632c40e896 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -2393,8 +2393,8 @@ out_dio:
2393 2393
2394 if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) || 2394 if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) ||
2395 ((file->f_flags & O_DIRECT) && !direct_io)) { 2395 ((file->f_flags & O_DIRECT) && !direct_io)) {
2396 ret = filemap_fdatawrite_range(file->f_mapping, pos, 2396 ret = filemap_fdatawrite_range(file->f_mapping, *ppos,
2397 pos + count - 1); 2397 *ppos + count - 1);
2398 if (ret < 0) 2398 if (ret < 0)
2399 written = ret; 2399 written = ret;
2400 2400
@@ -2407,8 +2407,8 @@ out_dio:
2407 } 2407 }
2408 2408
2409 if (!ret) 2409 if (!ret)
2410 ret = filemap_fdatawait_range(file->f_mapping, pos, 2410 ret = filemap_fdatawait_range(file->f_mapping, *ppos,
2411 pos + count - 1); 2411 *ppos + count - 1);
2412 } 2412 }
2413 2413
2414 /* 2414 /*
diff --git a/fs/open.c b/fs/open.c
index 4b3e1edf2fe4..b9ed8b25c108 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -705,6 +705,10 @@ static int do_dentry_open(struct file *f,
705 return 0; 705 return 0;
706 } 706 }
707 707
708 /* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */
709 if (S_ISREG(inode->i_mode))
710 f->f_mode |= FMODE_ATOMIC_POS;
711
708 f->f_op = fops_get(inode->i_fop); 712 f->f_op = fops_get(inode->i_fop);
709 if (unlikely(WARN_ON(!f->f_op))) { 713 if (unlikely(WARN_ON(!f->f_op))) {
710 error = -ENODEV; 714 error = -ENODEV;
diff --git a/fs/read_write.c b/fs/read_write.c
index edc5746a902a..54e19b9392dc 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}
265EXPORT_SYMBOL(vfs_llseek); 265EXPORT_SYMBOL(vfs_llseek);
266 266
267static inline struct fd fdget_pos(int fd)
268{
269 return __to_fd(__fdget_pos(fd));
270}
271
272static 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
267SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) 279SYSCALL_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
@@ -498,7 +510,7 @@ static inline void file_pos_write(struct file *file, loff_t pos)
498 510
499SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) 511SYSCALL_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)
514SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, 526SYSCALL_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);
797SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, 809SYSCALL_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,
817SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, 829SYSCALL_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)
@@ -968,7 +980,7 @@ COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,
968 const struct compat_iovec __user *,vec, 980 const struct compat_iovec __user *,vec,
969 compat_ulong_t, vlen) 981 compat_ulong_t, vlen)
970{ 982{
971 struct fd f = fdget(fd); 983 struct fd f = fdget_pos(fd);
972 ssize_t ret; 984 ssize_t ret;
973 loff_t pos; 985 loff_t pos;
974 986
@@ -978,7 +990,7 @@ COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,
978 ret = compat_readv(f.file, vec, vlen, &pos); 990 ret = compat_readv(f.file, vec, vlen, &pos);
979 if (ret >= 0) 991 if (ret >= 0)
980 f.file->f_pos = pos; 992 f.file->f_pos = pos;
981 fdput(f); 993 fdput_pos(f);
982 return ret; 994 return ret;
983} 995}
984 996
@@ -1035,7 +1047,7 @@ COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd,
1035 const struct compat_iovec __user *, vec, 1047 const struct compat_iovec __user *, vec,
1036 compat_ulong_t, vlen) 1048 compat_ulong_t, vlen)
1037{ 1049{
1038 struct fd f = fdget(fd); 1050 struct fd f = fdget_pos(fd);
1039 ssize_t ret; 1051 ssize_t ret;
1040 loff_t pos; 1052 loff_t pos;
1041 1053
@@ -1045,7 +1057,7 @@ COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd,
1045 ret = compat_writev(f.file, vec, vlen, &pos); 1057 ret = compat_writev(f.file, vec, vlen, &pos);
1046 if (ret >= 0) 1058 if (ret >= 0)
1047 f.file->f_pos = pos; 1059 f.file->f_pos = pos;
1048 fdput(f); 1060 fdput_pos(f);
1049 return ret; 1061 return ret;
1050} 1062}
1051 1063
diff --git a/include/linux/file.h b/include/linux/file.h
index cbacf4faf447..4d69123377a2 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -28,33 +28,36 @@ static inline void fput_light(struct file *file, int fput_needed)
28 28
29struct fd { 29struct fd {
30 struct file *file; 30 struct file *file;
31 int need_put; 31 unsigned int flags;
32}; 32};
33#define FDPUT_FPUT 1
34#define FDPUT_POS_UNLOCK 2
33 35
34static inline void fdput(struct fd fd) 36static inline void fdput(struct fd fd)
35{ 37{
36 if (fd.need_put) 38 if (fd.flags & FDPUT_FPUT)
37 fput(fd.file); 39 fput(fd.file);
38} 40}
39 41
40extern struct file *fget(unsigned int fd); 42extern struct file *fget(unsigned int fd);
41extern struct file *fget_light(unsigned int fd, int *fput_needed); 43extern struct file *fget_raw(unsigned int fd);
44extern unsigned long __fdget(unsigned int fd);
45extern unsigned long __fdget_raw(unsigned int fd);
46extern unsigned long __fdget_pos(unsigned int fd);
42 47
43static inline struct fd fdget(unsigned int fd) 48static inline struct fd __to_fd(unsigned long v)
44{ 49{
45 int b; 50 return (struct fd){(struct file *)(v & ~3),v & 3};
46 struct file *f = fget_light(fd, &b);
47 return (struct fd){f,b};
48} 51}
49 52
50extern struct file *fget_raw(unsigned int fd); 53static inline struct fd fdget(unsigned int fd)
51extern struct file *fget_raw_light(unsigned int fd, int *fput_needed); 54{
55 return __to_fd(__fdget(fd));
56}
52 57
53static inline struct fd fdget_raw(unsigned int fd) 58static inline struct fd fdget_raw(unsigned int fd)
54{ 59{
55 int b; 60 return __to_fd(__fdget_raw(fd));
56 struct file *f = fget_raw_light(fd, &b);
57 return (struct fd){f,b};
58} 61}
59 62
60extern int f_dupfd(unsigned int from, struct file *file, unsigned flags); 63extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 60829565e552..23b2a35d712e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -123,6 +123,9 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
123/* File is opened with O_PATH; almost nothing can be done with it */ 123/* File is opened with O_PATH; almost nothing can be done with it */
124#define FMODE_PATH ((__force fmode_t)0x4000) 124#define FMODE_PATH ((__force fmode_t)0x4000)
125 125
126/* File needs atomic accesses to f_pos */
127#define FMODE_ATOMIC_POS ((__force fmode_t)0x8000)
128
126/* File was opened by fanotify and shouldn't generate fanotify events */ 129/* File was opened by fanotify and shouldn't generate fanotify events */
127#define FMODE_NONOTIFY ((__force fmode_t)0x1000000) 130#define FMODE_NONOTIFY ((__force fmode_t)0x1000000)
128 131
@@ -780,13 +783,14 @@ struct file {
780 const struct file_operations *f_op; 783 const struct file_operations *f_op;
781 784
782 /* 785 /*
783 * Protects f_ep_links, f_flags, f_pos vs i_size in lseek SEEK_CUR. 786 * Protects f_ep_links, f_flags.
784 * Must not be taken from IRQ context. 787 * Must not be taken from IRQ context.
785 */ 788 */
786 spinlock_t f_lock; 789 spinlock_t f_lock;
787 atomic_long_t f_count; 790 atomic_long_t f_count;
788 unsigned int f_flags; 791 unsigned int f_flags;
789 fmode_t f_mode; 792 fmode_t f_mode;
793 struct mutex f_pos_lock;
790 loff_t f_pos; 794 loff_t f_pos;
791 struct fown_struct f_owner; 795 struct fown_struct f_owner;
792 const struct cred *f_cred; 796 const struct cred *f_cred;
@@ -808,7 +812,7 @@ struct file {
808#ifdef CONFIG_DEBUG_WRITECOUNT 812#ifdef CONFIG_DEBUG_WRITECOUNT
809 unsigned long f_mnt_write_state; 813 unsigned long f_mnt_write_state;
810#endif 814#endif
811}; 815} __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
812 816
813struct file_handle { 817struct file_handle {
814 __u32 handle_bytes; 818 __u32 handle_bytes;
diff --git a/net/socket.c b/net/socket.c
index 879933aaed4c..fd8d86e06f95 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -450,16 +450,17 @@ EXPORT_SYMBOL(sockfd_lookup);
450 450
451static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) 451static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
452{ 452{
453 struct file *file; 453 struct fd f = fdget(fd);
454 struct socket *sock; 454 struct socket *sock;
455 455
456 *err = -EBADF; 456 *err = -EBADF;
457 file = fget_light(fd, fput_needed); 457 if (f.file) {
458 if (file) { 458 sock = sock_from_file(f.file, err);
459 sock = sock_from_file(file, err); 459 if (likely(sock)) {
460 if (sock) 460 *fput_needed = f.flags;
461 return sock; 461 return sock;
462 fput_light(file, *fput_needed); 462 }
463 fdput(f);
463 } 464 }
464 return NULL; 465 return NULL;
465} 466}