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 | { |
