aboutsummaryrefslogtreecommitdiffstats
path: root/fs/open.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/open.c')
-rw-r--r--fs/open.c76
1 files changed, 57 insertions, 19 deletions
diff --git a/fs/open.c b/fs/open.c
index d54301219d04..d6c79a0dffc7 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -654,10 +654,23 @@ static inline int __get_file_write_access(struct inode *inode,
654 return error; 654 return error;
655} 655}
656 656
657static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, 657int open_check_o_direct(struct file *f)
658 struct file *f, 658{
659 int (*open)(struct inode *, struct file *), 659 /* NB: we're sure to have correct a_ops only after f_op->open */
660 const struct cred *cred) 660 if (f->f_flags & O_DIRECT) {
661 if (!f->f_mapping->a_ops ||
662 ((!f->f_mapping->a_ops->direct_IO) &&
663 (!f->f_mapping->a_ops->get_xip_mem))) {
664 return -EINVAL;
665 }
666 }
667 return 0;
668}
669
670static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
671 struct file *f,
672 int (*open)(struct inode *, struct file *),
673 const struct cred *cred)
661{ 674{
662 static const struct file_operations empty_fops = {}; 675 static const struct file_operations empty_fops = {};
663 struct inode *inode; 676 struct inode *inode;
@@ -713,16 +726,6 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
713 726
714 file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); 727 file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
715 728
716 /* NB: we're sure to have correct a_ops only after f_op->open */
717 if (f->f_flags & O_DIRECT) {
718 if (!f->f_mapping->a_ops ||
719 ((!f->f_mapping->a_ops->direct_IO) &&
720 (!f->f_mapping->a_ops->get_xip_mem))) {
721 fput(f);
722 f = ERR_PTR(-EINVAL);
723 }
724 }
725
726 return f; 729 return f;
727 730
728cleanup_all: 731cleanup_all:
@@ -744,12 +747,29 @@ cleanup_all:
744 f->f_path.dentry = NULL; 747 f->f_path.dentry = NULL;
745 f->f_path.mnt = NULL; 748 f->f_path.mnt = NULL;
746cleanup_file: 749cleanup_file:
747 put_filp(f);
748 dput(dentry); 750 dput(dentry);
749 mntput(mnt); 751 mntput(mnt);
750 return ERR_PTR(error); 752 return ERR_PTR(error);
751} 753}
752 754
755static 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}
772
753/** 773/**
754 * lookup_instantiate_filp - instantiates the open intent filp 774 * lookup_instantiate_filp - instantiates the open intent filp
755 * @nd: pointer to nameidata 775 * @nd: pointer to nameidata
@@ -804,13 +824,31 @@ struct file *nameidata_to_filp(struct nameidata *nd)
804 824
805 /* Pick up the filp from the open intent */ 825 /* Pick up the filp from the open intent */
806 filp = nd->intent.open.file; 826 filp = nd->intent.open.file;
807 nd->intent.open.file = NULL;
808 827
809 /* Has the filesystem initialised the file for us? */ 828 /* Has the filesystem initialised the file for us? */
810 if (filp->f_path.dentry == NULL) { 829 if (filp->f_path.dentry != NULL) {
830 nd->intent.open.file = NULL;
831 } else {
832 struct file *res;
833
811 path_get(&nd->path); 834 path_get(&nd->path);
812 filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp, 835 res = do_dentry_open(nd->path.dentry, nd->path.mnt,
813 NULL, cred); 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 }
814 } 852 }
815 return filp; 853 return filp;
816} 854}