diff options
author | Tyler Hicks <code@tyhicks.com> | 2021-04-19 04:39:17 +0000 |
---|---|---|
committer | Tyler Hicks <code@tyhicks.com> | 2021-04-19 04:39:17 +0000 |
commit | b7f8f259896f669f131713b0c74ba4d008daa71d (patch) | |
tree | cb42f2b5e67674b011fcca54594213f43c086e8b /fs/file.c | |
parent | 902af369942f8d0a6bdaa8466ff0d84d3d9b03a8 (diff) | |
parent | d434405aaab7d0ebc516b68a8fc4100922d7f5ef (diff) | |
download | lwn-b7f8f259896f669f131713b0c74ba4d008daa71d.tar.gz lwn-b7f8f259896f669f131713b0c74ba4d008daa71d.zip |
Merge tag 'v5.12-rc7' into ecryptfs/next
Required to pick up idmapped mount changes which changed some function
parameters.
Diffstat (limited to 'fs/file.c')
-rw-r--r-- | fs/file.c | 57 |
1 files changed, 42 insertions, 15 deletions
diff --git a/fs/file.c b/fs/file.c index dab120b71e44..f633348029a5 100644 --- a/fs/file.c +++ b/fs/file.c @@ -22,6 +22,8 @@ #include <linux/close_range.h> #include <net/sock.h> +#include "internal.h" + unsigned int sysctl_nr_open __read_mostly = 1024*1024; unsigned int sysctl_nr_open_min = BITS_PER_LONG; /* our min() is unusable in constant expressions ;-/ */ @@ -627,17 +629,30 @@ int close_fd(unsigned fd) } EXPORT_SYMBOL(close_fd); /* for ksys_close() */ +/** + * last_fd - return last valid index into fd table + * @cur_fds: files struct + * + * Context: Either rcu read lock or files_lock must be held. + * + * Returns: Last valid index into fdtable. + */ +static inline unsigned last_fd(struct fdtable *fdt) +{ + return fdt->max_fds - 1; +} + static inline void __range_cloexec(struct files_struct *cur_fds, unsigned int fd, unsigned int max_fd) { struct fdtable *fdt; - if (fd > max_fd) - return; - + /* make sure we're using the correct maximum value */ spin_lock(&cur_fds->file_lock); fdt = files_fdtable(cur_fds); - bitmap_set(fdt->close_on_exec, fd, max_fd - fd + 1); + max_fd = min(last_fd(fdt), max_fd); + if (fd <= max_fd) + bitmap_set(fdt->close_on_exec, fd, max_fd - fd + 1); spin_unlock(&cur_fds->file_lock); } @@ -732,36 +747,48 @@ int __close_range(unsigned fd, unsigned max_fd, unsigned int flags) } /* - * variant of close_fd that gets a ref on the file for later fput. - * The caller must ensure that filp_close() called on the file, and then - * an fput(). + * See close_fd_get_file() below, this variant assumes current->files->file_lock + * is held. */ -int close_fd_get_file(unsigned int fd, struct file **res) +int __close_fd_get_file(unsigned int fd, struct file **res) { struct files_struct *files = current->files; struct file *file; struct fdtable *fdt; - spin_lock(&files->file_lock); fdt = files_fdtable(files); if (fd >= fdt->max_fds) - goto out_unlock; + goto out_err; file = fdt->fd[fd]; if (!file) - goto out_unlock; + goto out_err; rcu_assign_pointer(fdt->fd[fd], NULL); __put_unused_fd(files, fd); - spin_unlock(&files->file_lock); get_file(file); *res = file; return 0; - -out_unlock: - spin_unlock(&files->file_lock); +out_err: *res = NULL; return -ENOENT; } +/* + * variant of close_fd that gets a ref on the file for later fput. + * The caller must ensure that filp_close() called on the file, and then + * an fput(). + */ +int close_fd_get_file(unsigned int fd, struct file **res) +{ + struct files_struct *files = current->files; + int ret; + + spin_lock(&files->file_lock); + ret = __close_fd_get_file(fd, res); + spin_unlock(&files->file_lock); + + return ret; +} + void do_close_on_exec(struct files_struct *files) { unsigned i; |