diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-08-21 17:56:33 +0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-09-27 05:09:56 +0400 |
commit | 6a6d27de340c89c5323565b49f7851362619925d (patch) | |
tree | b9b4ab23b43bd330584521917c9b2855c4a4e0cd /fs/file.c | |
parent | 723a1d77431b0c568730ffac4dd0bcbbd3400031 (diff) | |
download | linux-6a6d27de340c89c5323565b49f7851362619925d.tar.xz |
take close-on-exec logics to fs/file.c, clean it up a bit
... and add cond_resched() there, while we are at it. We can
get large latencies as is...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/file.c')
-rw-r--r-- | fs/file.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/fs/file.c b/fs/file.c index fd4694e688ab..92197dd9fdc8 100644 --- a/fs/file.c +++ b/fs/file.c @@ -652,6 +652,43 @@ out_unlock: return -EBADF; } +void do_close_on_exec(struct files_struct *files) +{ + unsigned i; + struct fdtable *fdt; + + /* exec unshares first */ + BUG_ON(atomic_read(&files->count) != 1); + 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 = fdt->fd[fd]; + if (!file) + continue; + rcu_assign_pointer(fdt->fd[fd], NULL); + __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); +} + struct file *fget(unsigned int fd) { struct file *file; |