Commit f8f95702 authored by Al Viro's avatar Al Viro

[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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 3b125388
...@@ -55,14 +55,16 @@ static int get_close_on_exec(unsigned int fd) ...@@ -55,14 +55,16 @@ static int get_close_on_exec(unsigned int fd)
* file_lock held for write. * file_lock held for write.
*/ */
static int locate_fd(struct files_struct *files, static int locate_fd(unsigned int orig_start, int cloexec)
struct file *file, unsigned int orig_start)
{ {
struct files_struct *files = current->files;
unsigned int newfd; unsigned int newfd;
unsigned int start; unsigned int start;
int error; int error;
struct fdtable *fdt; struct fdtable *fdt;
spin_lock(&files->file_lock);
error = -EINVAL; error = -EINVAL;
if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
goto out; goto out;
...@@ -97,42 +99,28 @@ static int locate_fd(struct files_struct *files, ...@@ -97,42 +99,28 @@ static int locate_fd(struct files_struct *files,
if (error) if (error)
goto repeat; 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) if (start <= files->next_fd)
files->next_fd = newfd + 1; 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; error = newfd;
out: out:
spin_unlock(&files->file_lock);
return error; return error;
} }
static int dupfd(struct file *file, unsigned int start, int cloexec) static int dupfd(struct file *file, unsigned int start, int cloexec)
{ {
struct files_struct * files = current->files; int fd = locate_fd(start, cloexec);
struct fdtable *fdt; if (fd >= 0)
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);
fd_install(fd, file); fd_install(fd, file);
} else { else
spin_unlock(&files->file_lock);
fput(file); fput(file);
}
return fd; return fd;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment