diff options
| -rw-r--r-- | fs/fcntl.c | 87 | ||||
| -rw-r--r-- | fs/file.c | 61 | ||||
| -rw-r--r-- | fs/open.c | 56 | ||||
| -rw-r--r-- | include/linux/file.h | 3 |
4 files changed, 77 insertions, 130 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; |
| @@ -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/module.h> | ||
| 9 | #include <linux/fs.h> | 10 | #include <linux/fs.h> |
| 10 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
| 11 | #include <linux/time.h> | 12 | #include <linux/time.h> |
| @@ -432,3 +433,63 @@ struct files_struct init_files = { | |||
| 432 | }, | 433 | }, |
| 433 | .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock), | 434 | .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock), |
| 434 | }; | 435 | }; |
| 436 | |||
| 437 | /* | ||
| 438 | * allocate a file descriptor, mark it busy. | ||
| 439 | */ | ||
| 440 | int alloc_fd(unsigned start, unsigned flags) | ||
| 441 | { | ||
| 442 | struct files_struct *files = current->files; | ||
| 443 | unsigned int fd; | ||
| 444 | int error; | ||
| 445 | struct fdtable *fdt; | ||
| 446 | |||
| 447 | spin_lock(&files->file_lock); | ||
| 448 | repeat: | ||
| 449 | fdt = files_fdtable(files); | ||
| 450 | fd = start; | ||
| 451 | if (fd < files->next_fd) | ||
| 452 | fd = files->next_fd; | ||
| 453 | |||
| 454 | if (fd < fdt->max_fds) | ||
| 455 | fd = find_next_zero_bit(fdt->open_fds->fds_bits, | ||
| 456 | fdt->max_fds, fd); | ||
| 457 | |||
| 458 | error = expand_files(files, fd); | ||
| 459 | if (error < 0) | ||
| 460 | goto out; | ||
| 461 | |||
| 462 | /* | ||
| 463 | * If we needed to expand the fs array we | ||
| 464 | * might have blocked - try again. | ||
| 465 | */ | ||
| 466 | if (error) | ||
| 467 | goto repeat; | ||
| 468 | |||
| 469 | if (start <= files->next_fd) | ||
| 470 | files->next_fd = fd + 1; | ||
| 471 | |||
| 472 | FD_SET(fd, fdt->open_fds); | ||
| 473 | if (flags & O_CLOEXEC) | ||
| 474 | FD_SET(fd, fdt->close_on_exec); | ||
| 475 | else | ||
| 476 | FD_CLR(fd, fdt->close_on_exec); | ||
| 477 | error = fd; | ||
| 478 | #if 1 | ||
| 479 | /* Sanity check */ | ||
| 480 | if (rcu_dereference(fdt->fd[fd]) != NULL) { | ||
| 481 | printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd); | ||
| 482 | rcu_assign_pointer(fdt->fd[fd], NULL); | ||
| 483 | } | ||
| 484 | #endif | ||
| 485 | |||
| 486 | out: | ||
| 487 | spin_unlock(&files->file_lock); | ||
| 488 | return error; | ||
| 489 | } | ||
| 490 | |||
| 491 | int get_unused_fd(void) | ||
| 492 | { | ||
| 493 | return alloc_fd(0, 0); | ||
| 494 | } | ||
| 495 | EXPORT_SYMBOL(get_unused_fd); | ||
| @@ -963,62 +963,6 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | |||
| 963 | } | 963 | } |
| 964 | EXPORT_SYMBOL(dentry_open); | 964 | EXPORT_SYMBOL(dentry_open); |
| 965 | 965 | ||
| 966 | /* | ||
| 967 | * Find an empty file descriptor entry, and mark it busy. | ||
| 968 | */ | ||
| 969 | int get_unused_fd_flags(int flags) | ||
| 970 | { | ||
| 971 | struct files_struct * files = current->files; | ||
| 972 | int fd, error; | ||
| 973 | struct fdtable *fdt; | ||
| 974 | |||
| 975 | spin_lock(&files->file_lock); | ||
| 976 | |||
| 977 | repeat: | ||
| 978 | fdt = files_fdtable(files); | ||
| 979 | fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds, | ||
| 980 | files->next_fd); | ||
| 981 | |||
| 982 | /* Do we need to expand the fd array or fd set? */ | ||
| 983 | error = expand_files(files, fd); | ||
| 984 | if (error < 0) | ||
| 985 | goto out; | ||
| 986 | |||
| 987 | if (error) { | ||
| 988 | /* | ||
| 989 | * If we needed to expand the fs array we | ||
| 990 | * might have blocked - try again. | ||
| 991 | */ | ||
| 992 | goto repeat; | ||
| 993 | } | ||
| 994 | |||
| 995 | FD_SET(fd, fdt->open_fds); | ||
| 996 | if (flags & O_CLOEXEC) | ||
| 997 | FD_SET(fd, fdt->close_on_exec); | ||
| 998 | else | ||
| 999 | FD_CLR(fd, fdt->close_on_exec); | ||
| 1000 | files->next_fd = fd + 1; | ||
| 1001 | #if 1 | ||
| 1002 | /* Sanity check */ | ||
| 1003 | if (fdt->fd[fd] != NULL) { | ||
| 1004 | printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); | ||
| 1005 | fdt->fd[fd] = NULL; | ||
| 1006 | } | ||
| 1007 | #endif | ||
| 1008 | error = fd; | ||
| 1009 | |||
| 1010 | out: | ||
| 1011 | spin_unlock(&files->file_lock); | ||
| 1012 | return error; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | int get_unused_fd(void) | ||
| 1016 | { | ||
| 1017 | return get_unused_fd_flags(0); | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | EXPORT_SYMBOL(get_unused_fd); | ||
| 1021 | |||
| 1022 | static void __put_unused_fd(struct files_struct *files, unsigned int fd) | 966 | static void __put_unused_fd(struct files_struct *files, unsigned int fd) |
| 1023 | { | 967 | { |
| 1024 | struct fdtable *fdt = files_fdtable(files); | 968 | struct fdtable *fdt = files_fdtable(files); |
diff --git a/include/linux/file.h b/include/linux/file.h index 27c64bdc68c9..a20259e248a5 100644 --- a/include/linux/file.h +++ b/include/linux/file.h | |||
| @@ -34,8 +34,9 @@ extern struct file *fget(unsigned int fd); | |||
| 34 | extern struct file *fget_light(unsigned int fd, int *fput_needed); | 34 | extern struct file *fget_light(unsigned int fd, int *fput_needed); |
| 35 | extern void set_close_on_exec(unsigned int fd, int flag); | 35 | extern void set_close_on_exec(unsigned int fd, int flag); |
| 36 | extern void put_filp(struct file *); | 36 | extern void put_filp(struct file *); |
| 37 | extern int alloc_fd(unsigned start, unsigned flags); | ||
| 37 | extern int get_unused_fd(void); | 38 | extern int get_unused_fd(void); |
| 38 | extern int get_unused_fd_flags(int flags); | 39 | #define get_unused_fd_flags(flags) alloc_fd(0, (flags)) |
| 39 | extern void put_unused_fd(unsigned int fd); | 40 | extern void put_unused_fd(unsigned int fd); |
| 40 | 41 | ||
| 41 | extern void fd_install(unsigned int fd, struct file *file); | 42 | extern void fd_install(unsigned int fd, struct file *file); |
