···4949 return res;5050}51515252-/*5353- * locate_fd finds a free file descriptor in the open_fds fdset,5454- * expanding the fd arrays if necessary. Must be called with the5555- * file_lock held for write.5656- */5757-5858-static int locate_fd(unsigned int orig_start, int cloexec)5959-{6060- struct files_struct *files = current->files;6161- unsigned int newfd;6262- unsigned int start;6363- int error;6464- struct fdtable *fdt;6565-6666- spin_lock(&files->file_lock);6767-repeat:6868- fdt = files_fdtable(files);6969- /*7070- * Someone might have closed fd's in the range7171- * orig_start..fdt->next_fd7272- */7373- start = orig_start;7474- if (start < files->next_fd)7575- start = files->next_fd;7676-7777- newfd = start;7878- if (start < fdt->max_fds)7979- newfd = find_next_zero_bit(fdt->open_fds->fds_bits,8080- fdt->max_fds, start);8181-8282- error = expand_files(files, newfd);8383- if (error < 0)8484- goto out;8585-8686- /*8787- * If we needed to expand the fs array we8888- * might have blocked - try again.8989- */9090- if (error)9191- goto repeat;9292-9393- if (start <= files->next_fd)9494- files->next_fd = newfd + 1;9595-9696- FD_SET(newfd, fdt->open_fds);9797- if (cloexec)9898- FD_SET(newfd, fdt->close_on_exec);9999- else100100- FD_CLR(newfd, fdt->close_on_exec);101101- error = newfd;102102-103103-out:104104- spin_unlock(&files->file_lock);105105- return error;106106-}107107-108108-static int dupfd(struct file *file, unsigned int start, int cloexec)109109-{110110- int fd = locate_fd(start, cloexec);111111- if (fd >= 0)112112- fd_install(fd, file);113113- else114114- fput(file);115115-116116- return fd;117117-}118118-11952asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags)12053{12154 int err = -EBADF;···127194asmlinkage long sys_dup(unsigned int fildes)128195{129196 int ret = -EBADF;130130- struct file * file = fget(fildes);197197+ struct file *file = fget(fildes);131198132132- if (file)133133- ret = dupfd(file, 0, 0);199199+ if (file) {200200+ ret = get_unused_fd();201201+ if (ret >= 0)202202+ fd_install(ret, file);203203+ else204204+ fput(file);205205+ }134206 return ret;135207}136208···260322 case F_DUPFD_CLOEXEC:261323 if (arg >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)262324 break;263263- get_file(filp);264264- err = dupfd(filp, arg, cmd == F_DUPFD_CLOEXEC);325325+ err = alloc_fd(arg, cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0);326326+ if (err >= 0) {327327+ get_file(filp);328328+ fd_install(err, filp);329329+ }265330 break;266331 case F_GETFD:267332 err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
+61
fs/file.c
···66 * Manage the dynamic fd arrays in the process files_struct.77 */8899+#include <linux/module.h>910#include <linux/fs.h>1011#include <linux/mm.h>1112#include <linux/time.h>···433432 },434433 .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock),435434};435435+436436+/*437437+ * allocate a file descriptor, mark it busy.438438+ */439439+int alloc_fd(unsigned start, unsigned flags)440440+{441441+ struct files_struct *files = current->files;442442+ unsigned int fd;443443+ int error;444444+ struct fdtable *fdt;445445+446446+ spin_lock(&files->file_lock);447447+repeat:448448+ fdt = files_fdtable(files);449449+ fd = start;450450+ if (fd < files->next_fd)451451+ fd = files->next_fd;452452+453453+ if (fd < fdt->max_fds)454454+ fd = find_next_zero_bit(fdt->open_fds->fds_bits,455455+ fdt->max_fds, fd);456456+457457+ error = expand_files(files, fd);458458+ if (error < 0)459459+ goto out;460460+461461+ /*462462+ * If we needed to expand the fs array we463463+ * might have blocked - try again.464464+ */465465+ if (error)466466+ goto repeat;467467+468468+ if (start <= files->next_fd)469469+ files->next_fd = fd + 1;470470+471471+ FD_SET(fd, fdt->open_fds);472472+ if (flags & O_CLOEXEC)473473+ FD_SET(fd, fdt->close_on_exec);474474+ else475475+ FD_CLR(fd, fdt->close_on_exec);476476+ error = fd;477477+#if 1478478+ /* Sanity check */479479+ if (rcu_dereference(fdt->fd[fd]) != NULL) {480480+ printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd);481481+ rcu_assign_pointer(fdt->fd[fd], NULL);482482+ }483483+#endif484484+485485+out:486486+ spin_unlock(&files->file_lock);487487+ return error;488488+}489489+490490+int get_unused_fd(void)491491+{492492+ return alloc_fd(0, 0);493493+}494494+EXPORT_SYMBOL(get_unused_fd);
-56
fs/open.c
···963963}964964EXPORT_SYMBOL(dentry_open);965965966966-/*967967- * Find an empty file descriptor entry, and mark it busy.968968- */969969-int get_unused_fd_flags(int flags)970970-{971971- struct files_struct * files = current->files;972972- int fd, error;973973- struct fdtable *fdt;974974-975975- spin_lock(&files->file_lock);976976-977977-repeat:978978- fdt = files_fdtable(files);979979- fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,980980- files->next_fd);981981-982982- /* Do we need to expand the fd array or fd set? */983983- error = expand_files(files, fd);984984- if (error < 0)985985- goto out;986986-987987- if (error) {988988- /*989989- * If we needed to expand the fs array we990990- * might have blocked - try again.991991- */992992- goto repeat;993993- }994994-995995- FD_SET(fd, fdt->open_fds);996996- if (flags & O_CLOEXEC)997997- FD_SET(fd, fdt->close_on_exec);998998- else999999- FD_CLR(fd, fdt->close_on_exec);10001000- files->next_fd = fd + 1;10011001-#if 110021002- /* Sanity check */10031003- if (fdt->fd[fd] != NULL) {10041004- printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd);10051005- fdt->fd[fd] = NULL;10061006- }10071007-#endif10081008- error = fd;10091009-10101010-out:10111011- spin_unlock(&files->file_lock);10121012- return error;10131013-}10141014-10151015-int get_unused_fd(void)10161016-{10171017- return get_unused_fd_flags(0);10181018-}10191019-10201020-EXPORT_SYMBOL(get_unused_fd);10211021-1022966static void __put_unused_fd(struct files_struct *files, unsigned int fd)1023967{1024968 struct fdtable *fdt = files_fdtable(files);
+2-1
include/linux/file.h
···3434extern struct file *fget_light(unsigned int fd, int *fput_needed);3535extern void set_close_on_exec(unsigned int fd, int flag);3636extern void put_filp(struct file *);3737+extern int alloc_fd(unsigned start, unsigned flags);3738extern int get_unused_fd(void);3838-extern int get_unused_fd_flags(int flags);3939+#define get_unused_fd_flags(flags) alloc_fd(0, (flags))3940extern void put_unused_fd(unsigned int fd);40414142extern void fd_install(unsigned int fd, struct file *file);