aboutsummaryrefslogtreecommitdiffstats
path: root/fs/file.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-08-15 21:12:10 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-09-26 21:08:56 -0400
commit0ee8cdfe6af052deb56dccd54838a1eb32fb4ca2 (patch)
tree3671169a822f5ed43482ab4db68d518906385e3d /fs/file.c
parentf869e8a7f753e3fd43d6483e796774776f645edb (diff)
take fget() and friends to fs/file.c
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/file.c')
-rw-r--r--fs/file.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/fs/file.c b/fs/file.c
index 0d1bf0515111..6eef55ce30c9 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -625,3 +625,109 @@ void fd_install(unsigned int fd, struct file *file)
625} 625}
626 626
627EXPORT_SYMBOL(fd_install); 627EXPORT_SYMBOL(fd_install);
628
629struct 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
647EXPORT_SYMBOL(fget);
648
649struct 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
666EXPORT_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 */
684struct 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
711struct 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}