diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-03-10 15:57:26 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-03-10 15:57:26 -0400 |
| commit | e6a4b6f5eaa8478b7a0b9a17e40c51463631db1a (patch) | |
| tree | 35e164226b3a590481469a1739a2eb2a7b1217c1 | |
| parent | 2b64c5434d1303646388e748b7add69624a1cfee (diff) | |
| parent | bd2a31d522344b3ac2fb680bd2366e77a9bd8209 (diff) | |
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...
| -rw-r--r-- | fs/file.c | 56 | ||||
| -rw-r--r-- | fs/file_table.c | 1 | ||||
| -rw-r--r-- | fs/namei.c | 2 | ||||
| -rw-r--r-- | fs/ocfs2/file.c | 8 | ||||
| -rw-r--r-- | fs/open.c | 4 | ||||
| -rw-r--r-- | fs/read_write.c | 40 | ||||
| -rw-r--r-- | include/linux/file.h | 27 | ||||
| -rw-r--r-- | include/linux/fs.h | 8 | ||||
| -rw-r--r-- | net/socket.c | 13 |
9 files changed, 107 insertions, 52 deletions
| @@ -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 | */ |
| 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 | 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 | } |
| 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); |
| 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; | ||
| 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 | |||
| 715 | void set_close_on_exec(unsigned int fd, int flag) | 745 | void 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 | /* |
| @@ -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 | } |
| 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 | |
