diff options
Diffstat (limited to 'fs/file.c')
-rw-r--r-- | fs/file.c | 573 |
1 files changed, 549 insertions, 24 deletions
@@ -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/syscalls.h> | ||
9 | #include <linux/export.h> | 10 | #include <linux/export.h> |
10 | #include <linux/fs.h> | 11 | #include <linux/fs.h> |
11 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
@@ -84,22 +85,14 @@ static void free_fdtable_work(struct work_struct *work) | |||
84 | } | 85 | } |
85 | } | 86 | } |
86 | 87 | ||
87 | void free_fdtable_rcu(struct rcu_head *rcu) | 88 | static void free_fdtable_rcu(struct rcu_head *rcu) |
88 | { | 89 | { |
89 | struct fdtable *fdt = container_of(rcu, struct fdtable, rcu); | 90 | struct fdtable *fdt = container_of(rcu, struct fdtable, rcu); |
90 | struct fdtable_defer *fddef; | 91 | struct fdtable_defer *fddef; |
91 | 92 | ||
92 | BUG_ON(!fdt); | 93 | BUG_ON(!fdt); |
94 | BUG_ON(fdt->max_fds <= NR_OPEN_DEFAULT); | ||
93 | 95 | ||
94 | if (fdt->max_fds <= NR_OPEN_DEFAULT) { | ||
95 | /* | ||
96 | * This fdtable is embedded in the files structure and that | ||
97 | * structure itself is getting destroyed. | ||
98 | */ | ||
99 | kmem_cache_free(files_cachep, | ||
100 | container_of(fdt, struct files_struct, fdtab)); | ||
101 | return; | ||
102 | } | ||
103 | if (!is_vmalloc_addr(fdt->fd) && !is_vmalloc_addr(fdt->open_fds)) { | 96 | if (!is_vmalloc_addr(fdt->fd) && !is_vmalloc_addr(fdt->open_fds)) { |
104 | kfree(fdt->fd); | 97 | kfree(fdt->fd); |
105 | kfree(fdt->open_fds); | 98 | kfree(fdt->open_fds); |
@@ -229,7 +222,7 @@ static int expand_fdtable(struct files_struct *files, int nr) | |||
229 | copy_fdtable(new_fdt, cur_fdt); | 222 | copy_fdtable(new_fdt, cur_fdt); |
230 | rcu_assign_pointer(files->fdt, new_fdt); | 223 | rcu_assign_pointer(files->fdt, new_fdt); |
231 | if (cur_fdt->max_fds > NR_OPEN_DEFAULT) | 224 | if (cur_fdt->max_fds > NR_OPEN_DEFAULT) |
232 | free_fdtable(cur_fdt); | 225 | call_rcu(&cur_fdt->rcu, free_fdtable_rcu); |
233 | } else { | 226 | } else { |
234 | /* Somebody else expanded, so undo our attempt */ | 227 | /* Somebody else expanded, so undo our attempt */ |
235 | __free_fdtable(new_fdt); | 228 | __free_fdtable(new_fdt); |
@@ -245,19 +238,12 @@ static int expand_fdtable(struct files_struct *files, int nr) | |||
245 | * expanded and execution may have blocked. | 238 | * expanded and execution may have blocked. |
246 | * The files->file_lock should be held on entry, and will be held on exit. | 239 | * The files->file_lock should be held on entry, and will be held on exit. |
247 | */ | 240 | */ |
248 | int expand_files(struct files_struct *files, int nr) | 241 | static int expand_files(struct files_struct *files, int nr) |
249 | { | 242 | { |
250 | struct fdtable *fdt; | 243 | struct fdtable *fdt; |
251 | 244 | ||
252 | fdt = files_fdtable(files); | 245 | fdt = files_fdtable(files); |
253 | 246 | ||
254 | /* | ||
255 | * N.B. For clone tasks sharing a files structure, this test | ||
256 | * will limit the total number of files that can be opened. | ||
257 | */ | ||
258 | if (nr >= rlimit(RLIMIT_NOFILE)) | ||
259 | return -EMFILE; | ||
260 | |||
261 | /* Do we need to expand? */ | 247 | /* Do we need to expand? */ |
262 | if (nr < fdt->max_fds) | 248 | if (nr < fdt->max_fds) |
263 | return 0; | 249 | return 0; |
@@ -270,6 +256,26 @@ int expand_files(struct files_struct *files, int nr) | |||
270 | return expand_fdtable(files, nr); | 256 | return expand_fdtable(files, nr); |
271 | } | 257 | } |
272 | 258 | ||
259 | static inline void __set_close_on_exec(int fd, struct fdtable *fdt) | ||
260 | { | ||
261 | __set_bit(fd, fdt->close_on_exec); | ||
262 | } | ||
263 | |||
264 | static inline void __clear_close_on_exec(int fd, struct fdtable *fdt) | ||
265 | { | ||
266 | __clear_bit(fd, fdt->close_on_exec); | ||
267 | } | ||
268 | |||
269 | static inline void __set_open_fd(int fd, struct fdtable *fdt) | ||
270 | { | ||
271 | __set_bit(fd, fdt->open_fds); | ||
272 | } | ||
273 | |||
274 | static inline void __clear_open_fd(int fd, struct fdtable *fdt) | ||
275 | { | ||
276 | __clear_bit(fd, fdt->open_fds); | ||
277 | } | ||
278 | |||
273 | static int count_open_files(struct fdtable *fdt) | 279 | static int count_open_files(struct fdtable *fdt) |
274 | { | 280 | { |
275 | int size = fdt->max_fds; | 281 | int size = fdt->max_fds; |
@@ -395,6 +401,95 @@ out: | |||
395 | return NULL; | 401 | return NULL; |
396 | } | 402 | } |
397 | 403 | ||
404 | static void close_files(struct files_struct * files) | ||
405 | { | ||
406 | int i, j; | ||
407 | struct fdtable *fdt; | ||
408 | |||
409 | j = 0; | ||
410 | |||
411 | /* | ||
412 | * It is safe to dereference the fd table without RCU or | ||
413 | * ->file_lock because this is the last reference to the | ||
414 | * files structure. But use RCU to shut RCU-lockdep up. | ||
415 | */ | ||
416 | rcu_read_lock(); | ||
417 | fdt = files_fdtable(files); | ||
418 | rcu_read_unlock(); | ||
419 | for (;;) { | ||
420 | unsigned long set; | ||
421 | i = j * BITS_PER_LONG; | ||
422 | if (i >= fdt->max_fds) | ||
423 | break; | ||
424 | set = fdt->open_fds[j++]; | ||
425 | while (set) { | ||
426 | if (set & 1) { | ||
427 | struct file * file = xchg(&fdt->fd[i], NULL); | ||
428 | if (file) { | ||
429 | filp_close(file, files); | ||
430 | cond_resched(); | ||
431 | } | ||
432 | } | ||
433 | i++; | ||
434 | set >>= 1; | ||
435 | } | ||
436 | } | ||
437 | } | ||
438 | |||
439 | struct files_struct *get_files_struct(struct task_struct *task) | ||
440 | { | ||
441 | struct files_struct *files; | ||
442 | |||
443 | task_lock(task); | ||
444 | files = task->files; | ||
445 | if (files) | ||
446 | atomic_inc(&files->count); | ||
447 | task_unlock(task); | ||
448 | |||
449 | return files; | ||
450 | } | ||
451 | |||
452 | void put_files_struct(struct files_struct *files) | ||
453 | { | ||
454 | struct fdtable *fdt; | ||
455 | |||
456 | if (atomic_dec_and_test(&files->count)) { | ||
457 | close_files(files); | ||
458 | /* not really needed, since nobody can see us */ | ||
459 | rcu_read_lock(); | ||
460 | fdt = files_fdtable(files); | ||
461 | rcu_read_unlock(); | ||
462 | /* free the arrays if they are not embedded */ | ||
463 | if (fdt != &files->fdtab) | ||
464 | __free_fdtable(fdt); | ||
465 | kmem_cache_free(files_cachep, files); | ||
466 | } | ||
467 | } | ||
468 | |||
469 | void reset_files_struct(struct files_struct *files) | ||
470 | { | ||
471 | struct task_struct *tsk = current; | ||
472 | struct files_struct *old; | ||
473 | |||
474 | old = tsk->files; | ||
475 | task_lock(tsk); | ||
476 | tsk->files = files; | ||
477 | task_unlock(tsk); | ||
478 | put_files_struct(old); | ||
479 | } | ||
480 | |||
481 | void exit_files(struct task_struct *tsk) | ||
482 | { | ||
483 | struct files_struct * files = tsk->files; | ||
484 | |||
485 | if (files) { | ||
486 | task_lock(tsk); | ||
487 | tsk->files = NULL; | ||
488 | task_unlock(tsk); | ||
489 | put_files_struct(files); | ||
490 | } | ||
491 | } | ||
492 | |||
398 | static void __devinit fdtable_defer_list_init(int cpu) | 493 | static void __devinit fdtable_defer_list_init(int cpu) |
399 | { | 494 | { |
400 | struct fdtable_defer *fddef = &per_cpu(fdtable_defer_list, cpu); | 495 | struct fdtable_defer *fddef = &per_cpu(fdtable_defer_list, cpu); |
@@ -424,12 +519,18 @@ struct files_struct init_files = { | |||
424 | .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock), | 519 | .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock), |
425 | }; | 520 | }; |
426 | 521 | ||
522 | void daemonize_descriptors(void) | ||
523 | { | ||
524 | atomic_inc(&init_files.count); | ||
525 | reset_files_struct(&init_files); | ||
526 | } | ||
527 | |||
427 | /* | 528 | /* |
428 | * allocate a file descriptor, mark it busy. | 529 | * allocate a file descriptor, mark it busy. |
429 | */ | 530 | */ |
430 | int alloc_fd(unsigned start, unsigned flags) | 531 | int __alloc_fd(struct files_struct *files, |
532 | unsigned start, unsigned end, unsigned flags) | ||
431 | { | 533 | { |
432 | struct files_struct *files = current->files; | ||
433 | unsigned int fd; | 534 | unsigned int fd; |
434 | int error; | 535 | int error; |
435 | struct fdtable *fdt; | 536 | struct fdtable *fdt; |
@@ -444,6 +545,14 @@ repeat: | |||
444 | if (fd < fdt->max_fds) | 545 | if (fd < fdt->max_fds) |
445 | fd = find_next_zero_bit(fdt->open_fds, fdt->max_fds, fd); | 546 | fd = find_next_zero_bit(fdt->open_fds, fdt->max_fds, fd); |
446 | 547 | ||
548 | /* | ||
549 | * N.B. For clone tasks sharing a files structure, this test | ||
550 | * will limit the total number of files that can be opened. | ||
551 | */ | ||
552 | error = -EMFILE; | ||
553 | if (fd >= end) | ||
554 | goto out; | ||
555 | |||
447 | error = expand_files(files, fd); | 556 | error = expand_files(files, fd); |
448 | if (error < 0) | 557 | if (error < 0) |
449 | goto out; | 558 | goto out; |
@@ -477,8 +586,424 @@ out: | |||
477 | return error; | 586 | return error; |
478 | } | 587 | } |
479 | 588 | ||
480 | int get_unused_fd(void) | 589 | static int alloc_fd(unsigned start, unsigned flags) |
590 | { | ||
591 | return __alloc_fd(current->files, start, rlimit(RLIMIT_NOFILE), flags); | ||
592 | } | ||
593 | |||
594 | int get_unused_fd_flags(unsigned flags) | ||
595 | { | ||
596 | return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags); | ||
597 | } | ||
598 | EXPORT_SYMBOL(get_unused_fd_flags); | ||
599 | |||
600 | static void __put_unused_fd(struct files_struct *files, unsigned int fd) | ||
601 | { | ||
602 | struct fdtable *fdt = files_fdtable(files); | ||
603 | __clear_open_fd(fd, fdt); | ||
604 | if (fd < files->next_fd) | ||
605 | files->next_fd = fd; | ||
606 | } | ||
607 | |||
608 | void put_unused_fd(unsigned int fd) | ||
609 | { | ||
610 | struct files_struct *files = current->files; | ||
611 | spin_lock(&files->file_lock); | ||
612 | __put_unused_fd(files, fd); | ||
613 | spin_unlock(&files->file_lock); | ||
614 | } | ||
615 | |||
616 | EXPORT_SYMBOL(put_unused_fd); | ||
617 | |||
618 | /* | ||
619 | * Install a file pointer in the fd array. | ||
620 | * | ||
621 | * The VFS is full of places where we drop the files lock between | ||
622 | * setting the open_fds bitmap and installing the file in the file | ||
623 | * array. At any such point, we are vulnerable to a dup2() race | ||
624 | * installing a file in the array before us. We need to detect this and | ||
625 | * fput() the struct file we are about to overwrite in this case. | ||
626 | * | ||
627 | * It should never happen - if we allow dup2() do it, _really_ bad things | ||
628 | * will follow. | ||
629 | * | ||
630 | * NOTE: __fd_install() variant is really, really low-level; don't | ||
631 | * use it unless you are forced to by truly lousy API shoved down | ||
632 | * your throat. 'files' *MUST* be either current->files or obtained | ||
633 | * by get_files_struct(current) done by whoever had given it to you, | ||
634 | * or really bad things will happen. Normally you want to use | ||
635 | * fd_install() instead. | ||
636 | */ | ||
637 | |||
638 | void __fd_install(struct files_struct *files, unsigned int fd, | ||
639 | struct file *file) | ||
640 | { | ||
641 | struct fdtable *fdt; | ||
642 | spin_lock(&files->file_lock); | ||
643 | fdt = files_fdtable(files); | ||
644 | BUG_ON(fdt->fd[fd] != NULL); | ||
645 | rcu_assign_pointer(fdt->fd[fd], file); | ||
646 | spin_unlock(&files->file_lock); | ||
647 | } | ||
648 | |||
649 | void fd_install(unsigned int fd, struct file *file) | ||
481 | { | 650 | { |
482 | return alloc_fd(0, 0); | 651 | __fd_install(current->files, fd, file); |
652 | } | ||
653 | |||
654 | EXPORT_SYMBOL(fd_install); | ||
655 | |||
656 | /* | ||
657 | * The same warnings as for __alloc_fd()/__fd_install() apply here... | ||
658 | */ | ||
659 | int __close_fd(struct files_struct *files, unsigned fd) | ||
660 | { | ||
661 | struct file *file; | ||
662 | struct fdtable *fdt; | ||
663 | |||
664 | spin_lock(&files->file_lock); | ||
665 | fdt = files_fdtable(files); | ||
666 | if (fd >= fdt->max_fds) | ||
667 | goto out_unlock; | ||
668 | file = fdt->fd[fd]; | ||
669 | if (!file) | ||
670 | goto out_unlock; | ||
671 | rcu_assign_pointer(fdt->fd[fd], NULL); | ||
672 | __clear_close_on_exec(fd, fdt); | ||
673 | __put_unused_fd(files, fd); | ||
674 | spin_unlock(&files->file_lock); | ||
675 | return filp_close(file, files); | ||
676 | |||
677 | out_unlock: | ||
678 | spin_unlock(&files->file_lock); | ||
679 | return -EBADF; | ||
680 | } | ||
681 | |||
682 | void do_close_on_exec(struct files_struct *files) | ||
683 | { | ||
684 | unsigned i; | ||
685 | struct fdtable *fdt; | ||
686 | |||
687 | /* exec unshares first */ | ||
688 | BUG_ON(atomic_read(&files->count) != 1); | ||
689 | spin_lock(&files->file_lock); | ||
690 | for (i = 0; ; i++) { | ||
691 | unsigned long set; | ||
692 | unsigned fd = i * BITS_PER_LONG; | ||
693 | fdt = files_fdtable(files); | ||
694 | if (fd >= fdt->max_fds) | ||
695 | break; | ||
696 | set = fdt->close_on_exec[i]; | ||
697 | if (!set) | ||
698 | continue; | ||
699 | fdt->close_on_exec[i] = 0; | ||
700 | for ( ; set ; fd++, set >>= 1) { | ||
701 | struct file *file; | ||
702 | if (!(set & 1)) | ||
703 | continue; | ||
704 | file = fdt->fd[fd]; | ||
705 | if (!file) | ||
706 | continue; | ||
707 | rcu_assign_pointer(fdt->fd[fd], NULL); | ||
708 | __put_unused_fd(files, fd); | ||
709 | spin_unlock(&files->file_lock); | ||
710 | filp_close(file, files); | ||
711 | cond_resched(); | ||
712 | spin_lock(&files->file_lock); | ||
713 | } | ||
714 | |||
715 | } | ||
716 | spin_unlock(&files->file_lock); | ||
717 | } | ||
718 | |||
719 | struct file *fget(unsigned int fd) | ||
720 | { | ||
721 | struct file *file; | ||
722 | struct files_struct *files = current->files; | ||
723 | |||
724 | rcu_read_lock(); | ||
725 | file = fcheck_files(files, fd); | ||
726 | if (file) { | ||
727 | /* File object ref couldn't be taken */ | ||
728 | if (file->f_mode & FMODE_PATH || | ||
729 | !atomic_long_inc_not_zero(&file->f_count)) | ||
730 | file = NULL; | ||
731 | } | ||
732 | rcu_read_unlock(); | ||
733 | |||
734 | return file; | ||
735 | } | ||
736 | |||
737 | EXPORT_SYMBOL(fget); | ||
738 | |||
739 | struct file *fget_raw(unsigned int fd) | ||
740 | { | ||
741 | struct file *file; | ||
742 | struct files_struct *files = current->files; | ||
743 | |||
744 | rcu_read_lock(); | ||
745 | file = fcheck_files(files, fd); | ||
746 | if (file) { | ||
747 | /* File object ref couldn't be taken */ | ||
748 | if (!atomic_long_inc_not_zero(&file->f_count)) | ||
749 | file = NULL; | ||
750 | } | ||
751 | rcu_read_unlock(); | ||
752 | |||
753 | return file; | ||
754 | } | ||
755 | |||
756 | EXPORT_SYMBOL(fget_raw); | ||
757 | |||
758 | /* | ||
759 | * Lightweight file lookup - no refcnt increment if fd table isn't shared. | ||
760 | * | ||
761 | * You can use this instead of fget if you satisfy all of the following | ||
762 | * conditions: | ||
763 | * 1) You must call fput_light before exiting the syscall and returning control | ||
764 | * to userspace (i.e. you cannot remember the returned struct file * after | ||
765 | * returning to userspace). | ||
766 | * 2) You must not call filp_close on the returned struct file * in between | ||
767 | * calls to fget_light and fput_light. | ||
768 | * 3) You must not clone the current task in between the calls to fget_light | ||
769 | * and fput_light. | ||
770 | * | ||
771 | * The fput_needed flag returned by fget_light should be passed to the | ||
772 | * corresponding fput_light. | ||
773 | */ | ||
774 | struct file *fget_light(unsigned int fd, int *fput_needed) | ||
775 | { | ||
776 | struct file *file; | ||
777 | struct files_struct *files = current->files; | ||
778 | |||
779 | *fput_needed = 0; | ||
780 | if (atomic_read(&files->count) == 1) { | ||
781 | file = fcheck_files(files, fd); | ||
782 | if (file && (file->f_mode & FMODE_PATH)) | ||
783 | file = NULL; | ||
784 | } else { | ||
785 | rcu_read_lock(); | ||
786 | file = fcheck_files(files, fd); | ||
787 | if (file) { | ||
788 | if (!(file->f_mode & FMODE_PATH) && | ||
789 | atomic_long_inc_not_zero(&file->f_count)) | ||
790 | *fput_needed = 1; | ||
791 | else | ||
792 | /* Didn't get the reference, someone's freed */ | ||
793 | file = NULL; | ||
794 | } | ||
795 | rcu_read_unlock(); | ||
796 | } | ||
797 | |||
798 | return file; | ||
799 | } | ||
800 | EXPORT_SYMBOL(fget_light); | ||
801 | |||
802 | struct file *fget_raw_light(unsigned int fd, int *fput_needed) | ||
803 | { | ||
804 | struct file *file; | ||
805 | struct files_struct *files = current->files; | ||
806 | |||
807 | *fput_needed = 0; | ||
808 | if (atomic_read(&files->count) == 1) { | ||
809 | file = fcheck_files(files, fd); | ||
810 | } else { | ||
811 | rcu_read_lock(); | ||
812 | file = fcheck_files(files, fd); | ||
813 | if (file) { | ||
814 | if (atomic_long_inc_not_zero(&file->f_count)) | ||
815 | *fput_needed = 1; | ||
816 | else | ||
817 | /* Didn't get the reference, someone's freed */ | ||
818 | file = NULL; | ||
819 | } | ||
820 | rcu_read_unlock(); | ||
821 | } | ||
822 | |||
823 | return file; | ||
824 | } | ||
825 | |||
826 | void set_close_on_exec(unsigned int fd, int flag) | ||
827 | { | ||
828 | struct files_struct *files = current->files; | ||
829 | struct fdtable *fdt; | ||
830 | spin_lock(&files->file_lock); | ||
831 | fdt = files_fdtable(files); | ||
832 | if (flag) | ||
833 | __set_close_on_exec(fd, fdt); | ||
834 | else | ||
835 | __clear_close_on_exec(fd, fdt); | ||
836 | spin_unlock(&files->file_lock); | ||
837 | } | ||
838 | |||
839 | bool get_close_on_exec(unsigned int fd) | ||
840 | { | ||
841 | struct files_struct *files = current->files; | ||
842 | struct fdtable *fdt; | ||
843 | bool res; | ||
844 | rcu_read_lock(); | ||
845 | fdt = files_fdtable(files); | ||
846 | res = close_on_exec(fd, fdt); | ||
847 | rcu_read_unlock(); | ||
848 | return res; | ||
849 | } | ||
850 | |||
851 | static int do_dup2(struct files_struct *files, | ||
852 | struct file *file, unsigned fd, unsigned flags) | ||
853 | { | ||
854 | struct file *tofree; | ||
855 | struct fdtable *fdt; | ||
856 | |||
857 | /* | ||
858 | * We need to detect attempts to do dup2() over allocated but still | ||
859 | * not finished descriptor. NB: OpenBSD avoids that at the price of | ||
860 | * extra work in their equivalent of fget() - they insert struct | ||
861 | * file immediately after grabbing descriptor, mark it larval if | ||
862 | * more work (e.g. actual opening) is needed and make sure that | ||
863 | * fget() treats larval files as absent. Potentially interesting, | ||
864 | * but while extra work in fget() is trivial, locking implications | ||
865 | * and amount of surgery on open()-related paths in VFS are not. | ||
866 | * FreeBSD fails with -EBADF in the same situation, NetBSD "solution" | ||
867 | * deadlocks in rather amusing ways, AFAICS. All of that is out of | ||
868 | * scope of POSIX or SUS, since neither considers shared descriptor | ||
869 | * tables and this condition does not arise without those. | ||
870 | */ | ||
871 | fdt = files_fdtable(files); | ||
872 | tofree = fdt->fd[fd]; | ||
873 | if (!tofree && fd_is_open(fd, fdt)) | ||
874 | goto Ebusy; | ||
875 | get_file(file); | ||
876 | rcu_assign_pointer(fdt->fd[fd], file); | ||
877 | __set_open_fd(fd, fdt); | ||
878 | if (flags & O_CLOEXEC) | ||
879 | __set_close_on_exec(fd, fdt); | ||
880 | else | ||
881 | __clear_close_on_exec(fd, fdt); | ||
882 | spin_unlock(&files->file_lock); | ||
883 | |||
884 | if (tofree) | ||
885 | filp_close(tofree, files); | ||
886 | |||
887 | return fd; | ||
888 | |||
889 | Ebusy: | ||
890 | spin_unlock(&files->file_lock); | ||
891 | return -EBUSY; | ||
892 | } | ||
893 | |||
894 | int replace_fd(unsigned fd, struct file *file, unsigned flags) | ||
895 | { | ||
896 | int err; | ||
897 | struct files_struct *files = current->files; | ||
898 | |||
899 | if (!file) | ||
900 | return __close_fd(files, fd); | ||
901 | |||
902 | if (fd >= rlimit(RLIMIT_NOFILE)) | ||
903 | return -EMFILE; | ||
904 | |||
905 | spin_lock(&files->file_lock); | ||
906 | err = expand_files(files, fd); | ||
907 | if (unlikely(err < 0)) | ||
908 | goto out_unlock; | ||
909 | return do_dup2(files, file, fd, flags); | ||
910 | |||
911 | out_unlock: | ||
912 | spin_unlock(&files->file_lock); | ||
913 | return err; | ||
914 | } | ||
915 | |||
916 | SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags) | ||
917 | { | ||
918 | int err = -EBADF; | ||
919 | struct file *file; | ||
920 | struct files_struct *files = current->files; | ||
921 | |||
922 | if ((flags & ~O_CLOEXEC) != 0) | ||
923 | return -EINVAL; | ||
924 | |||
925 | if (newfd >= rlimit(RLIMIT_NOFILE)) | ||
926 | return -EMFILE; | ||
927 | |||
928 | spin_lock(&files->file_lock); | ||
929 | err = expand_files(files, newfd); | ||
930 | file = fcheck(oldfd); | ||
931 | if (unlikely(!file)) | ||
932 | goto Ebadf; | ||
933 | if (unlikely(err < 0)) { | ||
934 | if (err == -EMFILE) | ||
935 | goto Ebadf; | ||
936 | goto out_unlock; | ||
937 | } | ||
938 | return do_dup2(files, file, newfd, flags); | ||
939 | |||
940 | Ebadf: | ||
941 | err = -EBADF; | ||
942 | out_unlock: | ||
943 | spin_unlock(&files->file_lock); | ||
944 | return err; | ||
945 | } | ||
946 | |||
947 | SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd) | ||
948 | { | ||
949 | if (unlikely(newfd == oldfd)) { /* corner case */ | ||
950 | struct files_struct *files = current->files; | ||
951 | int retval = oldfd; | ||
952 | |||
953 | rcu_read_lock(); | ||
954 | if (!fcheck_files(files, oldfd)) | ||
955 | retval = -EBADF; | ||
956 | rcu_read_unlock(); | ||
957 | return retval; | ||
958 | } | ||
959 | return sys_dup3(oldfd, newfd, 0); | ||
960 | } | ||
961 | |||
962 | SYSCALL_DEFINE1(dup, unsigned int, fildes) | ||
963 | { | ||
964 | int ret = -EBADF; | ||
965 | struct file *file = fget_raw(fildes); | ||
966 | |||
967 | if (file) { | ||
968 | ret = get_unused_fd(); | ||
969 | if (ret >= 0) | ||
970 | fd_install(ret, file); | ||
971 | else | ||
972 | fput(file); | ||
973 | } | ||
974 | return ret; | ||
975 | } | ||
976 | |||
977 | int f_dupfd(unsigned int from, struct file *file, unsigned flags) | ||
978 | { | ||
979 | int err; | ||
980 | if (from >= rlimit(RLIMIT_NOFILE)) | ||
981 | return -EINVAL; | ||
982 | err = alloc_fd(from, flags); | ||
983 | if (err >= 0) { | ||
984 | get_file(file); | ||
985 | fd_install(err, file); | ||
986 | } | ||
987 | return err; | ||
988 | } | ||
989 | |||
990 | int iterate_fd(struct files_struct *files, unsigned n, | ||
991 | int (*f)(const void *, struct file *, unsigned), | ||
992 | const void *p) | ||
993 | { | ||
994 | struct fdtable *fdt; | ||
995 | struct file *file; | ||
996 | int res = 0; | ||
997 | if (!files) | ||
998 | return 0; | ||
999 | spin_lock(&files->file_lock); | ||
1000 | fdt = files_fdtable(files); | ||
1001 | while (!res && n < fdt->max_fds) { | ||
1002 | file = rcu_dereference_check_fdtable(files, fdt->fd[n++]); | ||
1003 | if (file) | ||
1004 | res = f(p, file, n); | ||
1005 | } | ||
1006 | spin_unlock(&files->file_lock); | ||
1007 | return res; | ||
483 | } | 1008 | } |
484 | EXPORT_SYMBOL(get_unused_fd); | 1009 | EXPORT_SYMBOL(iterate_fd); |