aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/9p/vfs_inode.c114
-rw-r--r--include/net/9p/9p.h4
-rw-r--r--include/net/9p/client.h2
-rw-r--r--net/9p/client.c44
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
653static int
654v9fs_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
748error:
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
1810static const struct inode_operations v9fs_dir_inode_operations_dotl = { 1922static 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 { \
137enum p9_msg_t { 139enum 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,
229int p9_client_link(struct p9_fid *fid, struct p9_fid *oldfid, char *newname); 229int p9_client_link(struct p9_fid *fid, struct p9_fid *oldfid, char *newname);
230int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid, 230int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid,
231 struct p9_qid *qid); 231 struct p9_qid *qid);
232int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
233 gid_t gid, struct p9_qid *qid);
232int p9_client_clunk(struct p9_fid *fid); 234int p9_client_clunk(struct p9_fid *fid);
233int p9_client_remove(struct p9_fid *fid); 235int p9_client_remove(struct p9_fid *fid);
234int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, 236int 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}
1051EXPORT_SYMBOL(p9_client_open); 1051EXPORT_SYMBOL(p9_client_open);
1052 1052
1053int 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
1090free_and_error:
1091 p9_free_req(clnt, req);
1092error:
1093 return err;
1094}
1095EXPORT_SYMBOL(p9_client_create_dotl);
1096
1053int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, 1097int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
1054 char *extension) 1098 char *extension)
1055{ 1099{