[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>
This commit is contained in:
38
fs/fcntl.c
38
fs/fcntl.c
@@ -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 @@ repeat:
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user