While here take more advantage of the fact nobody should be messing with the table anymore and don't clear the fd slot. Signed-off-by: Mateusz Guzik <mjguzik@xxxxxxxxx> --- how about this instead, I think it's a nicer clean up. It's literally do_close_on_exec except locking and put fd are deleted. boots & does not blow up, but admittedly I did not bother with ltp or any serious testing fs/file.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/fs/file.c b/fs/file.c index 74d7ad676579..3ff2e8265156 100644 --- a/fs/file.c +++ b/fs/file.c @@ -389,33 +389,38 @@ struct files_struct *dup_fd(struct files_struct *oldf, unsigned int max_fds) return newf; } -static struct fdtable *close_files(struct files_struct * files) +static struct fdtable *close_files(struct files_struct *files) { /* * It is safe to dereference the fd table without RCU or * ->file_lock because this is the last reference to the * files structure. + * + * For the same reason we can skip locking. */ struct fdtable *fdt = rcu_dereference_raw(files->fdt); - unsigned int i, j = 0; + unsigned i; - for (;;) { + for (i = 0; ; i++) { unsigned long set; - i = j * BITS_PER_LONG; - if (i >= fdt->max_fds) + unsigned fd = i * BITS_PER_LONG; + fdt = files_fdtable(files); + if (fd >= fdt->max_fds) break; - set = fdt->open_fds[j++]; - while (set) { - if (set & 1) { - struct file * file = xchg(&fdt->fd[i], NULL); - if (file) { - filp_close(file, files); - cond_resched(); - } - } - i++; - set >>= 1; + set = fdt->open_fds[i]; + if (!set) + continue; + for ( ; set ; fd++, set >>= 1) { + struct file *file; + if (!(set & 1)) + continue; + file = fdt->fd[fd]; + if (!file) + continue; + filp_close(file, files); + cond_resched(); } + } return fdt; -- 2.43.0