diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-23 15:27:27 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-23 15:27:27 -0400 |
commit | a66d2c8f7ec1284206ca7c14569e2a607583f1e3 (patch) | |
tree | 08cf68bcef3559b370843cab8191e5cc0f740bde /fs/9p/vfs_inode.c | |
parent | a6be1fcbc57f95bb47ef3c8e4ee3d83731b8f21e (diff) | |
parent | 8cae6f7158ec1fa44c8a04a43db7d8020ec60437 (diff) |
Merge branch 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull the big VFS changes from Al Viro:
"This one is *big* and changes quite a few things around VFS. What's in there:
- the first of two really major architecture changes - death to open
intents.
The former is finally there; it was very long in making, but with
Miklos getting through really hard and messy final push in
fs/namei.c, we finally have it. Unlike his variant, this one
doesn't introduce struct opendata; what we have instead is
->atomic_open() taking preallocated struct file * and passing
everything via its fields.
Instead of returning struct file *, it returns -E... on error, 0
on success and 1 in "deal with it yourself" case (e.g. symlink
found on server, etc.).
See comments before fs/namei.c:atomic_open(). That made a lot of
goodies finally possible and quite a few are in that pile:
->lookup(), ->d_revalidate() and ->create() do not get struct
nameidata * anymore; ->lookup() and ->d_revalidate() get lookup
flags instead, ->create() gets "do we want it exclusive" flag.
With the introduction of new helper (kern_path_locked()) we are rid
of all struct nameidata instances outside of fs/namei.c; it's still
visible in namei.h, but not for long. Come the next cycle,
declaration will move either to fs/internal.h or to fs/namei.c
itself. [me, miklos, hch]
- The second major change: behaviour of final fput(). Now we have
__fput() done without any locks held by caller *and* not from deep
in call stack.
That obviously lifts a lot of constraints on the locking in there.
Moreover, it's legal now to call fput() from atomic contexts (which
has immediately simplified life for aio.c). We also don't need
anti-recursion logics in __scm_destroy() anymore.
There is a price, though - the damn thing has become partially
asynchronous. For fput() from normal process we are guaranteed
that pending __fput() will be done before the caller returns to
userland, exits or gets stopped for ptrace.
For kernel threads and atomic contexts it's done via
schedule_work(), so theoretically we might need a way to make sure
it's finished; so far only one such place had been found, but there
might be more.
There's flush_delayed_fput() (do all pending __fput()) and there's
__fput_sync() (fput() analog doing __fput() immediately). I hope
we won't need them often; see warnings in fs/file_table.c for
details. [me, based on task_work series from Oleg merged last
cycle]
- sync series from Jan
- large part of "death to sync_supers()" work from Artem; the only
bits missing here are exofs and ext4 ones. As far as I understand,
those are going via the exofs and ext4 trees resp.; once they are
in, we can put ->write_super() to the rest, along with the thread
calling it.
- preparatory bits from unionmount series (from dhowells).
- assorted cleanups and fixes all over the place, as usual.
This is not the last pile for this cycle; there's at least jlayton's
ESTALE work and fsfreeze series (the latter - in dire need of fixes,
so I'm not sure it'll make the cut this cycle). I'll probably throw
symlink/hardlink restrictions stuff from Kees into the next pile, too.
Plus there's a lot of misc patches I hadn't thrown into that one -
it's large enough as it is..."
* 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (127 commits)
ext4: switch EXT4_IOC_RESIZE_FS to mnt_want_write_file()
btrfs: switch btrfs_ioctl_balance() to mnt_want_write_file()
switch dentry_open() to struct path, make it grab references itself
spufs: shift dget/mntget towards dentry_open()
zoran: don't bother with struct file * in zoran_map
ecryptfs: don't reinvent the wheels, please - use struct completion
don't expose I_NEW inodes via dentry->d_inode
tidy up namei.c a bit
unobfuscate follow_up() a bit
ext3: pass custom EOF to generic_file_llseek_size()
ext4: use core vfs llseek code for dir seeks
vfs: allow custom EOF in generic_file_llseek code
vfs: Avoid unnecessary WB_SYNC_NONE writeback during sys_sync and reorder sync passes
vfs: Remove unnecessary flushing of block devices
vfs: Make sys_sync writeout also block device inodes
vfs: Create function for iterating over block devices
vfs: Reorder operations during sys_sync
quota: Move quota syncing to ->sync_fs method
quota: Split dquot_quota_sync() to writeback and cache flushing part
vfs: Move noop_backing_dev_info check from sync into writeback
...
Diffstat (limited to 'fs/9p/vfs_inode.c')
-rw-r--r-- | fs/9p/vfs_inode.c | 170 |
1 files changed, 99 insertions, 71 deletions
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 57ccb7537dae..cbf9dbb1b2a2 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -712,88 +712,34 @@ error: | |||
712 | } | 712 | } |
713 | 713 | ||
714 | /** | 714 | /** |
715 | * v9fs_vfs_create - VFS hook to create files | 715 | * v9fs_vfs_create - VFS hook to create a regular file |
716 | * | ||
717 | * open(.., O_CREAT) is handled in v9fs_vfs_atomic_open(). This is only called | ||
718 | * for mknod(2). | ||
719 | * | ||
716 | * @dir: directory inode that is being created | 720 | * @dir: directory inode that is being created |
717 | * @dentry: dentry that is being deleted | 721 | * @dentry: dentry that is being deleted |
718 | * @mode: create permissions | 722 | * @mode: create permissions |
719 | * @nd: path information | ||
720 | * | 723 | * |
721 | */ | 724 | */ |
722 | 725 | ||
723 | static int | 726 | static int |
724 | v9fs_vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, | 727 | v9fs_vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, |
725 | struct nameidata *nd) | 728 | bool excl) |
726 | { | 729 | { |
727 | int err; | 730 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); |
728 | u32 perm; | 731 | u32 perm = unixmode2p9mode(v9ses, mode); |
729 | int flags; | 732 | struct p9_fid *fid; |
730 | struct file *filp; | ||
731 | struct v9fs_inode *v9inode; | ||
732 | struct v9fs_session_info *v9ses; | ||
733 | struct p9_fid *fid, *inode_fid; | ||
734 | |||
735 | err = 0; | ||
736 | fid = NULL; | ||
737 | v9ses = v9fs_inode2v9ses(dir); | ||
738 | perm = unixmode2p9mode(v9ses, mode); | ||
739 | if (nd) | ||
740 | flags = nd->intent.open.flags; | ||
741 | else | ||
742 | flags = O_RDWR; | ||
743 | 733 | ||
744 | fid = v9fs_create(v9ses, dir, dentry, NULL, perm, | 734 | /* P9_OEXCL? */ |
745 | v9fs_uflags2omode(flags, | 735 | fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_ORDWR); |
746 | v9fs_proto_dotu(v9ses))); | 736 | if (IS_ERR(fid)) |
747 | if (IS_ERR(fid)) { | 737 | return PTR_ERR(fid); |
748 | err = PTR_ERR(fid); | ||
749 | fid = NULL; | ||
750 | goto error; | ||
751 | } | ||
752 | 738 | ||
753 | v9fs_invalidate_inode_attr(dir); | 739 | v9fs_invalidate_inode_attr(dir); |
754 | /* if we are opening a file, assign the open fid to the file */ | 740 | p9_client_clunk(fid); |
755 | if (nd) { | ||
756 | v9inode = V9FS_I(dentry->d_inode); | ||
757 | mutex_lock(&v9inode->v_mutex); | ||
758 | if (v9ses->cache && !v9inode->writeback_fid && | ||
759 | ((flags & O_ACCMODE) != O_RDONLY)) { | ||
760 | /* | ||
761 | * clone a fid and add it to writeback_fid | ||
762 | * we do it during open time instead of | ||
763 | * page dirty time via write_begin/page_mkwrite | ||
764 | * because we want write after unlink usecase | ||
765 | * to work. | ||
766 | */ | ||
767 | inode_fid = v9fs_writeback_fid(dentry); | ||
768 | if (IS_ERR(inode_fid)) { | ||
769 | err = PTR_ERR(inode_fid); | ||
770 | mutex_unlock(&v9inode->v_mutex); | ||
771 | goto error; | ||
772 | } | ||
773 | v9inode->writeback_fid = (void *) inode_fid; | ||
774 | } | ||
775 | mutex_unlock(&v9inode->v_mutex); | ||
776 | filp = lookup_instantiate_filp(nd, dentry, generic_file_open); | ||
777 | if (IS_ERR(filp)) { | ||
778 | err = PTR_ERR(filp); | ||
779 | goto error; | ||
780 | } | ||
781 | |||
782 | filp->private_data = fid; | ||
783 | #ifdef CONFIG_9P_FSCACHE | ||
784 | if (v9ses->cache) | ||
785 | v9fs_cache_inode_set_cookie(dentry->d_inode, filp); | ||
786 | #endif | ||
787 | } else | ||
788 | p9_client_clunk(fid); | ||
789 | 741 | ||
790 | return 0; | 742 | return 0; |
791 | |||
792 | error: | ||
793 | if (fid) | ||
794 | p9_client_clunk(fid); | ||
795 | |||
796 | return err; | ||
797 | } | 743 | } |
798 | 744 | ||
799 | /** | 745 | /** |
@@ -839,7 +785,7 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode | |||
839 | */ | 785 | */ |
840 | 786 | ||
841 | struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | 787 | struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, |
842 | struct nameidata *nameidata) | 788 | unsigned int flags) |
843 | { | 789 | { |
844 | struct dentry *res; | 790 | struct dentry *res; |
845 | struct super_block *sb; | 791 | struct super_block *sb; |
@@ -849,8 +795,8 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
849 | char *name; | 795 | char *name; |
850 | int result = 0; | 796 | int result = 0; |
851 | 797 | ||
852 | p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", | 798 | p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p flags: %x\n", |
853 | dir, dentry->d_name.name, dentry, nameidata); | 799 | dir, dentry->d_name.name, dentry, flags); |
854 | 800 | ||
855 | if (dentry->d_name.len > NAME_MAX) | 801 | if (dentry->d_name.len > NAME_MAX) |
856 | return ERR_PTR(-ENAMETOOLONG); | 802 | return ERR_PTR(-ENAMETOOLONG); |
@@ -910,6 +856,86 @@ error: | |||
910 | return ERR_PTR(result); | 856 | return ERR_PTR(result); |
911 | } | 857 | } |
912 | 858 | ||
859 | static int | ||
860 | v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, | ||
861 | struct file *file, unsigned flags, umode_t mode, | ||
862 | int *opened) | ||
863 | { | ||
864 | int err; | ||
865 | u32 perm; | ||
866 | struct v9fs_inode *v9inode; | ||
867 | struct v9fs_session_info *v9ses; | ||
868 | struct p9_fid *fid, *inode_fid; | ||
869 | struct dentry *res = NULL; | ||
870 | |||
871 | if (d_unhashed(dentry)) { | ||
872 | res = v9fs_vfs_lookup(dir, dentry, 0); | ||
873 | if (IS_ERR(res)) | ||
874 | return PTR_ERR(res); | ||
875 | |||
876 | if (res) | ||
877 | dentry = res; | ||
878 | } | ||
879 | |||
880 | /* Only creates */ | ||
881 | if (!(flags & O_CREAT) || dentry->d_inode) | ||
882 | return finish_no_open(file, res); | ||
883 | |||
884 | err = 0; | ||
885 | fid = NULL; | ||
886 | v9ses = v9fs_inode2v9ses(dir); | ||
887 | perm = unixmode2p9mode(v9ses, mode); | ||
888 | fid = v9fs_create(v9ses, dir, dentry, NULL, perm, | ||
889 | v9fs_uflags2omode(flags, | ||
890 | v9fs_proto_dotu(v9ses))); | ||
891 | if (IS_ERR(fid)) { | ||
892 | err = PTR_ERR(fid); | ||
893 | fid = NULL; | ||
894 | goto error; | ||
895 | } | ||
896 | |||
897 | v9fs_invalidate_inode_attr(dir); | ||
898 | v9inode = V9FS_I(dentry->d_inode); | ||
899 | mutex_lock(&v9inode->v_mutex); | ||
900 | if (v9ses->cache && !v9inode->writeback_fid && | ||
901 | ((flags & O_ACCMODE) != O_RDONLY)) { | ||
902 | /* | ||
903 | * clone a fid and add it to writeback_fid | ||
904 | * we do it during open time instead of | ||
905 | * page dirty time via write_begin/page_mkwrite | ||
906 | * because we want write after unlink usecase | ||
907 | * to work. | ||
908 | */ | ||
909 | inode_fid = v9fs_writeback_fid(dentry); | ||
910 | if (IS_ERR(inode_fid)) { | ||
911 | err = PTR_ERR(inode_fid); | ||
912 | mutex_unlock(&v9inode->v_mutex); | ||
913 | goto error; | ||
914 | } | ||
915 | v9inode->writeback_fid = (void *) inode_fid; | ||
916 | } | ||
917 | mutex_unlock(&v9inode->v_mutex); | ||
918 | err = finish_open(file, dentry, generic_file_open, opened); | ||
919 | if (err) | ||
920 | goto error; | ||
921 | |||
922 | file->private_data = fid; | ||
923 | #ifdef CONFIG_9P_FSCACHE | ||
924 | if (v9ses->cache) | ||
925 | v9fs_cache_inode_set_cookie(dentry->d_inode, file); | ||
926 | #endif | ||
927 | |||
928 | *opened |= FILE_CREATED; | ||
929 | out: | ||
930 | dput(res); | ||
931 | return err; | ||
932 | |||
933 | error: | ||
934 | if (fid) | ||
935 | p9_client_clunk(fid); | ||
936 | goto out; | ||
937 | } | ||
938 | |||
913 | /** | 939 | /** |
914 | * v9fs_vfs_unlink - VFS unlink hook to delete an inode | 940 | * v9fs_vfs_unlink - VFS unlink hook to delete an inode |
915 | * @i: inode that is being unlinked | 941 | * @i: inode that is being unlinked |
@@ -1488,6 +1514,7 @@ out: | |||
1488 | static const struct inode_operations v9fs_dir_inode_operations_dotu = { | 1514 | static const struct inode_operations v9fs_dir_inode_operations_dotu = { |
1489 | .create = v9fs_vfs_create, | 1515 | .create = v9fs_vfs_create, |
1490 | .lookup = v9fs_vfs_lookup, | 1516 | .lookup = v9fs_vfs_lookup, |
1517 | .atomic_open = v9fs_vfs_atomic_open, | ||
1491 | .symlink = v9fs_vfs_symlink, | 1518 | .symlink = v9fs_vfs_symlink, |
1492 | .link = v9fs_vfs_link, | 1519 | .link = v9fs_vfs_link, |
1493 | .unlink = v9fs_vfs_unlink, | 1520 | .unlink = v9fs_vfs_unlink, |
@@ -1502,6 +1529,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = { | |||
1502 | static const struct inode_operations v9fs_dir_inode_operations = { | 1529 | static const struct inode_operations v9fs_dir_inode_operations = { |
1503 | .create = v9fs_vfs_create, | 1530 | .create = v9fs_vfs_create, |
1504 | .lookup = v9fs_vfs_lookup, | 1531 | .lookup = v9fs_vfs_lookup, |
1532 | .atomic_open = v9fs_vfs_atomic_open, | ||
1505 | .unlink = v9fs_vfs_unlink, | 1533 | .unlink = v9fs_vfs_unlink, |
1506 | .mkdir = v9fs_vfs_mkdir, | 1534 | .mkdir = v9fs_vfs_mkdir, |
1507 | .rmdir = v9fs_vfs_rmdir, | 1535 | .rmdir = v9fs_vfs_rmdir, |