diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2012-06-05 09:10:26 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-14 08:33:17 -0400 |
commit | e43ae79c540270865918dab5ac914c74f43101e2 (patch) | |
tree | dc580a2de6799cfc3b99a6ab43e16c834e23736a /fs/9p | |
parent | 2d83bde9a16e18eafdc73a3a1f4a8eb110e49672 (diff) |
9p: implement i_op->atomic_open()
Add an ->atomic_open implementation which replaces the atomic open+create
operation implemented via ->create. No functionality is changed.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
CC: Eric Van Hensbergen <ericvh@gmail.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/9p')
-rw-r--r-- | fs/9p/vfs_inode.c | 169 | ||||
-rw-r--r-- | fs/9p/vfs_inode_dotl.c | 52 |
2 files changed, 137 insertions, 84 deletions
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 57ccb7537dae..e8c42ceb89ba 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -712,11 +712,14 @@ 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 | ||
@@ -724,76 +727,19 @@ 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 | struct nameidata *nd) |
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 | /** |
@@ -910,6 +856,93 @@ error: | |||
910 | return ERR_PTR(result); | 856 | return ERR_PTR(result); |
911 | } | 857 | } |
912 | 858 | ||
859 | static struct file * | ||
860 | v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, | ||
861 | struct opendata *od, unsigned flags, umode_t mode, | ||
862 | bool *created) | ||
863 | { | ||
864 | int err; | ||
865 | u32 perm; | ||
866 | struct file *filp; | ||
867 | struct v9fs_inode *v9inode; | ||
868 | struct v9fs_session_info *v9ses; | ||
869 | struct p9_fid *fid, *inode_fid; | ||
870 | struct dentry *res = NULL; | ||
871 | |||
872 | if (d_unhashed(dentry)) { | ||
873 | res = v9fs_vfs_lookup(dir, dentry, NULL); | ||
874 | if (IS_ERR(res)) | ||
875 | return ERR_CAST(res); | ||
876 | |||
877 | if (res) | ||
878 | dentry = res; | ||
879 | } | ||
880 | |||
881 | /* Only creates */ | ||
882 | if (!(flags & O_CREAT) || dentry->d_inode) { | ||
883 | finish_no_open(od, res); | ||
884 | return NULL; | ||
885 | } | ||
886 | |||
887 | err = 0; | ||
888 | fid = NULL; | ||
889 | v9ses = v9fs_inode2v9ses(dir); | ||
890 | perm = unixmode2p9mode(v9ses, mode); | ||
891 | fid = v9fs_create(v9ses, dir, dentry, NULL, perm, | ||
892 | v9fs_uflags2omode(flags, | ||
893 | v9fs_proto_dotu(v9ses))); | ||
894 | if (IS_ERR(fid)) { | ||
895 | err = PTR_ERR(fid); | ||
896 | fid = NULL; | ||
897 | goto error; | ||
898 | } | ||
899 | |||
900 | v9fs_invalidate_inode_attr(dir); | ||
901 | v9inode = V9FS_I(dentry->d_inode); | ||
902 | mutex_lock(&v9inode->v_mutex); | ||
903 | if (v9ses->cache && !v9inode->writeback_fid && | ||
904 | ((flags & O_ACCMODE) != O_RDONLY)) { | ||
905 | /* | ||
906 | * clone a fid and add it to writeback_fid | ||
907 | * we do it during open time instead of | ||
908 | * page dirty time via write_begin/page_mkwrite | ||
909 | * because we want write after unlink usecase | ||
910 | * to work. | ||
911 | */ | ||
912 | inode_fid = v9fs_writeback_fid(dentry); | ||
913 | if (IS_ERR(inode_fid)) { | ||
914 | err = PTR_ERR(inode_fid); | ||
915 | mutex_unlock(&v9inode->v_mutex); | ||
916 | goto error; | ||
917 | } | ||
918 | v9inode->writeback_fid = (void *) inode_fid; | ||
919 | } | ||
920 | mutex_unlock(&v9inode->v_mutex); | ||
921 | filp = finish_open(od, dentry, generic_file_open); | ||
922 | if (IS_ERR(filp)) { | ||
923 | err = PTR_ERR(filp); | ||
924 | goto error; | ||
925 | } | ||
926 | |||
927 | filp->private_data = fid; | ||
928 | #ifdef CONFIG_9P_FSCACHE | ||
929 | if (v9ses->cache) | ||
930 | v9fs_cache_inode_set_cookie(dentry->d_inode, filp); | ||
931 | #endif | ||
932 | |||
933 | *created = true; | ||
934 | out: | ||
935 | dput(res); | ||
936 | return filp; | ||
937 | |||
938 | error: | ||
939 | if (fid) | ||
940 | p9_client_clunk(fid); | ||
941 | |||
942 | filp = ERR_PTR(err); | ||
943 | goto out; | ||
944 | } | ||
945 | |||
913 | /** | 946 | /** |
914 | * v9fs_vfs_unlink - VFS unlink hook to delete an inode | 947 | * v9fs_vfs_unlink - VFS unlink hook to delete an inode |
915 | * @i: inode that is being unlinked | 948 | * @i: inode that is being unlinked |
@@ -1488,6 +1521,7 @@ out: | |||
1488 | static const struct inode_operations v9fs_dir_inode_operations_dotu = { | 1521 | static const struct inode_operations v9fs_dir_inode_operations_dotu = { |
1489 | .create = v9fs_vfs_create, | 1522 | .create = v9fs_vfs_create, |
1490 | .lookup = v9fs_vfs_lookup, | 1523 | .lookup = v9fs_vfs_lookup, |
1524 | .atomic_open = v9fs_vfs_atomic_open, | ||
1491 | .symlink = v9fs_vfs_symlink, | 1525 | .symlink = v9fs_vfs_symlink, |
1492 | .link = v9fs_vfs_link, | 1526 | .link = v9fs_vfs_link, |
1493 | .unlink = v9fs_vfs_unlink, | 1527 | .unlink = v9fs_vfs_unlink, |
@@ -1502,6 +1536,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = { | |||
1502 | static const struct inode_operations v9fs_dir_inode_operations = { | 1536 | static const struct inode_operations v9fs_dir_inode_operations = { |
1503 | .create = v9fs_vfs_create, | 1537 | .create = v9fs_vfs_create, |
1504 | .lookup = v9fs_vfs_lookup, | 1538 | .lookup = v9fs_vfs_lookup, |
1539 | .atomic_open = v9fs_vfs_atomic_open, | ||
1505 | .unlink = v9fs_vfs_unlink, | 1540 | .unlink = v9fs_vfs_unlink, |
1506 | .mkdir = v9fs_vfs_mkdir, | 1541 | .mkdir = v9fs_vfs_mkdir, |
1507 | .rmdir = v9fs_vfs_rmdir, | 1542 | .rmdir = v9fs_vfs_rmdir, |
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index e3dd2a1e2bfc..a354fe2cb234 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c | |||
@@ -230,7 +230,6 @@ int v9fs_open_to_dotl_flags(int flags) | |||
230 | * @dir: directory inode that is being created | 230 | * @dir: directory inode that is being created |
231 | * @dentry: dentry that is being deleted | 231 | * @dentry: dentry that is being deleted |
232 | * @mode: create permissions | 232 | * @mode: create permissions |
233 | * @nd: path information | ||
234 | * | 233 | * |
235 | */ | 234 | */ |
236 | 235 | ||
@@ -238,9 +237,16 @@ static int | |||
238 | v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode, | 237 | v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode, |
239 | struct nameidata *nd) | 238 | struct nameidata *nd) |
240 | { | 239 | { |
240 | return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0); | ||
241 | } | ||
242 | |||
243 | static struct file * | ||
244 | v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, | ||
245 | struct opendata *od, unsigned flags, umode_t omode, | ||
246 | bool *created) | ||
247 | { | ||
241 | int err = 0; | 248 | int err = 0; |
242 | gid_t gid; | 249 | gid_t gid; |
243 | int flags; | ||
244 | umode_t mode; | 250 | umode_t mode; |
245 | char *name = NULL; | 251 | char *name = NULL; |
246 | struct file *filp; | 252 | struct file *filp; |
@@ -251,19 +257,25 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode, | |||
251 | struct p9_fid *dfid, *ofid, *inode_fid; | 257 | struct p9_fid *dfid, *ofid, *inode_fid; |
252 | struct v9fs_session_info *v9ses; | 258 | struct v9fs_session_info *v9ses; |
253 | struct posix_acl *pacl = NULL, *dacl = NULL; | 259 | struct posix_acl *pacl = NULL, *dacl = NULL; |
260 | struct dentry *res = NULL; | ||
254 | 261 | ||
255 | v9ses = v9fs_inode2v9ses(dir); | 262 | if (d_unhashed(dentry)) { |
256 | if (nd) | 263 | res = v9fs_vfs_lookup(dir, dentry, NULL); |
257 | flags = nd->intent.open.flags; | 264 | if (IS_ERR(res)) |
258 | else { | 265 | return ERR_CAST(res); |
259 | /* | 266 | |
260 | * create call without LOOKUP_OPEN is due | 267 | if (res) |
261 | * to mknod of regular files. So use mknod | 268 | dentry = res; |
262 | * operation. | 269 | } |
263 | */ | 270 | |
264 | return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0); | 271 | /* Only creates */ |
272 | if (!(flags & O_CREAT) || dentry->d_inode) { | ||
273 | finish_no_open(od, res); | ||
274 | return NULL; | ||
265 | } | 275 | } |
266 | 276 | ||
277 | v9ses = v9fs_inode2v9ses(dir); | ||
278 | |||
267 | name = (char *) dentry->d_name.name; | 279 | name = (char *) dentry->d_name.name; |
268 | p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%hx\n", | 280 | p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%hx\n", |
269 | name, flags, omode); | 281 | name, flags, omode); |
@@ -272,7 +284,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode, | |||
272 | if (IS_ERR(dfid)) { | 284 | if (IS_ERR(dfid)) { |
273 | err = PTR_ERR(dfid); | 285 | err = PTR_ERR(dfid); |
274 | p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err); | 286 | p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err); |
275 | return err; | 287 | goto err_return; |
276 | } | 288 | } |
277 | 289 | ||
278 | /* clone a fid to use for creation */ | 290 | /* clone a fid to use for creation */ |
@@ -280,7 +292,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode, | |||
280 | if (IS_ERR(ofid)) { | 292 | if (IS_ERR(ofid)) { |
281 | err = PTR_ERR(ofid); | 293 | err = PTR_ERR(ofid); |
282 | p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); | 294 | p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); |
283 | return err; | 295 | goto err_return; |
284 | } | 296 | } |
285 | 297 | ||
286 | gid = v9fs_get_fsgid_for_create(dir); | 298 | gid = v9fs_get_fsgid_for_create(dir); |
@@ -345,7 +357,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode, | |||
345 | } | 357 | } |
346 | mutex_unlock(&v9inode->v_mutex); | 358 | mutex_unlock(&v9inode->v_mutex); |
347 | /* Since we are opening a file, assign the open fid to the file */ | 359 | /* Since we are opening a file, assign the open fid to the file */ |
348 | filp = lookup_instantiate_filp(nd, dentry, generic_file_open); | 360 | filp = finish_open(od, dentry, generic_file_open); |
349 | if (IS_ERR(filp)) { | 361 | if (IS_ERR(filp)) { |
350 | err = PTR_ERR(filp); | 362 | err = PTR_ERR(filp); |
351 | goto err_clunk_old_fid; | 363 | goto err_clunk_old_fid; |
@@ -355,7 +367,10 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode, | |||
355 | if (v9ses->cache) | 367 | if (v9ses->cache) |
356 | v9fs_cache_inode_set_cookie(inode, filp); | 368 | v9fs_cache_inode_set_cookie(inode, filp); |
357 | #endif | 369 | #endif |
358 | return 0; | 370 | *created = true; |
371 | out: | ||
372 | dput(res); | ||
373 | return filp; | ||
359 | 374 | ||
360 | error: | 375 | error: |
361 | if (fid) | 376 | if (fid) |
@@ -364,7 +379,9 @@ err_clunk_old_fid: | |||
364 | if (ofid) | 379 | if (ofid) |
365 | p9_client_clunk(ofid); | 380 | p9_client_clunk(ofid); |
366 | v9fs_set_create_acl(NULL, &dacl, &pacl); | 381 | v9fs_set_create_acl(NULL, &dacl, &pacl); |
367 | return err; | 382 | err_return: |
383 | filp = ERR_PTR(err); | ||
384 | goto out; | ||
368 | } | 385 | } |
369 | 386 | ||
370 | /** | 387 | /** |
@@ -982,6 +999,7 @@ out: | |||
982 | 999 | ||
983 | const struct inode_operations v9fs_dir_inode_operations_dotl = { | 1000 | const struct inode_operations v9fs_dir_inode_operations_dotl = { |
984 | .create = v9fs_vfs_create_dotl, | 1001 | .create = v9fs_vfs_create_dotl, |
1002 | .atomic_open = v9fs_vfs_atomic_open_dotl, | ||
985 | .lookup = v9fs_vfs_lookup, | 1003 | .lookup = v9fs_vfs_lookup, |
986 | .link = v9fs_vfs_link_dotl, | 1004 | .link = v9fs_vfs_link_dotl, |
987 | .symlink = v9fs_vfs_symlink_dotl, | 1005 | .symlink = v9fs_vfs_symlink_dotl, |