diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-01 13:34:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-01 13:34:35 -0400 |
commit | 1193755ac6328ad240ba987e6ec41d5e8baf0680 (patch) | |
tree | 40bf847d7e3ebaa57b107151d14e6cd1d280cc6d /fs/open.c | |
parent | 4edebed86690eb8db9af3ab85baf4a34e73266cc (diff) | |
parent | 0ef97dcfce4179a2eba046b855ee2f91d6f1b414 (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.c | 76 |
1 files changed, 57 insertions, 19 deletions
@@ -654,10 +654,23 @@ static inline int __get_file_write_access(struct inode *inode, | |||
654 | return error; | 654 | return error; |
655 | } | 655 | } |
656 | 656 | ||
657 | static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | 657 | int 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 | |||
670 | static 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 | ||
728 | cleanup_all: | 731 | cleanup_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; |
746 | cleanup_file: | 749 | cleanup_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 | ||
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 | } | ||
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 | } |