[PATCH] sanitize locate_fd()
* 'file' argument is unused; lose it.
* move setting flags from the caller (dupfd()) to locate_fd();
pass cloexec flag as new argument. Note that files_fdtable()
that used to be in dupfd() isn't needed in the place in
locate_fd() where the moved code ends up - we know that ->file_lock
hadn't been dropped since the last time we calculated fdt because
we can get there only if expand_files() returns 0 and it doesn't
drop/reacquire in that case.
* move getting/dropping ->file_lock into locate_fd(). Now the caller
doesn't need to do anything with files_struct *files anymore and
we can move that inside locate_fd() as well, killing the
struct files_struct * argument.
At that point locate_fd() is extremely similar to get_unused_fd_flags()
and the next patches will merge those two.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
diff --git a/fs/fcntl.c b/fs/fcntl.c
index e632da7..3f3ac63 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -55,14 +55,16 @@
* file_lock held for write.
*/
-static int locate_fd(struct files_struct *files,
- struct file *file, unsigned int orig_start)
+static int locate_fd(unsigned int orig_start, int cloexec)
{
+ struct files_struct *files = current->files;
unsigned int newfd;
unsigned int start;
int error;
struct fdtable *fdt;
+ spin_lock(&files->file_lock);
+
error = -EINVAL;
if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
goto out;
@@ -97,42 +99,28 @@
if (error)
goto repeat;
- /*
- * We reacquired files_lock, so we are safe as long as
- * we reacquire the fdtable pointer and use it while holding
- * the lock, no one can free it during that time.
- */
if (start <= files->next_fd)
files->next_fd = newfd + 1;
+ FD_SET(newfd, fdt->open_fds);
+ if (cloexec)
+ FD_SET(newfd, fdt->close_on_exec);
+ else
+ FD_CLR(newfd, fdt->close_on_exec);
error = newfd;
-
+
out:
+ spin_unlock(&files->file_lock);
return error;
}
static int dupfd(struct file *file, unsigned int start, int cloexec)
{
- struct files_struct * files = current->files;
- struct fdtable *fdt;
- int fd;
-
- spin_lock(&files->file_lock);
- fd = locate_fd(files, file, start);
- if (fd >= 0) {
- /* locate_fd() may have expanded fdtable, load the ptr */
- fdt = files_fdtable(files);
- FD_SET(fd, fdt->open_fds);
- if (cloexec)
- FD_SET(fd, fdt->close_on_exec);
- else
- FD_CLR(fd, fdt->close_on_exec);
- spin_unlock(&files->file_lock);
+ int fd = locate_fd(start, cloexec);
+ if (fd >= 0)
fd_install(fd, file);
- } else {
- spin_unlock(&files->file_lock);
+ else
fput(file);
- }
return fd;
}