X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;f=fs%2Ffcntl.c;h=9679fcbdeaa0b7440992db5baec1698e90704588;hb=336dd1f70ff62d7dd8655228caed4c5bfc818c56;hp=e632da761fc11cd19b8637bcad23b1f5562d7382;hpb=c58310bf4933986513020fa90b4190c7492995ae;p=linux-block.git diff --git a/fs/fcntl.c b/fs/fcntl.c index e632da761fc1..9679fcbdeaa0 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -9,9 +9,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -55,14 +55,16 @@ static int get_close_on_exec(unsigned int fd) * 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,53 +99,42 @@ repeat: 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; } -asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) +asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags) { int err = -EBADF; struct file * file, *tofree; struct files_struct * files = current->files; struct fdtable *fdt; + if ((flags & ~O_CLOEXEC) != 0) + return -EINVAL; + spin_lock(&files->file_lock); if (!(file = fcheck(oldfd))) goto out_unlock; @@ -175,7 +166,10 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) rcu_assign_pointer(fdt->fd[newfd], file); FD_SET(newfd, fdt->open_fds); - FD_CLR(newfd, fdt->close_on_exec); + if (flags & O_CLOEXEC) + FD_SET(newfd, fdt->close_on_exec); + else + FD_CLR(newfd, fdt->close_on_exec); spin_unlock(&files->file_lock); if (tofree) @@ -193,6 +187,11 @@ out_fput: goto out; } +asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) +{ + return sys_dup3(oldfd, newfd, 0); +} + asmlinkage long sys_dup(unsigned int fildes) { int ret = -EBADF; @@ -238,7 +237,6 @@ static int setfl(int fd, struct file * filp, unsigned long arg) if (error) return error; - lock_kernel(); if ((arg ^ filp->f_flags) & FASYNC) { if (filp->f_op && filp->f_op->fasync) { error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0); @@ -249,7 +247,6 @@ static int setfl(int fd, struct file * filp, unsigned long arg) filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK); out: - unlock_kernel(); return error; }