Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull vfs fixes from Al Viro.

Clean up file table accesses (get rid of fget_light() in favor of the
fdget() interface), add proper file position locking.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
get rid of fget_light()
sockfd_lookup_light(): switch to fdget^W^Waway from fget_light
vfs: atomic f_pos accesses as per POSIX
ocfs2 syncs the wrong range...

+107 -52
+43 -13
fs/file.c
··· 683 683 * The fput_needed flag returned by fget_light should be passed to the 684 684 * corresponding fput_light. 685 685 */ 686 - struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed) 686 + static unsigned long __fget_light(unsigned int fd, fmode_t mask) 687 687 { 688 688 struct files_struct *files = current->files; 689 689 struct file *file; 690 690 691 - *fput_needed = 0; 692 691 if (atomic_read(&files->count) == 1) { 693 692 file = __fcheck_files(files, fd); 694 - if (file && (file->f_mode & mask)) 695 - file = NULL; 693 + if (!file || unlikely(file->f_mode & mask)) 694 + return 0; 695 + return (unsigned long)file; 696 696 } else { 697 697 file = __fget(fd, mask); 698 - if (file) 699 - *fput_needed = 1; 698 + if (!file) 699 + return 0; 700 + return FDPUT_FPUT | (unsigned long)file; 700 701 } 701 - 702 - return file; 703 702 } 704 - struct file *fget_light(unsigned int fd, int *fput_needed) 703 + unsigned 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 } 708 - EXPORT_SYMBOL(fget_light); 707 + EXPORT_SYMBOL(__fdget); 709 708 710 - struct file *fget_raw_light(unsigned int fd, int *fput_needed) 709 + unsigned long __fdget_raw(unsigned int fd) 711 710 { 712 - return __fget_light(fd, 0, fput_needed); 711 + return __fget_light(fd, 0); 713 712 } 713 + 714 + unsigned 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; 737 + } 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 + */ 714 744 715 745 void set_close_on_exec(unsigned int fd, int flag) 716 746 {
+1
fs/file_table.c
··· 135 135 atomic_long_set(&f->f_count, 1); 136 136 rwlock_init(&f->f_owner.lock); 137 137 spin_lock_init(&f->f_lock); 138 + mutex_init(&f->f_pos_lock); 138 139 eventpoll_init_file(f); 139 140 /* f->f_version: 0 */ 140 141 return f;
+1 -1
fs/namei.c
··· 1884 1884 1885 1885 nd->path = f.file->f_path; 1886 1886 if (flags & LOOKUP_RCU) { 1887 - if (f.need_put) 1887 + if (f.flags & FDPUT_FPUT) 1888 1888 *fp = f.file; 1889 1889 nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); 1890 1890 rcu_read_lock();
+4 -4
fs/ocfs2/file.c
··· 2393 2393 2394 2394 if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) || 2395 2395 ((file->f_flags & O_DIRECT) && !direct_io)) { 2396 - ret = filemap_fdatawrite_range(file->f_mapping, pos, 2397 - pos + count - 1); 2396 + ret = filemap_fdatawrite_range(file->f_mapping, *ppos, 2397 + *ppos + count - 1); 2398 2398 if (ret < 0) 2399 2399 written = ret; 2400 2400 ··· 2407 2407 } 2408 2408 2409 2409 if (!ret) 2410 - ret = filemap_fdatawait_range(file->f_mapping, pos, 2411 - pos + count - 1); 2410 + ret = filemap_fdatawait_range(file->f_mapping, *ppos, 2411 + *ppos + count - 1); 2412 2412 } 2413 2413 2414 2414 /*
+4
fs/open.c
··· 705 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 712 f->f_op = fops_get(inode->i_fop); 709 713 if (unlikely(WARN_ON(!f->f_op))) { 710 714 error = -ENODEV;
+26 -14
fs/read_write.c
··· 264 264 } 265 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 279 SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) 268 280 { 269 281 off_t retval; 270 - struct fd f = fdget(fd); 282 + struct fd f = fdget_pos(fd); 271 283 if (!f.file) 272 284 return -EBADF; 273 285 ··· 290 278 if (res != (loff_t)retval) 291 279 retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ 292 280 } 293 - fdput(f); 281 + fdput_pos(f); 294 282 return retval; 295 283 } 296 284 ··· 510 498 511 499 SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) 512 500 { 513 - struct fd f = fdget(fd); 501 + struct fd f = fdget_pos(fd); 514 502 ssize_t ret = -EBADF; 515 503 516 504 if (f.file) { ··· 518 506 ret = vfs_read(f.file, buf, count, &pos); 519 507 if (ret >= 0) 520 508 file_pos_write(f.file, pos); 521 - fdput(f); 509 + fdput_pos(f); 522 510 } 523 511 return ret; 524 512 } ··· 526 514 SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, 527 515 size_t, count) 528 516 { 529 - struct fd f = fdget(fd); 517 + struct fd f = fdget_pos(fd); 530 518 ssize_t ret = -EBADF; 531 519 532 520 if (f.file) { ··· 534 522 ret = vfs_write(f.file, buf, count, &pos); 535 523 if (ret >= 0) 536 524 file_pos_write(f.file, pos); 537 - fdput(f); 525 + fdput_pos(f); 538 526 } 539 527 540 528 return ret; ··· 809 797 SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, 810 798 unsigned long, vlen) 811 799 { 812 - struct fd f = fdget(fd); 800 + struct fd f = fdget_pos(fd); 813 801 ssize_t ret = -EBADF; 814 802 815 803 if (f.file) { ··· 817 805 ret = vfs_readv(f.file, vec, vlen, &pos); 818 806 if (ret >= 0) 819 807 file_pos_write(f.file, pos); 820 - fdput(f); 808 + fdput_pos(f); 821 809 } 822 810 823 811 if (ret > 0) ··· 829 817 SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, 830 818 unsigned long, vlen) 831 819 { 832 - struct fd f = fdget(fd); 820 + struct fd f = fdget_pos(fd); 833 821 ssize_t ret = -EBADF; 834 822 835 823 if (f.file) { ··· 837 825 ret = vfs_writev(f.file, vec, vlen, &pos); 838 826 if (ret >= 0) 839 827 file_pos_write(f.file, pos); 840 - fdput(f); 828 + fdput_pos(f); 841 829 } 842 830 843 831 if (ret > 0) ··· 980 968 const struct compat_iovec __user *,vec, 981 969 compat_ulong_t, vlen) 982 970 { 983 - struct fd f = fdget(fd); 971 + struct fd f = fdget_pos(fd); 984 972 ssize_t ret; 985 973 loff_t pos; 986 974 ··· 990 978 ret = compat_readv(f.file, vec, vlen, &pos); 991 979 if (ret >= 0) 992 980 f.file->f_pos = pos; 993 - fdput(f); 981 + fdput_pos(f); 994 982 return ret; 995 983 } 996 984 ··· 1047 1035 const struct compat_iovec __user *, vec, 1048 1036 compat_ulong_t, vlen) 1049 1037 { 1050 - struct fd f = fdget(fd); 1038 + struct fd f = fdget_pos(fd); 1051 1039 ssize_t ret; 1052 1040 loff_t pos; 1053 1041 ··· 1057 1045 ret = compat_writev(f.file, vec, vlen, &pos); 1058 1046 if (ret >= 0) 1059 1047 f.file->f_pos = pos; 1060 - fdput(f); 1048 + fdput_pos(f); 1061 1049 return ret; 1062 1050 } 1063 1051
+15 -12
include/linux/file.h
··· 28 28 29 29 struct fd { 30 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 34 36 static inline void fdput(struct fd fd) 35 37 { 36 - if (fd.need_put) 38 + if (fd.flags & FDPUT_FPUT) 37 39 fput(fd.file); 38 40 } 39 41 40 42 extern struct file *fget(unsigned int fd); 41 - extern struct file *fget_light(unsigned int fd, int *fput_needed); 43 + extern struct file *fget_raw(unsigned int fd); 44 + extern unsigned long __fdget(unsigned int fd); 45 + extern unsigned long __fdget_raw(unsigned int fd); 46 + extern unsigned long __fdget_pos(unsigned int fd); 47 + 48 + static inline struct fd __to_fd(unsigned long v) 49 + { 50 + return (struct fd){(struct file *)(v & ~3),v & 3}; 51 + } 42 52 43 53 static inline struct fd fdget(unsigned int fd) 44 54 { 45 - int b; 46 - struct file *f = fget_light(fd, &b); 47 - return (struct fd){f,b}; 55 + return __to_fd(__fdget(fd)); 48 56 } 49 - 50 - extern struct file *fget_raw(unsigned int fd); 51 - extern struct file *fget_raw_light(unsigned int fd, int *fput_needed); 52 57 53 58 static inline struct fd fdget_raw(unsigned int fd) 54 59 { 55 - int b; 56 - struct file *f = fget_raw_light(fd, &b); 57 - return (struct fd){f,b}; 60 + return __to_fd(__fdget_raw(fd)); 58 61 } 59 62 60 63 extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
+6 -2
include/linux/fs.h
··· 123 123 /* File is opened with O_PATH; almost nothing can be done with it */ 124 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 129 /* File was opened by fanotify and shouldn't generate fanotify events */ 127 130 #define FMODE_NONOTIFY ((__force fmode_t)0x1000000) 128 131 ··· 783 780 const struct file_operations *f_op; 784 781 785 782 /* 786 - * Protects f_ep_links, f_flags, f_pos vs i_size in lseek SEEK_CUR. 783 + * Protects f_ep_links, f_flags. 787 784 * Must not be taken from IRQ context. 788 785 */ 789 786 spinlock_t f_lock; 790 787 atomic_long_t f_count; 791 788 unsigned int f_flags; 792 789 fmode_t f_mode; 790 + struct mutex f_pos_lock; 793 791 loff_t f_pos; 794 792 struct fown_struct f_owner; 795 793 const struct cred *f_cred; ··· 812 808 #ifdef CONFIG_DEBUG_WRITECOUNT 813 809 unsigned long f_mnt_write_state; 814 810 #endif 815 - }; 811 + } __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */ 816 812 817 813 struct file_handle { 818 814 __u32 handle_bytes;
+7 -6
net/socket.c
··· 450 450 451 451 static 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 454 struct socket *sock; 455 455 456 456 *err = -EBADF; 457 - file = fget_light(fd, fput_needed); 458 - if (file) { 459 - sock = sock_from_file(file, err); 460 - if (sock) 457 + if (f.file) { 458 + sock = sock_from_file(f.file, err); 459 + if (likely(sock)) { 460 + *fput_needed = f.flags; 461 461 return sock; 462 - fput_light(file, *fput_needed); 462 + } 463 + fdput(f); 463 464 } 464 465 return NULL; 465 466 }