summaryrefslogtreecommitdiffstats
path: root/fs/fcntl.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/fcntl.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/fcntl.c')
-rw-r--r--fs/fcntl.c131
1 files changed, 3 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;