diff options
Diffstat (limited to 'fs/open.c')
-rw-r--r-- | fs/open.c | 211 |
1 files changed, 65 insertions, 146 deletions
@@ -537,25 +537,6 @@ static int chown_common(struct path *path, uid_t user, gid_t group) | |||
537 | return error; | 537 | return error; |
538 | } | 538 | } |
539 | 539 | ||
540 | SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group) | ||
541 | { | ||
542 | struct path path; | ||
543 | int error; | ||
544 | |||
545 | error = user_path(filename, &path); | ||
546 | if (error) | ||
547 | goto out; | ||
548 | error = mnt_want_write(path.mnt); | ||
549 | if (error) | ||
550 | goto out_release; | ||
551 | error = chown_common(&path, user, group); | ||
552 | mnt_drop_write(path.mnt); | ||
553 | out_release: | ||
554 | path_put(&path); | ||
555 | out: | ||
556 | return error; | ||
557 | } | ||
558 | |||
559 | SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user, | 540 | SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user, |
560 | gid_t, group, int, flag) | 541 | gid_t, group, int, flag) |
561 | { | 542 | { |
@@ -583,23 +564,15 @@ out: | |||
583 | return error; | 564 | return error; |
584 | } | 565 | } |
585 | 566 | ||
586 | SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group) | 567 | SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group) |
587 | { | 568 | { |
588 | struct path path; | 569 | return sys_fchownat(AT_FDCWD, filename, user, group, 0); |
589 | int error; | 570 | } |
590 | 571 | ||
591 | error = user_lpath(filename, &path); | 572 | SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group) |
592 | if (error) | 573 | { |
593 | goto out; | 574 | return sys_fchownat(AT_FDCWD, filename, user, group, |
594 | error = mnt_want_write(path.mnt); | 575 | AT_SYMLINK_NOFOLLOW); |
595 | if (error) | ||
596 | goto out_release; | ||
597 | error = chown_common(&path, user, group); | ||
598 | mnt_drop_write(path.mnt); | ||
599 | out_release: | ||
600 | path_put(&path); | ||
601 | out: | ||
602 | return error; | ||
603 | } | 576 | } |
604 | 577 | ||
605 | SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) | 578 | SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) |
@@ -667,10 +640,9 @@ int open_check_o_direct(struct file *f) | |||
667 | return 0; | 640 | return 0; |
668 | } | 641 | } |
669 | 642 | ||
670 | static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt, | 643 | static int do_dentry_open(struct file *f, |
671 | struct file *f, | 644 | int (*open)(struct inode *, struct file *), |
672 | int (*open)(struct inode *, struct file *), | 645 | const struct cred *cred) |
673 | const struct cred *cred) | ||
674 | { | 646 | { |
675 | static const struct file_operations empty_fops = {}; | 647 | static const struct file_operations empty_fops = {}; |
676 | struct inode *inode; | 648 | struct inode *inode; |
@@ -682,9 +654,9 @@ static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt, | |||
682 | if (unlikely(f->f_flags & O_PATH)) | 654 | if (unlikely(f->f_flags & O_PATH)) |
683 | f->f_mode = FMODE_PATH; | 655 | f->f_mode = FMODE_PATH; |
684 | 656 | ||
685 | inode = dentry->d_inode; | 657 | inode = f->f_path.dentry->d_inode; |
686 | if (f->f_mode & FMODE_WRITE) { | 658 | if (f->f_mode & FMODE_WRITE) { |
687 | error = __get_file_write_access(inode, mnt); | 659 | error = __get_file_write_access(inode, f->f_path.mnt); |
688 | if (error) | 660 | if (error) |
689 | goto cleanup_file; | 661 | goto cleanup_file; |
690 | if (!special_file(inode->i_mode)) | 662 | if (!special_file(inode->i_mode)) |
@@ -692,14 +664,12 @@ static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt, | |||
692 | } | 664 | } |
693 | 665 | ||
694 | f->f_mapping = inode->i_mapping; | 666 | f->f_mapping = inode->i_mapping; |
695 | f->f_path.dentry = dentry; | ||
696 | f->f_path.mnt = mnt; | ||
697 | f->f_pos = 0; | 667 | f->f_pos = 0; |
698 | file_sb_list_add(f, inode->i_sb); | 668 | file_sb_list_add(f, inode->i_sb); |
699 | 669 | ||
700 | if (unlikely(f->f_mode & FMODE_PATH)) { | 670 | if (unlikely(f->f_mode & FMODE_PATH)) { |
701 | f->f_op = &empty_fops; | 671 | f->f_op = &empty_fops; |
702 | return f; | 672 | return 0; |
703 | } | 673 | } |
704 | 674 | ||
705 | f->f_op = fops_get(inode->i_fop); | 675 | f->f_op = fops_get(inode->i_fop); |
@@ -726,10 +696,11 @@ static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt, | |||
726 | 696 | ||
727 | file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); | 697 | file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); |
728 | 698 | ||
729 | return f; | 699 | return 0; |
730 | 700 | ||
731 | cleanup_all: | 701 | cleanup_all: |
732 | fops_put(f->f_op); | 702 | fops_put(f->f_op); |
703 | file_sb_list_del(f); | ||
733 | if (f->f_mode & FMODE_WRITE) { | 704 | if (f->f_mode & FMODE_WRITE) { |
734 | put_write_access(inode); | 705 | put_write_access(inode); |
735 | if (!special_file(inode->i_mode)) { | 706 | if (!special_file(inode->i_mode)) { |
@@ -740,124 +711,62 @@ cleanup_all: | |||
740 | * here, so just reset the state. | 711 | * here, so just reset the state. |
741 | */ | 712 | */ |
742 | file_reset_write(f); | 713 | file_reset_write(f); |
743 | mnt_drop_write(mnt); | 714 | mnt_drop_write(f->f_path.mnt); |
744 | } | 715 | } |
745 | } | 716 | } |
746 | file_sb_list_del(f); | ||
747 | f->f_path.dentry = NULL; | ||
748 | f->f_path.mnt = NULL; | ||
749 | cleanup_file: | 717 | cleanup_file: |
750 | dput(dentry); | 718 | path_put(&f->f_path); |
751 | mntput(mnt); | 719 | f->f_path.mnt = NULL; |
752 | return ERR_PTR(error); | 720 | f->f_path.dentry = NULL; |
753 | } | 721 | return error; |
754 | |||
755 | static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | ||
756 | struct file *f, | ||
757 | int (*open)(struct inode *, struct file *), | ||
758 | const struct cred *cred) | ||
759 | { | ||
760 | struct file *res = do_dentry_open(dentry, mnt, f, open, cred); | ||
761 | if (!IS_ERR(res)) { | ||
762 | int error = open_check_o_direct(f); | ||
763 | if (error) { | ||
764 | fput(res); | ||
765 | res = ERR_PTR(error); | ||
766 | } | ||
767 | } else { | ||
768 | put_filp(f); | ||
769 | } | ||
770 | return res; | ||
771 | } | 722 | } |
772 | 723 | ||
773 | /** | 724 | /** |
774 | * lookup_instantiate_filp - instantiates the open intent filp | 725 | * finish_open - finish opening a file |
775 | * @nd: pointer to nameidata | 726 | * @od: opaque open data |
776 | * @dentry: pointer to dentry | 727 | * @dentry: pointer to dentry |
777 | * @open: open callback | 728 | * @open: open callback |
778 | * | 729 | * |
779 | * Helper for filesystems that want to use lookup open intents and pass back | 730 | * This can be used to finish opening a file passed to i_op->atomic_open(). |
780 | * a fully instantiated struct file to the caller. | 731 | * |
781 | * This function is meant to be called from within a filesystem's | ||
782 | * lookup method. | ||
783 | * Beware of calling it for non-regular files! Those ->open methods might block | ||
784 | * (e.g. in fifo_open), leaving you with parent locked (and in case of fifo, | ||
785 | * leading to a deadlock, as nobody can open that fifo anymore, because | ||
786 | * another process to open fifo will block on locked parent when doing lookup). | ||
787 | * Note that in case of error, nd->intent.open.file is destroyed, but the | ||
788 | * path information remains valid. | ||
789 | * If the open callback is set to NULL, then the standard f_op->open() | 732 | * If the open callback is set to NULL, then the standard f_op->open() |
790 | * filesystem callback is substituted. | 733 | * filesystem callback is substituted. |
791 | */ | 734 | */ |
792 | struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, | 735 | int finish_open(struct file *file, struct dentry *dentry, |
793 | int (*open)(struct inode *, struct file *)) | 736 | int (*open)(struct inode *, struct file *), |
737 | int *opened) | ||
794 | { | 738 | { |
795 | const struct cred *cred = current_cred(); | 739 | int error; |
740 | BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */ | ||
796 | 741 | ||
797 | if (IS_ERR(nd->intent.open.file)) | 742 | mntget(file->f_path.mnt); |
798 | goto out; | 743 | file->f_path.dentry = dget(dentry); |
799 | if (IS_ERR(dentry)) | 744 | |
800 | goto out_err; | 745 | error = do_dentry_open(file, open, current_cred()); |
801 | nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt), | 746 | if (!error) |
802 | nd->intent.open.file, | 747 | *opened |= FILE_OPENED; |
803 | open, cred); | 748 | |
804 | out: | 749 | return error; |
805 | return nd->intent.open.file; | ||
806 | out_err: | ||
807 | release_open_intent(nd); | ||
808 | nd->intent.open.file = ERR_CAST(dentry); | ||
809 | goto out; | ||
810 | } | 750 | } |
811 | EXPORT_SYMBOL_GPL(lookup_instantiate_filp); | 751 | EXPORT_SYMBOL(finish_open); |
812 | 752 | ||
813 | /** | 753 | /** |
814 | * nameidata_to_filp - convert a nameidata to an open filp. | 754 | * finish_no_open - finish ->atomic_open() without opening the file |
815 | * @nd: pointer to nameidata | 755 | * |
816 | * @flags: open flags | 756 | * @od: opaque open data |
757 | * @dentry: dentry or NULL (as returned from ->lookup()) | ||
817 | * | 758 | * |
818 | * Note that this function destroys the original nameidata | 759 | * This can be used to set the result of a successful lookup in ->atomic_open(). |
760 | * The filesystem's atomic_open() method shall return NULL after calling this. | ||
819 | */ | 761 | */ |
820 | struct file *nameidata_to_filp(struct nameidata *nd) | 762 | int finish_no_open(struct file *file, struct dentry *dentry) |
821 | { | 763 | { |
822 | const struct cred *cred = current_cred(); | 764 | file->f_path.dentry = dentry; |
823 | struct file *filp; | 765 | return 1; |
824 | |||
825 | /* Pick up the filp from the open intent */ | ||
826 | filp = nd->intent.open.file; | ||
827 | |||
828 | /* Has the filesystem initialised the file for us? */ | ||
829 | if (filp->f_path.dentry != NULL) { | ||
830 | nd->intent.open.file = NULL; | ||
831 | } else { | ||
832 | struct file *res; | ||
833 | |||
834 | path_get(&nd->path); | ||
835 | res = do_dentry_open(nd->path.dentry, nd->path.mnt, | ||
836 | filp, NULL, cred); | ||
837 | if (!IS_ERR(res)) { | ||
838 | int error; | ||
839 | |||
840 | nd->intent.open.file = NULL; | ||
841 | BUG_ON(res != filp); | ||
842 | |||
843 | error = open_check_o_direct(filp); | ||
844 | if (error) { | ||
845 | fput(filp); | ||
846 | filp = ERR_PTR(error); | ||
847 | } | ||
848 | } else { | ||
849 | /* Allow nd->intent.open.file to be recycled */ | ||
850 | filp = res; | ||
851 | } | ||
852 | } | ||
853 | return filp; | ||
854 | } | 766 | } |
767 | EXPORT_SYMBOL(finish_no_open); | ||
855 | 768 | ||
856 | /* | 769 | struct file *dentry_open(const struct path *path, int flags, |
857 | * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an | ||
858 | * error. | ||
859 | */ | ||
860 | struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, | ||
861 | const struct cred *cred) | 770 | const struct cred *cred) |
862 | { | 771 | { |
863 | int error; | 772 | int error; |
@@ -866,18 +775,28 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, | |||
866 | validate_creds(cred); | 775 | validate_creds(cred); |
867 | 776 | ||
868 | /* We must always pass in a valid mount pointer. */ | 777 | /* We must always pass in a valid mount pointer. */ |
869 | BUG_ON(!mnt); | 778 | BUG_ON(!path->mnt); |
870 | 779 | ||
871 | error = -ENFILE; | 780 | error = -ENFILE; |
872 | f = get_empty_filp(); | 781 | f = get_empty_filp(); |
873 | if (f == NULL) { | 782 | if (f == NULL) |
874 | dput(dentry); | ||
875 | mntput(mnt); | ||
876 | return ERR_PTR(error); | 783 | return ERR_PTR(error); |
877 | } | ||
878 | 784 | ||
879 | f->f_flags = flags; | 785 | f->f_flags = flags; |
880 | return __dentry_open(dentry, mnt, f, NULL, cred); | 786 | f->f_path = *path; |
787 | path_get(&f->f_path); | ||
788 | error = do_dentry_open(f, NULL, cred); | ||
789 | if (!error) { | ||
790 | error = open_check_o_direct(f); | ||
791 | if (error) { | ||
792 | fput(f); | ||
793 | f = ERR_PTR(error); | ||
794 | } | ||
795 | } else { | ||
796 | put_filp(f); | ||
797 | f = ERR_PTR(error); | ||
798 | } | ||
799 | return f; | ||
881 | } | 800 | } |
882 | EXPORT_SYMBOL(dentry_open); | 801 | EXPORT_SYMBOL(dentry_open); |
883 | 802 | ||