diff options
Diffstat (limited to 'fs/file.c')
-rw-r--r-- | fs/file.c | 106 |
1 files changed, 106 insertions, 0 deletions
@@ -625,3 +625,109 @@ void fd_install(unsigned int fd, struct file *file) | |||
625 | } | 625 | } |
626 | 626 | ||
627 | EXPORT_SYMBOL(fd_install); | 627 | EXPORT_SYMBOL(fd_install); |
628 | |||
629 | struct file *fget(unsigned int fd) | ||
630 | { | ||
631 | struct file *file; | ||
632 | struct files_struct *files = current->files; | ||
633 | |||
634 | rcu_read_lock(); | ||
635 | file = fcheck_files(files, fd); | ||
636 | if (file) { | ||
637 | /* File object ref couldn't be taken */ | ||
638 | if (file->f_mode & FMODE_PATH || | ||
639 | !atomic_long_inc_not_zero(&file->f_count)) | ||
640 | file = NULL; | ||
641 | } | ||
642 | rcu_read_unlock(); | ||
643 | |||
644 | return file; | ||
645 | } | ||
646 | |||
647 | EXPORT_SYMBOL(fget); | ||
648 | |||
649 | struct file *fget_raw(unsigned int fd) | ||
650 | { | ||
651 | struct file *file; | ||
652 | struct files_struct *files = current->files; | ||
653 | |||
654 | rcu_read_lock(); | ||
655 | file = fcheck_files(files, fd); | ||
656 | if (file) { | ||
657 | /* File object ref couldn't be taken */ | ||
658 | if (!atomic_long_inc_not_zero(&file->f_count)) | ||
659 | file = NULL; | ||
660 | } | ||
661 | rcu_read_unlock(); | ||
662 | |||
663 | return file; | ||
664 | } | ||
665 | |||
666 | EXPORT_SYMBOL(fget_raw); | ||
667 | |||
668 | /* | ||
669 | * Lightweight file lookup - no refcnt increment if fd table isn't shared. | ||
670 | * | ||
671 | * You can use this instead of fget if you satisfy all of the following | ||
672 | * conditions: | ||
673 | * 1) You must call fput_light before exiting the syscall and returning control | ||
674 | * to userspace (i.e. you cannot remember the returned struct file * after | ||
675 | * returning to userspace). | ||
676 | * 2) You must not call filp_close on the returned struct file * in between | ||
677 | * calls to fget_light and fput_light. | ||
678 | * 3) You must not clone the current task in between the calls to fget_light | ||
679 | * and fput_light. | ||
680 | * | ||
681 | * The fput_needed flag returned by fget_light should be passed to the | ||
682 | * corresponding fput_light. | ||
683 | */ | ||
684 | struct file *fget_light(unsigned int fd, int *fput_needed) | ||
685 | { | ||
686 | struct file *file; | ||
687 | struct files_struct *files = current->files; | ||
688 | |||
689 | *fput_needed = 0; | ||
690 | if (atomic_read(&files->count) == 1) { | ||
691 | file = fcheck_files(files, fd); | ||
692 | if (file && (file->f_mode & FMODE_PATH)) | ||
693 | file = NULL; | ||
694 | } else { | ||
695 | rcu_read_lock(); | ||
696 | file = fcheck_files(files, fd); | ||
697 | if (file) { | ||
698 | if (!(file->f_mode & FMODE_PATH) && | ||
699 | atomic_long_inc_not_zero(&file->f_count)) | ||
700 | *fput_needed = 1; | ||
701 | else | ||
702 | /* Didn't get the reference, someone's freed */ | ||
703 | file = NULL; | ||
704 | } | ||
705 | rcu_read_unlock(); | ||
706 | } | ||
707 | |||
708 | return file; | ||
709 | } | ||
710 | |||
711 | struct file *fget_raw_light(unsigned int fd, int *fput_needed) | ||
712 | { | ||
713 | struct file *file; | ||
714 | struct files_struct *files = current->files; | ||
715 | |||
716 | *fput_needed = 0; | ||
717 | if (atomic_read(&files->count) == 1) { | ||
718 | file = fcheck_files(files, fd); | ||
719 | } else { | ||
720 | rcu_read_lock(); | ||
721 | file = fcheck_files(files, fd); | ||
722 | if (file) { | ||
723 | if (atomic_long_inc_not_zero(&file->f_count)) | ||
724 | *fput_needed = 1; | ||
725 | else | ||
726 | /* Didn't get the reference, someone's freed */ | ||
727 | file = NULL; | ||
728 | } | ||
729 | rcu_read_unlock(); | ||
730 | } | ||
731 | |||
732 | return file; | ||
733 | } | ||