diff options
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r-- | fs/fcntl.c | 87 |
1 files changed, 14 insertions, 73 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c index 61d625136813..2e40799daad6 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -49,73 +49,6 @@ static int get_close_on_exec(unsigned int fd) | |||
49 | return res; | 49 | return res; |
50 | } | 50 | } |
51 | 51 | ||
52 | /* | ||
53 | * locate_fd finds a free file descriptor in the open_fds fdset, | ||
54 | * expanding the fd arrays if necessary. Must be called with the | ||
55 | * file_lock held for write. | ||
56 | */ | ||
57 | |||
58 | static int locate_fd(unsigned int orig_start, int cloexec) | ||
59 | { | ||
60 | struct files_struct *files = current->files; | ||
61 | unsigned int newfd; | ||
62 | unsigned int start; | ||
63 | int error; | ||
64 | struct fdtable *fdt; | ||
65 | |||
66 | spin_lock(&files->file_lock); | ||
67 | repeat: | ||
68 | fdt = files_fdtable(files); | ||
69 | /* | ||
70 | * Someone might have closed fd's in the range | ||
71 | * orig_start..fdt->next_fd | ||
72 | */ | ||
73 | start = orig_start; | ||
74 | if (start < files->next_fd) | ||
75 | start = files->next_fd; | ||
76 | |||
77 | newfd = start; | ||
78 | if (start < fdt->max_fds) | ||
79 | newfd = find_next_zero_bit(fdt->open_fds->fds_bits, | ||
80 | fdt->max_fds, start); | ||
81 | |||
82 | error = expand_files(files, newfd); | ||
83 | if (error < 0) | ||
84 | goto out; | ||
85 | |||
86 | /* | ||
87 | * If we needed to expand the fs array we | ||
88 | * might have blocked - try again. | ||
89 | */ | ||
90 | if (error) | ||
91 | goto repeat; | ||
92 | |||
93 | if (start <= files->next_fd) | ||
94 | files->next_fd = newfd + 1; | ||
95 | |||
96 | FD_SET(newfd, fdt->open_fds); | ||
97 | if (cloexec) | ||
98 | FD_SET(newfd, fdt->close_on_exec); | ||
99 | else | ||
100 | FD_CLR(newfd, fdt->close_on_exec); | ||
101 | error = newfd; | ||
102 | |||
103 | out: | ||
104 | spin_unlock(&files->file_lock); | ||
105 | return error; | ||
106 | } | ||
107 | |||
108 | static int dupfd(struct file *file, unsigned int start, int cloexec) | ||
109 | { | ||
110 | int fd = locate_fd(start, cloexec); | ||
111 | if (fd >= 0) | ||
112 | fd_install(fd, file); | ||
113 | else | ||
114 | fput(file); | ||
115 | |||
116 | return fd; | ||
117 | } | ||
118 | |||
119 | asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags) | 52 | asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags) |
120 | { | 53 | { |
121 | int err = -EBADF; | 54 | int err = -EBADF; |
@@ -194,10 +127,15 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) | |||
194 | asmlinkage long sys_dup(unsigned int fildes) | 127 | asmlinkage long sys_dup(unsigned int fildes) |
195 | { | 128 | { |
196 | int ret = -EBADF; | 129 | int ret = -EBADF; |
197 | struct file * file = fget(fildes); | 130 | struct file *file = fget(fildes); |
198 | 131 | ||
199 | if (file) | 132 | if (file) { |
200 | ret = dupfd(file, 0, 0); | 133 | ret = get_unused_fd(); |
134 | if (ret >= 0) | ||
135 | fd_install(ret, file); | ||
136 | else | ||
137 | fput(file); | ||
138 | } | ||
201 | return ret; | 139 | return ret; |
202 | } | 140 | } |
203 | 141 | ||
@@ -322,8 +260,11 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, | |||
322 | case F_DUPFD_CLOEXEC: | 260 | case F_DUPFD_CLOEXEC: |
323 | if (arg >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) | 261 | if (arg >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) |
324 | break; | 262 | break; |
325 | get_file(filp); | 263 | err = alloc_fd(arg, cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0); |
326 | err = dupfd(filp, arg, cmd == F_DUPFD_CLOEXEC); | 264 | if (err >= 0) { |
265 | get_file(filp); | ||
266 | fd_install(err, filp); | ||
267 | } | ||
327 | break; | 268 | break; |
328 | case F_GETFD: | 269 | case F_GETFD: |
329 | err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; | 270 | err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; |