aboutsummaryrefslogtreecommitdiffstats
path: root/fs/open.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-06-01 13:34:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-06-01 13:34:35 -0400
commit1193755ac6328ad240ba987e6ec41d5e8baf0680 (patch)
tree40bf847d7e3ebaa57b107151d14e6cd1d280cc6d /fs/open.c
parent4edebed86690eb8db9af3ab85baf4a34e73266cc (diff)
parent0ef97dcfce4179a2eba046b855ee2f91d6f1b414 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs changes from Al Viro. "A lot of misc stuff. The obvious groups: * Miklos' atomic_open series; kills the damn abuse of ->d_revalidate() by NFS, which was the major stumbling block for all work in that area. * ripping security_file_mmap() and dealing with deadlocks in the area; sanitizing the neighborhood of vm_mmap()/vm_munmap() in general. * ->encode_fh() switched to saner API; insane fake dentry in mm/cleancache.c gone. * assorted annotations in fs (endianness, __user) * parts of Artem's ->s_dirty work (jff2 and reiserfs parts) * ->update_time() work from Josef. * other bits and pieces all over the place. Normally it would've been in two or three pull requests, but signal.git stuff had eaten a lot of time during this cycle ;-/" Fix up trivial conflicts in Documentation/filesystems/vfs.txt (the 'truncate_range' inode method was removed by the VM changes, the VFS update adds an 'update_time()' method), and in fs/btrfs/ulist.[ch] (due to sparse fix added twice, with other changes nearby). * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (95 commits) nfs: don't open in ->d_revalidate vfs: retry last component if opening stale dentry vfs: nameidata_to_filp(): don't throw away file on error vfs: nameidata_to_filp(): inline __dentry_open() vfs: do_dentry_open(): don't put filp vfs: split __dentry_open() vfs: do_last() common post lookup vfs: do_last(): add audit_inode before open vfs: do_last(): only return EISDIR for O_CREAT vfs: do_last(): check LOOKUP_DIRECTORY vfs: do_last(): make ENOENT exit RCU safe vfs: make follow_link check RCU safe vfs: do_last(): use inode variable vfs: do_last(): inline walk_component() vfs: do_last(): make exit RCU safe vfs: split do_lookup() Btrfs: move over to use ->update_time fs: introduce inode operation ->update_time reiserfs: get rid of resierfs_sync_super reiserfs: mark the superblock as dirty a bit later ...
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}