diff options
-rw-r--r-- | fs/9p/vfs_inode.c | 114 | ||||
-rw-r--r-- | include/net/9p/9p.h | 4 | ||||
-rw-r--r-- | include/net/9p/client.h | 2 | ||||
-rw-r--r-- | net/9p/client.c | 44 |
4 files changed, 163 insertions, 1 deletions
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 39dc79567322..2ac245902a4f 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -642,6 +642,118 @@ error: | |||
642 | } | 642 | } |
643 | 643 | ||
644 | /** | 644 | /** |
645 | * v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol. | ||
646 | * @dir: directory inode that is being created | ||
647 | * @dentry: dentry that is being deleted | ||
648 | * @mode: create permissions | ||
649 | * @nd: path information | ||
650 | * | ||
651 | */ | ||
652 | |||
653 | static int | ||
654 | v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode, | ||
655 | struct nameidata *nd) | ||
656 | { | ||
657 | int err = 0; | ||
658 | char *name = NULL; | ||
659 | gid_t gid; | ||
660 | int flags; | ||
661 | struct v9fs_session_info *v9ses; | ||
662 | struct p9_fid *fid = NULL; | ||
663 | struct p9_fid *dfid, *ofid; | ||
664 | struct file *filp; | ||
665 | struct p9_qid qid; | ||
666 | struct inode *inode; | ||
667 | |||
668 | v9ses = v9fs_inode2v9ses(dir); | ||
669 | if (nd && nd->flags & LOOKUP_OPEN) | ||
670 | flags = nd->intent.open.flags - 1; | ||
671 | else | ||
672 | flags = O_RDWR; | ||
673 | |||
674 | name = (char *) dentry->d_name.name; | ||
675 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x " | ||
676 | "mode:0x%x\n", name, flags, mode); | ||
677 | |||
678 | dfid = v9fs_fid_lookup(dentry->d_parent); | ||
679 | if (IS_ERR(dfid)) { | ||
680 | err = PTR_ERR(dfid); | ||
681 | P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err); | ||
682 | return err; | ||
683 | } | ||
684 | |||
685 | /* clone a fid to use for creation */ | ||
686 | ofid = p9_client_walk(dfid, 0, NULL, 1); | ||
687 | if (IS_ERR(ofid)) { | ||
688 | err = PTR_ERR(ofid); | ||
689 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); | ||
690 | return err; | ||
691 | } | ||
692 | |||
693 | gid = v9fs_get_fsgid_for_create(dir); | ||
694 | err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid); | ||
695 | if (err < 0) { | ||
696 | P9_DPRINTK(P9_DEBUG_VFS, | ||
697 | "p9_client_open_dotl failed in creat %d\n", | ||
698 | err); | ||
699 | goto error; | ||
700 | } | ||
701 | |||
702 | /* No need to populate the inode if we are not opening the file AND | ||
703 | * not in cached mode. | ||
704 | */ | ||
705 | if (!v9ses->cache && !(nd && nd->flags & LOOKUP_OPEN)) { | ||
706 | /* Not in cached mode. No need to populate inode with stat */ | ||
707 | dentry->d_op = &v9fs_dentry_operations; | ||
708 | p9_client_clunk(ofid); | ||
709 | d_instantiate(dentry, NULL); | ||
710 | return 0; | ||
711 | } | ||
712 | |||
713 | /* Now walk from the parent so we can get an unopened fid. */ | ||
714 | fid = p9_client_walk(dfid, 1, &name, 1); | ||
715 | if (IS_ERR(fid)) { | ||
716 | err = PTR_ERR(fid); | ||
717 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); | ||
718 | fid = NULL; | ||
719 | goto error; | ||
720 | } | ||
721 | |||
722 | /* instantiate inode and assign the unopened fid to dentry */ | ||
723 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | ||
724 | if (IS_ERR(inode)) { | ||
725 | err = PTR_ERR(inode); | ||
726 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); | ||
727 | goto error; | ||
728 | } | ||
729 | dentry->d_op = &v9fs_cached_dentry_operations; | ||
730 | d_instantiate(dentry, inode); | ||
731 | err = v9fs_fid_add(dentry, fid); | ||
732 | if (err < 0) | ||
733 | goto error; | ||
734 | |||
735 | /* if we are opening a file, assign the open fid to the file */ | ||
736 | if (nd && nd->flags & LOOKUP_OPEN) { | ||
737 | filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); | ||
738 | if (IS_ERR(filp)) { | ||
739 | p9_client_clunk(ofid); | ||
740 | return PTR_ERR(filp); | ||
741 | } | ||
742 | filp->private_data = ofid; | ||
743 | } else | ||
744 | p9_client_clunk(ofid); | ||
745 | |||
746 | return 0; | ||
747 | |||
748 | error: | ||
749 | if (ofid) | ||
750 | p9_client_clunk(ofid); | ||
751 | if (fid) | ||
752 | p9_client_clunk(fid); | ||
753 | return err; | ||
754 | } | ||
755 | |||
756 | /** | ||
645 | * v9fs_vfs_create - VFS hook to create files | 757 | * v9fs_vfs_create - VFS hook to create files |
646 | * @dir: directory inode that is being created | 758 | * @dir: directory inode that is being created |
647 | * @dentry: dentry that is being deleted | 759 | * @dentry: dentry that is being deleted |
@@ -1808,7 +1920,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = { | |||
1808 | }; | 1920 | }; |
1809 | 1921 | ||
1810 | static const struct inode_operations v9fs_dir_inode_operations_dotl = { | 1922 | static const struct inode_operations v9fs_dir_inode_operations_dotl = { |
1811 | .create = v9fs_vfs_create, | 1923 | .create = v9fs_vfs_create_dotl, |
1812 | .lookup = v9fs_vfs_lookup, | 1924 | .lookup = v9fs_vfs_lookup, |
1813 | .link = v9fs_vfs_link_dotl, | 1925 | .link = v9fs_vfs_link_dotl, |
1814 | .symlink = v9fs_vfs_symlink_dotl, | 1926 | .symlink = v9fs_vfs_symlink_dotl, |
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index 091b471d8f05..06d111d61038 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h | |||
@@ -92,6 +92,8 @@ do { \ | |||
92 | * @P9_RSYMLINK: make symlink response | 92 | * @P9_RSYMLINK: make symlink response |
93 | * @P9_TMKNOD: create a special file object request | 93 | * @P9_TMKNOD: create a special file object request |
94 | * @P9_RMKNOD: create a special file object response | 94 | * @P9_RMKNOD: create a special file object response |
95 | * @P9_TLCREATE: prepare a handle for I/O on an new file for 9P2000.L | ||
96 | * @P9_RLCREATE: response with file access information for 9P2000.L | ||
95 | * @P9_TRENAME: rename request | 97 | * @P9_TRENAME: rename request |
96 | * @P9_RRENAME: rename response | 98 | * @P9_RRENAME: rename response |
97 | * @P9_TMKDIR: create a directory request | 99 | * @P9_TMKDIR: create a directory request |
@@ -137,6 +139,8 @@ do { \ | |||
137 | enum p9_msg_t { | 139 | enum p9_msg_t { |
138 | P9_TSTATFS = 8, | 140 | P9_TSTATFS = 8, |
139 | P9_RSTATFS, | 141 | P9_RSTATFS, |
142 | P9_TLCREATE = 14, | ||
143 | P9_RLCREATE, | ||
140 | P9_TSYMLINK = 16, | 144 | P9_TSYMLINK = 16, |
141 | P9_RSYMLINK, | 145 | P9_RSYMLINK, |
142 | P9_TMKNOD = 18, | 146 | P9_TMKNOD = 18, |
diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 55d913a9b797..d755c0ed6750 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h | |||
@@ -229,6 +229,8 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, | |||
229 | int p9_client_link(struct p9_fid *fid, struct p9_fid *oldfid, char *newname); | 229 | int p9_client_link(struct p9_fid *fid, struct p9_fid *oldfid, char *newname); |
230 | int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid, | 230 | int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid, |
231 | struct p9_qid *qid); | 231 | struct p9_qid *qid); |
232 | int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, | ||
233 | gid_t gid, struct p9_qid *qid); | ||
232 | int p9_client_clunk(struct p9_fid *fid); | 234 | int p9_client_clunk(struct p9_fid *fid); |
233 | int p9_client_remove(struct p9_fid *fid); | 235 | int p9_client_remove(struct p9_fid *fid); |
234 | int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, | 236 | int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, |
diff --git a/net/9p/client.c b/net/9p/client.c index a3bdd341f2ac..e580409b1052 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -1050,6 +1050,50 @@ error: | |||
1050 | } | 1050 | } |
1051 | EXPORT_SYMBOL(p9_client_open); | 1051 | EXPORT_SYMBOL(p9_client_open); |
1052 | 1052 | ||
1053 | int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, | ||
1054 | gid_t gid, struct p9_qid *qid) | ||
1055 | { | ||
1056 | int err = 0; | ||
1057 | struct p9_client *clnt; | ||
1058 | struct p9_req_t *req; | ||
1059 | int iounit; | ||
1060 | |||
1061 | P9_DPRINTK(P9_DEBUG_9P, | ||
1062 | ">>> TLCREATE fid %d name %s flags %d mode %d gid %d\n", | ||
1063 | ofid->fid, name, flags, mode, gid); | ||
1064 | clnt = ofid->clnt; | ||
1065 | |||
1066 | if (ofid->mode != -1) | ||
1067 | return -EINVAL; | ||
1068 | |||
1069 | req = p9_client_rpc(clnt, P9_TLCREATE, "dsddd", ofid->fid, name, flags, | ||
1070 | mode, gid); | ||
1071 | if (IS_ERR(req)) { | ||
1072 | err = PTR_ERR(req); | ||
1073 | goto error; | ||
1074 | } | ||
1075 | |||
1076 | err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit); | ||
1077 | if (err) { | ||
1078 | p9pdu_dump(1, req->rc); | ||
1079 | goto free_and_error; | ||
1080 | } | ||
1081 | |||
1082 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLCREATE qid %x.%llx.%x iounit %x\n", | ||
1083 | qid->type, | ||
1084 | (unsigned long long)qid->path, | ||
1085 | qid->version, iounit); | ||
1086 | |||
1087 | ofid->mode = mode; | ||
1088 | ofid->iounit = iounit; | ||
1089 | |||
1090 | free_and_error: | ||
1091 | p9_free_req(clnt, req); | ||
1092 | error: | ||
1093 | return err; | ||
1094 | } | ||
1095 | EXPORT_SYMBOL(p9_client_create_dotl); | ||
1096 | |||
1053 | int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, | 1097 | int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, |
1054 | char *extension) | 1098 | char *extension) |
1055 | { | 1099 | { |