diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-08-15 21:03:26 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-09-26 21:08:55 -0400 |
commit | 56007cae94f349387c088e738c7dcb6bc513063b (patch) | |
tree | b501eb1cc30619cb1cc9828a18256808546389de /fs/file.c | |
parent | 1983e781da2f7f77906f4ccc2c3dc279cd61d1ff (diff) | |
download | lwn-56007cae94f349387c088e738c7dcb6bc513063b.tar.gz lwn-56007cae94f349387c088e738c7dcb6bc513063b.zip |
move put_unused_fd() and fd_install() to fs/file.c
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/file.c')
-rw-r--r-- | fs/file.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/fs/file.c b/fs/file.c index 4ce4a0fcf320..78cf88f2a0e8 100644 --- a/fs/file.c +++ b/fs/file.c @@ -569,3 +569,47 @@ int get_unused_fd_flags(unsigned flags) return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags); } EXPORT_SYMBOL(get_unused_fd_flags); + +static void __put_unused_fd(struct files_struct *files, unsigned int fd) +{ + struct fdtable *fdt = files_fdtable(files); + __clear_open_fd(fd, fdt); + if (fd < files->next_fd) + files->next_fd = fd; +} + +void put_unused_fd(unsigned int fd) +{ + struct files_struct *files = current->files; + spin_lock(&files->file_lock); + __put_unused_fd(files, fd); + spin_unlock(&files->file_lock); +} + +EXPORT_SYMBOL(put_unused_fd); + +/* + * Install a file pointer in the fd array. + * + * The VFS is full of places where we drop the files lock between + * setting the open_fds bitmap and installing the file in the file + * array. At any such point, we are vulnerable to a dup2() race + * installing a file in the array before us. We need to detect this and + * fput() the struct file we are about to overwrite in this case. + * + * It should never happen - if we allow dup2() do it, _really_ bad things + * will follow. + */ + +void fd_install(unsigned int fd, struct file *file) +{ + struct files_struct *files = current->files; + struct fdtable *fdt; + spin_lock(&files->file_lock); + fdt = files_fdtable(files); + BUG_ON(fdt->fd[fd] != NULL); + rcu_assign_pointer(fdt->fd[fd], file); + spin_unlock(&files->file_lock); +} + +EXPORT_SYMBOL(fd_install); |