Replace close_on_exec with idr_(get,set,clear)_tag(). Through this patch, added new IDR tag FD_TAG_CLOEXEC which is passing to idr_(get,set,clear)_tag() to achieve close_on_exec functionality. Also removed get_close_on_exec() and using close_on_exec() instead of that. Signed-off-by: Sandhya Bankar <bankarsandhya512@xxxxxxxxx> Signed-off-by: Matthew Wilcox <mawilcox@xxxxxxxxxxxxx> --- fs/exec.c | 2 +- fs/fcntl.c | 2 +- fs/file.c | 85 +++++++++++++++---------------------------------- fs/proc/fd.c | 4 +-- include/linux/fdtable.h | 19 +++++++---- include/linux/file.h | 1 - 6 files changed, 41 insertions(+), 72 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 65145a3..2070bc6 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1728,7 +1728,7 @@ static int do_execveat_common(int fd, struct filename *filename, * inaccessible after exec. Relies on having exclusive access to * current->files (due to unshare_files above). */ - if (close_on_exec(fd, rcu_dereference_raw(current->files->fdt))) + if (close_on_exec(fd, current->files)) bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE; bprm->filename = pathbuf; } diff --git a/fs/fcntl.c b/fs/fcntl.c index be8fbe2..9c2061b 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -255,7 +255,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, err = f_dupfd(arg, filp, O_CLOEXEC); break; case F_GETFD: - err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; + err = close_on_exec(fd, current->files) ? FD_CLOEXEC : 0; break; case F_SETFD: err = 0; diff --git a/fs/file.c b/fs/file.c index 8cd77c5..56c5731 100644 --- a/fs/file.c +++ b/fs/file.c @@ -70,8 +70,6 @@ static void copy_fd_bitmaps(struct fdtable *nfdt, struct fdtable *ofdt, set = (nfdt->max_fds - count) / BITS_PER_BYTE; memcpy(nfdt->open_fds, ofdt->open_fds, cpy); memset((char *)nfdt->open_fds + cpy, 0, set); - memcpy(nfdt->close_on_exec, ofdt->close_on_exec, cpy); - memset((char *)nfdt->close_on_exec + cpy, 0, set); } /* @@ -115,13 +113,10 @@ static struct fdtable * alloc_fdtable(unsigned int nr) goto out; fdt->max_fds = nr; - data = alloc_fdmem(max_t(size_t, - 2 * nr / BITS_PER_BYTE, L1_CACHE_BYTES)); + data = alloc_fdmem(max_t(size_t, nr / BITS_PER_BYTE, L1_CACHE_BYTES)); if (!data) goto out_fdt; fdt->open_fds = data; - data += nr / BITS_PER_BYTE; - fdt->close_on_exec = data; return fdt; @@ -227,15 +222,16 @@ static inline bool fd_is_open(unsigned int fd, struct files_struct *files) return !idr_tag_get(&files->fd_idr, fd, IDR_FREE); } -static inline void __set_close_on_exec(unsigned int fd, struct fdtable *fdt) +static inline void __set_close_on_exec(unsigned int fd, + struct files_struct *files) { - __set_bit(fd, fdt->close_on_exec); + idr_tag_set(&files->fd_idr, fd, FD_TAG_CLOEXEC); } -static inline void __clear_close_on_exec(unsigned int fd, struct fdtable *fdt) +static inline void __clear_close_on_exec(unsigned int fd, + struct files_struct *files) { - if (test_bit(fd, fdt->close_on_exec)) - __clear_bit(fd, fdt->close_on_exec); + idr_tag_clear(&files->fd_idr, fd, FD_TAG_CLOEXEC); } static inline void __set_open_fd(unsigned int fd, struct fdtable *fdt) @@ -287,7 +283,6 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) init_waitqueue_head(&newf->resize_wait); new_fdt = &newf->fdtab; new_fdt->max_fds = NR_OPEN_DEFAULT; - new_fdt->close_on_exec = newf->close_on_exec_init; new_fdt->open_fds = newf->open_fds_init; restart: @@ -347,6 +342,9 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) spin_unlock(&oldf->file_lock); goto out; } + + if (idr_tag_get(&oldf->fd_idr, i, FD_TAG_CLOEXEC)) + idr_tag_set(&newf->fd_idr, i, FD_TAG_CLOEXEC); } spin_unlock(&oldf->file_lock); @@ -445,7 +443,6 @@ struct files_struct init_files = { .fdt = &init_files.fdtab, .fdtab = { .max_fds = NR_OPEN_DEFAULT, - .close_on_exec = init_files.close_on_exec_init, .open_fds = init_files.open_fds_init, }, .file_lock = __SPIN_LOCK_UNLOCKED(init_files.file_lock), @@ -482,9 +479,9 @@ int __alloc_fd(struct files_struct *files, fdt = files_fdtable(files); __set_open_fd(fd, fdt); if (flags & O_CLOEXEC) - __set_close_on_exec(fd, fdt); + __set_close_on_exec(fd, files); else - __clear_close_on_exec(fd, fdt); + __clear_close_on_exec(fd, files); error = fd; out: @@ -571,7 +568,7 @@ int __close_fd(struct files_struct *files, unsigned fd) file = idr_remove(&files->fd_idr, fd); if (!file) goto out_unlock; - __clear_close_on_exec(fd, fdt); + __clear_close_on_exec(fd, files); __put_unused_fd(files, fd); spin_unlock(&files->file_lock); return filp_close(file, files); @@ -583,35 +580,19 @@ int __close_fd(struct files_struct *files, unsigned fd) void do_close_on_exec(struct files_struct *files) { - unsigned i; - struct fdtable *fdt; + struct file *file; + unsigned int fd; /* exec unshares first */ spin_lock(&files->file_lock); - for (i = 0; ; i++) { - unsigned long set; - unsigned fd = i * BITS_PER_LONG; - fdt = files_fdtable(files); - if (fd >= fdt->max_fds) - break; - set = fdt->close_on_exec[i]; - if (!set) - continue; - fdt->close_on_exec[i] = 0; - for ( ; set ; fd++, set >>= 1) { - struct file *file; - if (!(set & 1)) - continue; - file = idr_remove(&files->fd_idr, fd); - if (!file) - continue; - __put_unused_fd(files, fd); - spin_unlock(&files->file_lock); - filp_close(file, files); - cond_resched(); - spin_lock(&files->file_lock); - } + idr_for_each_entry_tagged(&files->fd_idr, file, fd, FD_TAG_CLOEXEC) { + idr_remove(&files->fd_idr, fd); + __put_unused_fd(files, fd); + spin_unlock(&files->file_lock); + filp_close(file, files); + cond_resched(); + spin_lock(&files->file_lock); } spin_unlock(&files->file_lock); } @@ -723,28 +704,14 @@ void __f_unlock_pos(struct file *f) void set_close_on_exec(unsigned int fd, int flag) { struct files_struct *files = current->files; - struct fdtable *fdt; spin_lock(&files->file_lock); - fdt = files_fdtable(files); if (flag) - __set_close_on_exec(fd, fdt); + __set_close_on_exec(fd, files); else - __clear_close_on_exec(fd, fdt); + __clear_close_on_exec(fd, files); spin_unlock(&files->file_lock); } -bool get_close_on_exec(unsigned int fd) -{ - struct files_struct *files = current->files; - struct fdtable *fdt; - bool res; - rcu_read_lock(); - fdt = files_fdtable(files); - res = close_on_exec(fd, fdt); - rcu_read_unlock(); - return res; -} - static int do_dup2(struct files_struct *files, struct file *file, unsigned fd, unsigned flags) __releases(&files->file_lock) @@ -783,9 +750,9 @@ static int do_dup2(struct files_struct *files, } __set_open_fd(fd, fdt); if (flags & O_CLOEXEC) - __set_close_on_exec(fd, fdt); + __set_close_on_exec(fd, files); else - __clear_close_on_exec(fd, fdt); + __clear_close_on_exec(fd, files); spin_unlock(&files->file_lock); idr_preload_end(); diff --git a/fs/proc/fd.c b/fs/proc/fd.c index c330495..2735ccc 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -36,10 +36,8 @@ static int seq_show(struct seq_file *m, void *v) spin_lock(&files->file_lock); file = fcheck_files(files, fd); if (file) { - struct fdtable *fdt = files_fdtable(files); - f_flags = file->f_flags; - if (close_on_exec(fd, fdt)) + if (close_on_exec(fd, files)) f_flags |= O_CLOEXEC; get_file(file); diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index 67259f4..7f1ab82 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h @@ -22,18 +22,14 @@ */ #define NR_OPEN_DEFAULT BITS_PER_LONG +#define FD_TAG_CLOEXEC 1 + struct fdtable { unsigned int max_fds; - unsigned long *close_on_exec; unsigned long *open_fds; struct rcu_head rcu; }; -static inline bool close_on_exec(unsigned int fd, const struct fdtable *fdt) -{ - return test_bit(fd, fdt->close_on_exec); -} - /* * Open file table structure */ @@ -52,7 +48,6 @@ struct files_struct { * written part on a separate cache line in SMP */ spinlock_t file_lock ____cacheline_aligned_in_smp; - unsigned long close_on_exec_init[1]; unsigned long open_fds_init[1]; }; @@ -82,6 +77,16 @@ static inline struct file *fcheck_files(struct files_struct *files, unsigned int return __fcheck_files(files, fd); } +static inline bool close_on_exec(unsigned int fd, struct files_struct *files) +{ + bool res; + + rcu_read_lock(); + res = idr_tag_get(&files->fd_idr, fd, FD_TAG_CLOEXEC); + rcu_read_unlock(); + return res; +} + /* * Check whether the specified fd has an open file. */ diff --git a/include/linux/file.h b/include/linux/file.h index 61eb82c..1856bbf 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -76,7 +76,6 @@ static inline void fdput_pos(struct fd f) extern int f_dupfd(unsigned int from, struct file *file, unsigned flags); extern int replace_fd(unsigned fd, struct file *file, unsigned flags); extern void set_close_on_exec(unsigned int fd, int flag); -extern bool get_close_on_exec(unsigned int fd); extern void put_filp(struct file *); extern int get_unused_fd_flags(unsigned flags); extern void put_unused_fd(unsigned int fd); -- 1.8.3.1