Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] merge locate_fd() and get_unused_fd()

New primitive: alloc_fd(start, flags). get_unused_fd() and
get_unused_fd_flags() become wrappers on top of it.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro 1027abe8 a1bc6eb4

+76 -129
+13 -72
fs/fcntl.c
··· 49 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 52 asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags) 120 53 { 121 54 int err = -EBADF; ··· 127 194 asmlinkage long sys_dup(unsigned int fildes) 128 195 { 129 196 int ret = -EBADF; 130 - struct file * file = fget(fildes); 197 + struct file *file = fget(fildes); 131 198 132 - if (file) 133 - ret = dupfd(file, 0, 0); 199 + if (file) { 200 + ret = get_unused_fd(); 201 + if (ret >= 0) 202 + fd_install(ret, file); 203 + else 204 + fput(file); 205 + } 134 206 return ret; 135 207 } 136 208 ··· 260 322 case F_DUPFD_CLOEXEC: 261 323 if (arg >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) 262 324 break; 263 - get_file(filp); 264 - err = dupfd(filp, arg, cmd == F_DUPFD_CLOEXEC); 325 + err = alloc_fd(arg, cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0); 326 + if (err >= 0) { 327 + get_file(filp); 328 + fd_install(err, filp); 329 + } 265 330 break; 266 331 case F_GETFD: 267 332 err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
+61
fs/file.c
··· 6 6 * Manage the dynamic fd arrays in the process files_struct. 7 7 */ 8 8 9 + #include <linux/module.h> 9 10 #include <linux/fs.h> 10 11 #include <linux/mm.h> 11 12 #include <linux/time.h> ··· 433 432 }, 434 433 .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock), 435 434 }; 435 + 436 + /* 437 + * allocate a file descriptor, mark it busy. 438 + */ 439 + int alloc_fd(unsigned start, unsigned flags) 440 + { 441 + struct files_struct *files = current->files; 442 + unsigned int fd; 443 + int error; 444 + struct fdtable *fdt; 445 + 446 + spin_lock(&files->file_lock); 447 + repeat: 448 + fdt = files_fdtable(files); 449 + fd = start; 450 + if (fd < files->next_fd) 451 + fd = files->next_fd; 452 + 453 + if (fd < fdt->max_fds) 454 + fd = find_next_zero_bit(fdt->open_fds->fds_bits, 455 + fdt->max_fds, fd); 456 + 457 + error = expand_files(files, fd); 458 + if (error < 0) 459 + goto out; 460 + 461 + /* 462 + * If we needed to expand the fs array we 463 + * might have blocked - try again. 464 + */ 465 + if (error) 466 + goto repeat; 467 + 468 + if (start <= files->next_fd) 469 + files->next_fd = fd + 1; 470 + 471 + FD_SET(fd, fdt->open_fds); 472 + if (flags & O_CLOEXEC) 473 + FD_SET(fd, fdt->close_on_exec); 474 + else 475 + FD_CLR(fd, fdt->close_on_exec); 476 + error = fd; 477 + #if 1 478 + /* Sanity check */ 479 + if (rcu_dereference(fdt->fd[fd]) != NULL) { 480 + printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd); 481 + rcu_assign_pointer(fdt->fd[fd], NULL); 482 + } 483 + #endif 484 + 485 + out: 486 + spin_unlock(&files->file_lock); 487 + return error; 488 + } 489 + 490 + int get_unused_fd(void) 491 + { 492 + return alloc_fd(0, 0); 493 + } 494 + EXPORT_SYMBOL(get_unused_fd);
-56
fs/open.c
··· 963 963 } 964 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 966 static void __put_unused_fd(struct files_struct *files, unsigned int fd) 1023 967 { 1024 968 struct fdtable *fdt = files_fdtable(files);
+2 -1
include/linux/file.h
··· 34 34 extern struct file *fget_light(unsigned int fd, int *fput_needed); 35 35 extern void set_close_on_exec(unsigned int fd, int flag); 36 36 extern void put_filp(struct file *); 37 + extern int alloc_fd(unsigned start, unsigned flags); 37 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 40 extern void put_unused_fd(unsigned int fd); 40 41 41 42 extern void fd_install(unsigned int fd, struct file *file);