aboutsummaryrefslogtreecommitdiffstats
path: root/fs/file.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-08-21 11:48:11 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-09-26 21:09:57 -0400
commitfe17f22d7fd0e344ef6447238f799bb49f670c6f (patch)
tree793facbd992c674e55790793ffa912927ae7a766 /fs/file.c
parent6a6d27de340c89c5323565b49f7851362619925d (diff)
take purely descriptor-related stuff from fcntl.c to file.c
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/file.c')
-rw-r--r--fs/file.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/fs/file.c b/fs/file.c
index 92197dd9fdc8..7f29544755d0 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -6,6 +6,7 @@
6 * Manage the dynamic fd arrays in the process files_struct. 6 * Manage the dynamic fd arrays in the process files_struct.
7 */ 7 */
8 8
9#include <linux/syscalls.h>
9#include <linux/export.h> 10#include <linux/export.h>
10#include <linux/fs.h> 11#include <linux/fs.h>
11#include <linux/mm.h> 12#include <linux/mm.h>
@@ -794,3 +795,134 @@ struct file *fget_raw_light(unsigned int fd, int *fput_needed)
794 795
795 return file; 796 return file;
796} 797}
798
799void set_close_on_exec(unsigned int fd, int flag)
800{
801 struct files_struct *files = current->files;
802 struct fdtable *fdt;
803 spin_lock(&files->file_lock);
804 fdt = files_fdtable(files);
805 if (flag)
806 __set_close_on_exec(fd, fdt);
807 else
808 __clear_close_on_exec(fd, fdt);
809 spin_unlock(&files->file_lock);
810}
811
812bool get_close_on_exec(unsigned int fd)
813{
814 struct files_struct *files = current->files;
815 struct fdtable *fdt;
816 bool res;
817 rcu_read_lock();
818 fdt = files_fdtable(files);
819 res = close_on_exec(fd, fdt);
820 rcu_read_unlock();
821 return res;
822}
823
824SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
825{
826 int err = -EBADF;
827 struct file * file, *tofree;
828 struct files_struct * files = current->files;
829 struct fdtable *fdt;
830
831 if ((flags & ~O_CLOEXEC) != 0)
832 return -EINVAL;
833
834 if (newfd >= rlimit(RLIMIT_NOFILE))
835 return -EMFILE;
836
837 spin_lock(&files->file_lock);
838 err = expand_files(files, newfd);
839 file = fcheck(oldfd);
840 if (unlikely(!file))
841 goto Ebadf;
842 if (unlikely(err < 0)) {
843 if (err == -EMFILE)
844 goto Ebadf;
845 goto out_unlock;
846 }
847 /*
848 * We need to detect attempts to do dup2() over allocated but still
849 * not finished descriptor. NB: OpenBSD avoids that at the price of
850 * extra work in their equivalent of fget() - they insert struct
851 * file immediately after grabbing descriptor, mark it larval if
852 * more work (e.g. actual opening) is needed and make sure that
853 * fget() treats larval files as absent. Potentially interesting,
854 * but while extra work in fget() is trivial, locking implications
855 * and amount of surgery on open()-related paths in VFS are not.
856 * FreeBSD fails with -EBADF in the same situation, NetBSD "solution"
857 * deadlocks in rather amusing ways, AFAICS. All of that is out of
858 * scope of POSIX or SUS, since neither considers shared descriptor
859 * tables and this condition does not arise without those.
860 */
861 err = -EBUSY;
862 fdt = files_fdtable(files);
863 tofree = fdt->fd[newfd];
864 if (!tofree && fd_is_open(newfd, fdt))
865 goto out_unlock;
866 get_file(file);
867 rcu_assign_pointer(fdt->fd[newfd], file);
868 __set_open_fd(newfd, fdt);
869 if (flags & O_CLOEXEC)
870 __set_close_on_exec(newfd, fdt);
871 else
872 __clear_close_on_exec(newfd, fdt);
873 spin_unlock(&files->file_lock);
874
875 if (tofree)
876 filp_close(tofree, files);
877
878 return newfd;
879
880Ebadf:
881 err = -EBADF;
882out_unlock:
883 spin_unlock(&files->file_lock);
884 return err;
885}
886
887SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd)
888{
889 if (unlikely(newfd == oldfd)) { /* corner case */
890 struct files_struct *files = current->files;
891 int retval = oldfd;
892
893 rcu_read_lock();
894 if (!fcheck_files(files, oldfd))
895 retval = -EBADF;
896 rcu_read_unlock();
897 return retval;
898 }
899 return sys_dup3(oldfd, newfd, 0);
900}
901
902SYSCALL_DEFINE1(dup, unsigned int, fildes)
903{
904 int ret = -EBADF;
905 struct file *file = fget_raw(fildes);
906
907 if (file) {
908 ret = get_unused_fd();
909 if (ret >= 0)
910 fd_install(ret, file);
911 else
912 fput(file);
913 }
914 return ret;
915}
916
917int f_dupfd(unsigned int from, struct file *file, unsigned flags)
918{
919 int err;
920 if (from >= rlimit(RLIMIT_NOFILE))
921 return -EINVAL;
922 err = alloc_fd(from, flags);
923 if (err >= 0) {
924 get_file(file);
925 fd_install(err, file);
926 }
927 return err;
928}