aboutsummaryrefslogtreecommitdiffstats
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
parent6a6d27de340c89c5323565b49f7851362619925d (diff)
take purely descriptor-related stuff from fcntl.c to file.c
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/fcntl.c131
-rw-r--r--fs/file.c132
-rw-r--r--include/linux/file.h2
3 files changed, 137 insertions, 128 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 08e6af5c1b1f..40a5bfb72cca 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -26,127 +26,6 @@
26#include <asm/siginfo.h> 26#include <asm/siginfo.h>
27#include <asm/uaccess.h> 27#include <asm/uaccess.h>
28 28
29void set_close_on_exec(unsigned int fd, int flag)
30{
31 struct files_struct *files = current->files;
32 struct fdtable *fdt;
33 spin_lock(&files->file_lock);
34 fdt = files_fdtable(files);
35 if (flag)
36 __set_close_on_exec(fd, fdt);
37 else
38 __clear_close_on_exec(fd, fdt);
39 spin_unlock(&files->file_lock);
40}
41
42static bool get_close_on_exec(unsigned int fd)
43{
44 struct files_struct *files = current->files;
45 struct fdtable *fdt;
46 bool res;
47 rcu_read_lock();
48 fdt = files_fdtable(files);
49 res = close_on_exec(fd, fdt);
50 rcu_read_unlock();
51 return res;
52}
53
54SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
55{
56 int err = -EBADF;
57 struct file * file, *tofree;
58 struct files_struct * files = current->files;
59 struct fdtable *fdt;
60
61 if ((flags & ~O_CLOEXEC) != 0)
62 return -EINVAL;
63
64 if (unlikely(oldfd == newfd))
65 return -EINVAL;
66
67 if (newfd >= rlimit(RLIMIT_NOFILE))
68 return -EMFILE;
69
70 spin_lock(&files->file_lock);
71 err = expand_files(files, newfd);
72 file = fcheck(oldfd);
73 if (unlikely(!file))
74 goto Ebadf;
75 if (unlikely(err < 0)) {
76 if (err == -EMFILE)
77 goto Ebadf;
78 goto out_unlock;
79 }
80 /*
81 * We need to detect attempts to do dup2() over allocated but still
82 * not finished descriptor. NB: OpenBSD avoids that at the price of
83 * extra work in their equivalent of fget() - they insert struct
84 * file immediately after grabbing descriptor, mark it larval if
85 * more work (e.g. actual opening) is needed and make sure that
86 * fget() treats larval files as absent. Potentially interesting,
87 * but while extra work in fget() is trivial, locking implications
88 * and amount of surgery on open()-related paths in VFS are not.
89 * FreeBSD fails with -EBADF in the same situation, NetBSD "solution"
90 * deadlocks in rather amusing ways, AFAICS. All of that is out of
91 * scope of POSIX or SUS, since neither considers shared descriptor
92 * tables and this condition does not arise without those.
93 */
94 err = -EBUSY;
95 fdt = files_fdtable(files);
96 tofree = fdt->fd[newfd];
97 if (!tofree && fd_is_open(newfd, fdt))
98 goto out_unlock;
99 get_file(file);
100 rcu_assign_pointer(fdt->fd[newfd], file);
101 __set_open_fd(newfd, fdt);
102 if (flags & O_CLOEXEC)
103 __set_close_on_exec(newfd, fdt);
104 else
105 __clear_close_on_exec(newfd, fdt);
106 spin_unlock(&files->file_lock);
107
108 if (tofree)
109 filp_close(tofree, files);
110
111 return newfd;
112
113Ebadf:
114 err = -EBADF;
115out_unlock:
116 spin_unlock(&files->file_lock);
117 return err;
118}
119
120SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd)
121{
122 if (unlikely(newfd == oldfd)) { /* corner case */
123 struct files_struct *files = current->files;
124 int retval = oldfd;
125
126 rcu_read_lock();
127 if (!fcheck_files(files, oldfd))
128 retval = -EBADF;
129 rcu_read_unlock();
130 return retval;
131 }
132 return sys_dup3(oldfd, newfd, 0);
133}
134
135SYSCALL_DEFINE1(dup, unsigned int, fildes)
136{
137 int ret = -EBADF;
138 struct file *file = fget_raw(fildes);
139
140 if (file) {
141 ret = get_unused_fd();
142 if (ret >= 0)
143 fd_install(ret, file);
144 else
145 fput(file);
146 }
147 return ret;
148}
149
150#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) 29#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)
151 30
152static int setfl(int fd, struct file * filp, unsigned long arg) 31static int setfl(int fd, struct file * filp, unsigned long arg)
@@ -376,14 +255,10 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
376 255
377 switch (cmd) { 256 switch (cmd) {
378 case F_DUPFD: 257 case F_DUPFD:
258 err = f_dupfd(arg, filp, 0);
259 break;
379 case F_DUPFD_CLOEXEC: 260 case F_DUPFD_CLOEXEC:
380 if (arg >= rlimit(RLIMIT_NOFILE)) 261 err = f_dupfd(arg, filp, FD_CLOEXEC);
381 break;
382 err = alloc_fd(arg, cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0);
383 if (err >= 0) {
384 get_file(filp);
385 fd_install(err, filp);
386 }
387 break; 262 break;
388 case F_GETFD: 263 case F_GETFD:
389 err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; 264 err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
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}
diff --git a/include/linux/file.h b/include/linux/file.h
index 86795ec6027d..da84fa0f4579 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -30,7 +30,9 @@ extern struct file *fget(unsigned int fd);
30extern struct file *fget_light(unsigned int fd, int *fput_needed); 30extern struct file *fget_light(unsigned int fd, int *fput_needed);
31extern struct file *fget_raw(unsigned int fd); 31extern struct file *fget_raw(unsigned int fd);
32extern struct file *fget_raw_light(unsigned int fd, int *fput_needed); 32extern struct file *fget_raw_light(unsigned int fd, int *fput_needed);
33extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
33extern void set_close_on_exec(unsigned int fd, int flag); 34extern void set_close_on_exec(unsigned int fd, int flag);
35extern bool get_close_on_exec(unsigned int fd);
34extern void put_filp(struct file *); 36extern void put_filp(struct file *);
35extern int alloc_fd(unsigned start, unsigned flags); 37extern int alloc_fd(unsigned start, unsigned flags);
36extern int get_unused_fd_flags(unsigned flags); 38extern int get_unused_fd_flags(unsigned flags);