aboutsummaryrefslogtreecommitdiffstats
path: root/net/9p
diff options
context:
space:
mode:
Diffstat (limited to 'net/9p')
-rw-r--r--net/9p/client.c653
-rw-r--r--net/9p/protocol.c151
-rw-r--r--net/9p/protocol.h6
-rw-r--r--net/9p/trans_fd.c13
-rw-r--r--net/9p/trans_rdma.c40
-rw-r--r--net/9p/trans_virtio.c154
-rw-r--r--net/9p/util.c1
7 files changed, 848 insertions, 170 deletions
diff --git a/net/9p/client.c b/net/9p/client.c
index 8af95b2dddd6..9eb72505308f 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -29,6 +29,7 @@
29#include <linux/poll.h> 29#include <linux/poll.h>
30#include <linux/idr.h> 30#include <linux/idr.h>
31#include <linux/mutex.h> 31#include <linux/mutex.h>
32#include <linux/slab.h>
32#include <linux/sched.h> 33#include <linux/sched.h>
33#include <linux/uaccess.h> 34#include <linux/uaccess.h>
34#include <net/9p/9p.h> 35#include <net/9p/9p.h>
@@ -46,6 +47,7 @@ enum {
46 Opt_msize, 47 Opt_msize,
47 Opt_trans, 48 Opt_trans,
48 Opt_legacy, 49 Opt_legacy,
50 Opt_version,
49 Opt_err, 51 Opt_err,
50}; 52};
51 53
@@ -53,9 +55,43 @@ static const match_table_t tokens = {
53 {Opt_msize, "msize=%u"}, 55 {Opt_msize, "msize=%u"},
54 {Opt_legacy, "noextend"}, 56 {Opt_legacy, "noextend"},
55 {Opt_trans, "trans=%s"}, 57 {Opt_trans, "trans=%s"},
58 {Opt_version, "version=%s"},
56 {Opt_err, NULL}, 59 {Opt_err, NULL},
57}; 60};
58 61
62inline int p9_is_proto_dotl(struct p9_client *clnt)
63{
64 return (clnt->proto_version == p9_proto_2000L);
65}
66EXPORT_SYMBOL(p9_is_proto_dotl);
67
68inline int p9_is_proto_dotu(struct p9_client *clnt)
69{
70 return (clnt->proto_version == p9_proto_2000u);
71}
72EXPORT_SYMBOL(p9_is_proto_dotu);
73
74/* Interpret mount option for protocol version */
75static int get_protocol_version(const substring_t *name)
76{
77 int version = -EINVAL;
78
79 if (!strncmp("9p2000", name->from, name->to-name->from)) {
80 version = p9_proto_legacy;
81 P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n");
82 } else if (!strncmp("9p2000.u", name->from, name->to-name->from)) {
83 version = p9_proto_2000u;
84 P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.u\n");
85 } else if (!strncmp("9p2000.L", name->from, name->to-name->from)) {
86 version = p9_proto_2000L;
87 P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.L\n");
88 } else {
89 P9_DPRINTK(P9_DEBUG_ERROR, "Unknown protocol version %s. ",
90 name->from);
91 }
92 return version;
93}
94
59static struct p9_req_t * 95static struct p9_req_t *
60p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); 96p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
61 97
@@ -69,24 +105,25 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
69 105
70static int parse_opts(char *opts, struct p9_client *clnt) 106static int parse_opts(char *opts, struct p9_client *clnt)
71{ 107{
72 char *options; 108 char *options, *tmp_options;
73 char *p; 109 char *p;
74 substring_t args[MAX_OPT_ARGS]; 110 substring_t args[MAX_OPT_ARGS];
75 int option; 111 int option;
76 int ret = 0; 112 int ret = 0;
77 113
78 clnt->dotu = 1; 114 clnt->proto_version = p9_proto_2000u;
79 clnt->msize = 8192; 115 clnt->msize = 8192;
80 116
81 if (!opts) 117 if (!opts)
82 return 0; 118 return 0;
83 119
84 options = kstrdup(opts, GFP_KERNEL); 120 tmp_options = kstrdup(opts, GFP_KERNEL);
85 if (!options) { 121 if (!tmp_options) {
86 P9_DPRINTK(P9_DEBUG_ERROR, 122 P9_DPRINTK(P9_DEBUG_ERROR,
87 "failed to allocate copy of option string\n"); 123 "failed to allocate copy of option string\n");
88 return -ENOMEM; 124 return -ENOMEM;
89 } 125 }
126 options = tmp_options;
90 127
91 while ((p = strsep(&options, ",")) != NULL) { 128 while ((p = strsep(&options, ",")) != NULL) {
92 int token; 129 int token;
@@ -108,16 +145,30 @@ static int parse_opts(char *opts, struct p9_client *clnt)
108 break; 145 break;
109 case Opt_trans: 146 case Opt_trans:
110 clnt->trans_mod = v9fs_get_trans_by_name(&args[0]); 147 clnt->trans_mod = v9fs_get_trans_by_name(&args[0]);
148 if(clnt->trans_mod == NULL) {
149 P9_DPRINTK(P9_DEBUG_ERROR,
150 "Could not find request transport: %s\n",
151 (char *) &args[0]);
152 ret = -EINVAL;
153 goto free_and_return;
154 }
111 break; 155 break;
112 case Opt_legacy: 156 case Opt_legacy:
113 clnt->dotu = 0; 157 clnt->proto_version = p9_proto_legacy;
158 break;
159 case Opt_version:
160 ret = get_protocol_version(&args[0]);
161 if (ret == -EINVAL)
162 goto free_and_return;
163 clnt->proto_version = ret;
114 break; 164 break;
115 default: 165 default:
116 continue; 166 continue;
117 } 167 }
118 } 168 }
119 169
120 kfree(options); 170free_and_return:
171 kfree(tmp_options);
121 return ret; 172 return ret;
122} 173}
123 174
@@ -280,8 +331,10 @@ static void p9_tag_cleanup(struct p9_client *c)
280 } 331 }
281 } 332 }
282 333
283 if (c->tagpool) 334 if (c->tagpool) {
335 p9_idpool_put(0, c->tagpool); /* free reserved tag 0 */
284 p9_idpool_destroy(c->tagpool); 336 p9_idpool_destroy(c->tagpool);
337 }
285 338
286 /* free requests associated with tags */ 339 /* free requests associated with tags */
287 for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { 340 for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
@@ -401,14 +454,16 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
401 int ecode; 454 int ecode;
402 char *ename; 455 char *ename;
403 456
404 err = p9pdu_readf(req->rc, c->dotu, "s?d", &ename, &ecode); 457 err = p9pdu_readf(req->rc, c->proto_version, "s?d",
458 &ename, &ecode);
405 if (err) { 459 if (err) {
406 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", 460 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
407 err); 461 err);
408 return err; 462 return err;
409 } 463 }
410 464
411 if (c->dotu) 465 if (p9_is_proto_dotu(c) ||
466 p9_is_proto_dotl(c))
412 err = -ecode; 467 err = -ecode;
413 468
414 if (!err || !IS_ERR_VALUE(err)) 469 if (!err || !IS_ERR_VALUE(err))
@@ -483,7 +538,12 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
483 538
484 P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type); 539 P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type);
485 540
486 if (c->status != Connected) 541 /* we allow for any status other than disconnected */
542 if (c->status == Disconnected)
543 return ERR_PTR(-EIO);
544
545 /* if status is begin_disconnected we allow only clunk request */
546 if ((c->status == BeginDisconnect) && (type != P9_TCLUNK))
487 return ERR_PTR(-EIO); 547 return ERR_PTR(-EIO);
488 548
489 if (signal_pending(current)) { 549 if (signal_pending(current)) {
@@ -506,7 +566,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
506 /* marshall the data */ 566 /* marshall the data */
507 p9pdu_prepare(req->tc, tag, type); 567 p9pdu_prepare(req->tc, tag, type);
508 va_start(ap, fmt); 568 va_start(ap, fmt);
509 err = p9pdu_vwritef(req->tc, c->dotu, fmt, ap); 569 err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap);
510 va_end(ap); 570 va_end(ap);
511 p9pdu_finalize(req->tc); 571 p9pdu_finalize(req->tc);
512 572
@@ -618,14 +678,31 @@ int p9_client_version(struct p9_client *c)
618 char *version; 678 char *version;
619 int msize; 679 int msize;
620 680
621 P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n", 681 P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n",
622 c->msize, c->dotu); 682 c->msize, c->proto_version);
623 req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize, 683
624 c->dotu ? "9P2000.u" : "9P2000"); 684 switch (c->proto_version) {
685 case p9_proto_2000L:
686 req = p9_client_rpc(c, P9_TVERSION, "ds",
687 c->msize, "9P2000.L");
688 break;
689 case p9_proto_2000u:
690 req = p9_client_rpc(c, P9_TVERSION, "ds",
691 c->msize, "9P2000.u");
692 break;
693 case p9_proto_legacy:
694 req = p9_client_rpc(c, P9_TVERSION, "ds",
695 c->msize, "9P2000");
696 break;
697 default:
698 return -EINVAL;
699 break;
700 }
701
625 if (IS_ERR(req)) 702 if (IS_ERR(req))
626 return PTR_ERR(req); 703 return PTR_ERR(req);
627 704
628 err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version); 705 err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version);
629 if (err) { 706 if (err) {
630 P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); 707 P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
631 p9pdu_dump(1, req->rc); 708 p9pdu_dump(1, req->rc);
@@ -633,10 +710,12 @@ int p9_client_version(struct p9_client *c)
633 } 710 }
634 711
635 P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version); 712 P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
636 if (!memcmp(version, "9P2000.u", 8)) 713 if (!strncmp(version, "9P2000.L", 8))
637 c->dotu = 1; 714 c->proto_version = p9_proto_2000L;
638 else if (!memcmp(version, "9P2000", 6)) 715 else if (!strncmp(version, "9P2000.u", 8))
639 c->dotu = 0; 716 c->proto_version = p9_proto_2000u;
717 else if (!strncmp(version, "9P2000", 6))
718 c->proto_version = p9_proto_legacy;
640 else { 719 else {
641 err = -EREMOTEIO; 720 err = -EREMOTEIO;
642 goto error; 721 goto error;
@@ -667,18 +746,12 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
667 clnt->trans = NULL; 746 clnt->trans = NULL;
668 spin_lock_init(&clnt->lock); 747 spin_lock_init(&clnt->lock);
669 INIT_LIST_HEAD(&clnt->fidlist); 748 INIT_LIST_HEAD(&clnt->fidlist);
670 clnt->fidpool = p9_idpool_create();
671 if (IS_ERR(clnt->fidpool)) {
672 err = PTR_ERR(clnt->fidpool);
673 clnt->fidpool = NULL;
674 goto error;
675 }
676 749
677 p9_tag_init(clnt); 750 p9_tag_init(clnt);
678 751
679 err = parse_opts(options, clnt); 752 err = parse_opts(options, clnt);
680 if (err < 0) 753 if (err < 0)
681 goto error; 754 goto free_client;
682 755
683 if (!clnt->trans_mod) 756 if (!clnt->trans_mod)
684 clnt->trans_mod = v9fs_get_default_trans(); 757 clnt->trans_mod = v9fs_get_default_trans();
@@ -687,27 +760,40 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
687 err = -EPROTONOSUPPORT; 760 err = -EPROTONOSUPPORT;
688 P9_DPRINTK(P9_DEBUG_ERROR, 761 P9_DPRINTK(P9_DEBUG_ERROR,
689 "No transport defined or default transport\n"); 762 "No transport defined or default transport\n");
690 goto error; 763 goto free_client;
764 }
765
766 clnt->fidpool = p9_idpool_create();
767 if (IS_ERR(clnt->fidpool)) {
768 err = PTR_ERR(clnt->fidpool);
769 clnt->fidpool = NULL;
770 goto put_trans;
691 } 771 }
692 772
693 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d dotu %d\n", 773 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n",
694 clnt, clnt->trans_mod, clnt->msize, clnt->dotu); 774 clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
695 775
696 err = clnt->trans_mod->create(clnt, dev_name, options); 776 err = clnt->trans_mod->create(clnt, dev_name, options);
697 if (err) 777 if (err)
698 goto error; 778 goto destroy_fidpool;
699 779
700 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) 780 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize)
701 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; 781 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ;
702 782
703 err = p9_client_version(clnt); 783 err = p9_client_version(clnt);
704 if (err) 784 if (err)
705 goto error; 785 goto close_trans;
706 786
707 return clnt; 787 return clnt;
708 788
709error: 789close_trans:
710 p9_client_destroy(clnt); 790 clnt->trans_mod->close(clnt);
791destroy_fidpool:
792 p9_idpool_destroy(clnt->fidpool);
793put_trans:
794 v9fs_put_trans(clnt->trans_mod);
795free_client:
796 kfree(clnt);
711 return ERR_PTR(err); 797 return ERR_PTR(err);
712} 798}
713EXPORT_SYMBOL(p9_client_create); 799EXPORT_SYMBOL(p9_client_create);
@@ -723,8 +809,10 @@ void p9_client_destroy(struct p9_client *clnt)
723 809
724 v9fs_put_trans(clnt->trans_mod); 810 v9fs_put_trans(clnt->trans_mod);
725 811
726 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) 812 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) {
813 printk(KERN_INFO "Found fid %d not clunked\n", fid->fid);
727 p9_fid_destroy(fid); 814 p9_fid_destroy(fid);
815 }
728 816
729 if (clnt->fidpool) 817 if (clnt->fidpool)
730 p9_idpool_destroy(clnt->fidpool); 818 p9_idpool_destroy(clnt->fidpool);
@@ -742,6 +830,13 @@ void p9_client_disconnect(struct p9_client *clnt)
742} 830}
743EXPORT_SYMBOL(p9_client_disconnect); 831EXPORT_SYMBOL(p9_client_disconnect);
744 832
833void p9_client_begin_disconnect(struct p9_client *clnt)
834{
835 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
836 clnt->status = BeginDisconnect;
837}
838EXPORT_SYMBOL(p9_client_begin_disconnect);
839
745struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, 840struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
746 char *uname, u32 n_uname, char *aname) 841 char *uname, u32 n_uname, char *aname)
747{ 842{
@@ -768,7 +863,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
768 goto error; 863 goto error;
769 } 864 }
770 865
771 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); 866 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
772 if (err) { 867 if (err) {
773 p9pdu_dump(1, req->rc); 868 p9pdu_dump(1, req->rc);
774 p9_free_req(clnt, req); 869 p9_free_req(clnt, req);
@@ -817,7 +912,7 @@ p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname)
817 goto error; 912 goto error;
818 } 913 }
819 914
820 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); 915 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
821 if (err) { 916 if (err) {
822 p9pdu_dump(1, req->rc); 917 p9pdu_dump(1, req->rc);
823 p9_free_req(clnt, req); 918 p9_free_req(clnt, req);
@@ -851,6 +946,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
851 int16_t nwqids, count; 946 int16_t nwqids, count;
852 947
853 err = 0; 948 err = 0;
949 wqids = NULL;
854 clnt = oldfid->clnt; 950 clnt = oldfid->clnt;
855 if (clone) { 951 if (clone) {
856 fid = p9_fid_create(clnt); 952 fid = p9_fid_create(clnt);
@@ -875,7 +971,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
875 goto error; 971 goto error;
876 } 972 }
877 973
878 err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids); 974 err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids);
879 if (err) { 975 if (err) {
880 p9pdu_dump(1, req->rc); 976 p9pdu_dump(1, req->rc);
881 p9_free_req(clnt, req); 977 p9_free_req(clnt, req);
@@ -901,9 +997,11 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
901 else 997 else
902 fid->qid = oldfid->qid; 998 fid->qid = oldfid->qid;
903 999
1000 kfree(wqids);
904 return fid; 1001 return fid;
905 1002
906clunk_fid: 1003clunk_fid:
1004 kfree(wqids);
907 p9_client_clunk(fid); 1005 p9_client_clunk(fid);
908 fid = NULL; 1006 fid = NULL;
909 1007
@@ -923,29 +1021,32 @@ int p9_client_open(struct p9_fid *fid, int mode)
923 struct p9_qid qid; 1021 struct p9_qid qid;
924 int iounit; 1022 int iounit;
925 1023
926 P9_DPRINTK(P9_DEBUG_9P, ">>> TOPEN fid %d mode %d\n", fid->fid, mode);
927 err = 0;
928 clnt = fid->clnt; 1024 clnt = fid->clnt;
1025 P9_DPRINTK(P9_DEBUG_9P, ">>> %s fid %d mode %d\n",
1026 p9_is_proto_dotl(clnt) ? "TLOPEN" : "TOPEN", fid->fid, mode);
1027 err = 0;
929 1028
930 if (fid->mode != -1) 1029 if (fid->mode != -1)
931 return -EINVAL; 1030 return -EINVAL;
932 1031
933 req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode); 1032 if (p9_is_proto_dotl(clnt))
1033 req = p9_client_rpc(clnt, P9_TLOPEN, "dd", fid->fid, mode);
1034 else
1035 req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode);
934 if (IS_ERR(req)) { 1036 if (IS_ERR(req)) {
935 err = PTR_ERR(req); 1037 err = PTR_ERR(req);
936 goto error; 1038 goto error;
937 } 1039 }
938 1040
939 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); 1041 err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
940 if (err) { 1042 if (err) {
941 p9pdu_dump(1, req->rc); 1043 p9pdu_dump(1, req->rc);
942 goto free_and_error; 1044 goto free_and_error;
943 } 1045 }
944 1046
945 P9_DPRINTK(P9_DEBUG_9P, "<<< ROPEN qid %x.%llx.%x iounit %x\n", 1047 P9_DPRINTK(P9_DEBUG_9P, "<<< %s qid %x.%llx.%x iounit %x\n",
946 qid.type, 1048 p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN", qid.type,
947 (unsigned long long)qid.path, 1049 (unsigned long long)qid.path, qid.version, iounit);
948 qid.version, iounit);
949 1050
950 fid->mode = mode; 1051 fid->mode = mode;
951 fid->iounit = iounit; 1052 fid->iounit = iounit;
@@ -957,6 +1058,50 @@ error:
957} 1058}
958EXPORT_SYMBOL(p9_client_open); 1059EXPORT_SYMBOL(p9_client_open);
959 1060
1061int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
1062 gid_t gid, struct p9_qid *qid)
1063{
1064 int err = 0;
1065 struct p9_client *clnt;
1066 struct p9_req_t *req;
1067 int iounit;
1068
1069 P9_DPRINTK(P9_DEBUG_9P,
1070 ">>> TLCREATE fid %d name %s flags %d mode %d gid %d\n",
1071 ofid->fid, name, flags, mode, gid);
1072 clnt = ofid->clnt;
1073
1074 if (ofid->mode != -1)
1075 return -EINVAL;
1076
1077 req = p9_client_rpc(clnt, P9_TLCREATE, "dsddd", ofid->fid, name, flags,
1078 mode, gid);
1079 if (IS_ERR(req)) {
1080 err = PTR_ERR(req);
1081 goto error;
1082 }
1083
1084 err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit);
1085 if (err) {
1086 p9pdu_dump(1, req->rc);
1087 goto free_and_error;
1088 }
1089
1090 P9_DPRINTK(P9_DEBUG_9P, "<<< RLCREATE qid %x.%llx.%x iounit %x\n",
1091 qid->type,
1092 (unsigned long long)qid->path,
1093 qid->version, iounit);
1094
1095 ofid->mode = mode;
1096 ofid->iounit = iounit;
1097
1098free_and_error:
1099 p9_free_req(clnt, req);
1100error:
1101 return err;
1102}
1103EXPORT_SYMBOL(p9_client_create_dotl);
1104
960int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, 1105int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
961 char *extension) 1106 char *extension)
962{ 1107{
@@ -981,7 +1126,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
981 goto error; 1126 goto error;
982 } 1127 }
983 1128
984 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); 1129 err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
985 if (err) { 1130 if (err) {
986 p9pdu_dump(1, req->rc); 1131 p9pdu_dump(1, req->rc);
987 goto free_and_error; 1132 goto free_and_error;
@@ -1002,6 +1147,59 @@ error:
1002} 1147}
1003EXPORT_SYMBOL(p9_client_fcreate); 1148EXPORT_SYMBOL(p9_client_fcreate);
1004 1149
1150int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid,
1151 struct p9_qid *qid)
1152{
1153 int err = 0;
1154 struct p9_client *clnt;
1155 struct p9_req_t *req;
1156
1157 P9_DPRINTK(P9_DEBUG_9P, ">>> TSYMLINK dfid %d name %s symtgt %s\n",
1158 dfid->fid, name, symtgt);
1159 clnt = dfid->clnt;
1160
1161 req = p9_client_rpc(clnt, P9_TSYMLINK, "dssd", dfid->fid, name, symtgt,
1162 gid);
1163 if (IS_ERR(req)) {
1164 err = PTR_ERR(req);
1165 goto error;
1166 }
1167
1168 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
1169 if (err) {
1170 p9pdu_dump(1, req->rc);
1171 goto free_and_error;
1172 }
1173
1174 P9_DPRINTK(P9_DEBUG_9P, "<<< RSYMLINK qid %x.%llx.%x\n",
1175 qid->type, (unsigned long long)qid->path, qid->version);
1176
1177free_and_error:
1178 p9_free_req(clnt, req);
1179error:
1180 return err;
1181}
1182EXPORT_SYMBOL(p9_client_symlink);
1183
1184int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname)
1185{
1186 struct p9_client *clnt;
1187 struct p9_req_t *req;
1188
1189 P9_DPRINTK(P9_DEBUG_9P, ">>> TLINK dfid %d oldfid %d newname %s\n",
1190 dfid->fid, oldfid->fid, newname);
1191 clnt = dfid->clnt;
1192 req = p9_client_rpc(clnt, P9_TLINK, "dds", dfid->fid, oldfid->fid,
1193 newname);
1194 if (IS_ERR(req))
1195 return PTR_ERR(req);
1196
1197 P9_DPRINTK(P9_DEBUG_9P, "<<< RLINK\n");
1198 p9_free_req(clnt, req);
1199 return 0;
1200}
1201EXPORT_SYMBOL(p9_client_link);
1202
1005int p9_client_clunk(struct p9_fid *fid) 1203int p9_client_clunk(struct p9_fid *fid)
1006{ 1204{
1007 int err; 1205 int err;
@@ -1047,9 +1245,8 @@ int p9_client_remove(struct p9_fid *fid)
1047 P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid); 1245 P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid);
1048 1246
1049 p9_free_req(clnt, req); 1247 p9_free_req(clnt, req);
1050 p9_fid_destroy(fid);
1051
1052error: 1248error:
1249 p9_fid_destroy(fid);
1053 return err; 1250 return err;
1054} 1251}
1055EXPORT_SYMBOL(p9_client_remove); 1252EXPORT_SYMBOL(p9_client_remove);
@@ -1082,7 +1279,7 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
1082 goto error; 1279 goto error;
1083 } 1280 }
1084 1281
1085 err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr); 1282 err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
1086 if (err) { 1283 if (err) {
1087 p9pdu_dump(1, req->rc); 1284 p9pdu_dump(1, req->rc);
1088 goto free_and_error; 1285 goto free_and_error;
@@ -1143,7 +1340,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
1143 goto error; 1340 goto error;
1144 } 1341 }
1145 1342
1146 err = p9pdu_readf(req->rc, clnt->dotu, "d", &count); 1343 err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count);
1147 if (err) { 1344 if (err) {
1148 p9pdu_dump(1, req->rc); 1345 p9pdu_dump(1, req->rc);
1149 goto free_and_error; 1346 goto free_and_error;
@@ -1183,7 +1380,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
1183 goto error; 1380 goto error;
1184 } 1381 }
1185 1382
1186 err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret); 1383 err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret);
1187 if (err) { 1384 if (err) {
1188 p9pdu_dump(1, req->rc); 1385 p9pdu_dump(1, req->rc);
1189 p9_free_req(clnt, req); 1386 p9_free_req(clnt, req);
@@ -1210,14 +1407,74 @@ error:
1210} 1407}
1211EXPORT_SYMBOL(p9_client_stat); 1408EXPORT_SYMBOL(p9_client_stat);
1212 1409
1213static int p9_client_statsize(struct p9_wstat *wst, int optional) 1410struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
1411 u64 request_mask)
1412{
1413 int err;
1414 struct p9_client *clnt;
1415 struct p9_stat_dotl *ret = kmalloc(sizeof(struct p9_stat_dotl),
1416 GFP_KERNEL);
1417 struct p9_req_t *req;
1418
1419 P9_DPRINTK(P9_DEBUG_9P, ">>> TGETATTR fid %d, request_mask %lld\n",
1420 fid->fid, request_mask);
1421
1422 if (!ret)
1423 return ERR_PTR(-ENOMEM);
1424
1425 err = 0;
1426 clnt = fid->clnt;
1427
1428 req = p9_client_rpc(clnt, P9_TGETATTR, "dq", fid->fid, request_mask);
1429 if (IS_ERR(req)) {
1430 err = PTR_ERR(req);
1431 goto error;
1432 }
1433
1434 err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret);
1435 if (err) {
1436 p9pdu_dump(1, req->rc);
1437 p9_free_req(clnt, req);
1438 goto error;
1439 }
1440
1441 P9_DPRINTK(P9_DEBUG_9P,
1442 "<<< RGETATTR st_result_mask=%lld\n"
1443 "<<< qid=%x.%llx.%x\n"
1444 "<<< st_mode=%8.8x st_nlink=%llu\n"
1445 "<<< st_uid=%d st_gid=%d\n"
1446 "<<< st_rdev=%llx st_size=%llx st_blksize=%llu st_blocks=%llu\n"
1447 "<<< st_atime_sec=%lld st_atime_nsec=%lld\n"
1448 "<<< st_mtime_sec=%lld st_mtime_nsec=%lld\n"
1449 "<<< st_ctime_sec=%lld st_ctime_nsec=%lld\n"
1450 "<<< st_btime_sec=%lld st_btime_nsec=%lld\n"
1451 "<<< st_gen=%lld st_data_version=%lld",
1452 ret->st_result_mask, ret->qid.type, ret->qid.path,
1453 ret->qid.version, ret->st_mode, ret->st_nlink, ret->st_uid,
1454 ret->st_gid, ret->st_rdev, ret->st_size, ret->st_blksize,
1455 ret->st_blocks, ret->st_atime_sec, ret->st_atime_nsec,
1456 ret->st_mtime_sec, ret->st_mtime_nsec, ret->st_ctime_sec,
1457 ret->st_ctime_nsec, ret->st_btime_sec, ret->st_btime_nsec,
1458 ret->st_gen, ret->st_data_version);
1459
1460 p9_free_req(clnt, req);
1461 return ret;
1462
1463error:
1464 kfree(ret);
1465 return ERR_PTR(err);
1466}
1467EXPORT_SYMBOL(p9_client_getattr_dotl);
1468
1469static int p9_client_statsize(struct p9_wstat *wst, int proto_version)
1214{ 1470{
1215 int ret; 1471 int ret;
1216 1472
1473 /* NOTE: size shouldn't include its own length */
1217 /* size[2] type[2] dev[4] qid[13] */ 1474 /* size[2] type[2] dev[4] qid[13] */
1218 /* mode[4] atime[4] mtime[4] length[8]*/ 1475 /* mode[4] atime[4] mtime[4] length[8]*/
1219 /* name[s] uid[s] gid[s] muid[s] */ 1476 /* name[s] uid[s] gid[s] muid[s] */
1220 ret = 2+2+4+13+4+4+4+8+2+2+2+2; 1477 ret = 2+4+13+4+4+4+8+2+2+2+2;
1221 1478
1222 if (wst->name) 1479 if (wst->name)
1223 ret += strlen(wst->name); 1480 ret += strlen(wst->name);
@@ -1228,7 +1485,8 @@ static int p9_client_statsize(struct p9_wstat *wst, int optional)
1228 if (wst->muid) 1485 if (wst->muid)
1229 ret += strlen(wst->muid); 1486 ret += strlen(wst->muid);
1230 1487
1231 if (optional) { 1488 if ((proto_version == p9_proto_2000u) ||
1489 (proto_version == p9_proto_2000L)) {
1232 ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */ 1490 ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */
1233 if (wst->extension) 1491 if (wst->extension)
1234 ret += strlen(wst->extension); 1492 ret += strlen(wst->extension);
@@ -1245,7 +1503,7 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
1245 1503
1246 err = 0; 1504 err = 0;
1247 clnt = fid->clnt; 1505 clnt = fid->clnt;
1248 wst->size = p9_client_statsize(wst, clnt->dotu); 1506 wst->size = p9_client_statsize(wst, clnt->proto_version);
1249 P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid); 1507 P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid);
1250 P9_DPRINTK(P9_DEBUG_9P, 1508 P9_DPRINTK(P9_DEBUG_9P,
1251 " sz=%x type=%x dev=%x qid=%x.%llx.%x\n" 1509 " sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
@@ -1258,7 +1516,7 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
1258 wst->name, wst->uid, wst->gid, wst->muid, wst->extension, 1516 wst->name, wst->uid, wst->gid, wst->muid, wst->extension,
1259 wst->n_uid, wst->n_gid, wst->n_muid); 1517 wst->n_uid, wst->n_gid, wst->n_muid);
1260 1518
1261 req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, wst->size, wst); 1519 req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, wst->size+2, wst);
1262 if (IS_ERR(req)) { 1520 if (IS_ERR(req)) {
1263 err = PTR_ERR(req); 1521 err = PTR_ERR(req);
1264 goto error; 1522 goto error;
@@ -1271,3 +1529,284 @@ error:
1271 return err; 1529 return err;
1272} 1530}
1273EXPORT_SYMBOL(p9_client_wstat); 1531EXPORT_SYMBOL(p9_client_wstat);
1532
1533int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr)
1534{
1535 int err;
1536 struct p9_req_t *req;
1537 struct p9_client *clnt;
1538
1539 err = 0;
1540 clnt = fid->clnt;
1541 P9_DPRINTK(P9_DEBUG_9P, ">>> TSETATTR fid %d\n", fid->fid);
1542 P9_DPRINTK(P9_DEBUG_9P,
1543 " valid=%x mode=%x uid=%d gid=%d size=%lld\n"
1544 " atime_sec=%lld atime_nsec=%lld\n"
1545 " mtime_sec=%lld mtime_nsec=%lld\n",
1546 p9attr->valid, p9attr->mode, p9attr->uid, p9attr->gid,
1547 p9attr->size, p9attr->atime_sec, p9attr->atime_nsec,
1548 p9attr->mtime_sec, p9attr->mtime_nsec);
1549
1550 req = p9_client_rpc(clnt, P9_TSETATTR, "dI", fid->fid, p9attr);
1551
1552 if (IS_ERR(req)) {
1553 err = PTR_ERR(req);
1554 goto error;
1555 }
1556 P9_DPRINTK(P9_DEBUG_9P, "<<< RSETATTR fid %d\n", fid->fid);
1557 p9_free_req(clnt, req);
1558error:
1559 return err;
1560}
1561EXPORT_SYMBOL(p9_client_setattr);
1562
1563int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
1564{
1565 int err;
1566 struct p9_req_t *req;
1567 struct p9_client *clnt;
1568
1569 err = 0;
1570 clnt = fid->clnt;
1571
1572 P9_DPRINTK(P9_DEBUG_9P, ">>> TSTATFS fid %d\n", fid->fid);
1573
1574 req = p9_client_rpc(clnt, P9_TSTATFS, "d", fid->fid);
1575 if (IS_ERR(req)) {
1576 err = PTR_ERR(req);
1577 goto error;
1578 }
1579
1580 err = p9pdu_readf(req->rc, clnt->proto_version, "ddqqqqqqd", &sb->type,
1581 &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail,
1582 &sb->files, &sb->ffree, &sb->fsid, &sb->namelen);
1583 if (err) {
1584 p9pdu_dump(1, req->rc);
1585 p9_free_req(clnt, req);
1586 goto error;
1587 }
1588
1589 P9_DPRINTK(P9_DEBUG_9P, "<<< RSTATFS fid %d type 0x%lx bsize %ld "
1590 "blocks %llu bfree %llu bavail %llu files %llu ffree %llu "
1591 "fsid %llu namelen %ld\n",
1592 fid->fid, (long unsigned int)sb->type, (long int)sb->bsize,
1593 sb->blocks, sb->bfree, sb->bavail, sb->files, sb->ffree,
1594 sb->fsid, (long int)sb->namelen);
1595
1596 p9_free_req(clnt, req);
1597error:
1598 return err;
1599}
1600EXPORT_SYMBOL(p9_client_statfs);
1601
1602int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name)
1603{
1604 int err;
1605 struct p9_req_t *req;
1606 struct p9_client *clnt;
1607
1608 err = 0;
1609 clnt = fid->clnt;
1610
1611 P9_DPRINTK(P9_DEBUG_9P, ">>> TRENAME fid %d newdirfid %d name %s\n",
1612 fid->fid, newdirfid->fid, name);
1613
1614 req = p9_client_rpc(clnt, P9_TRENAME, "dds", fid->fid,
1615 newdirfid->fid, name);
1616 if (IS_ERR(req)) {
1617 err = PTR_ERR(req);
1618 goto error;
1619 }
1620
1621 P9_DPRINTK(P9_DEBUG_9P, "<<< RRENAME fid %d\n", fid->fid);
1622
1623 p9_free_req(clnt, req);
1624error:
1625 return err;
1626}
1627EXPORT_SYMBOL(p9_client_rename);
1628
1629/*
1630 * An xattrwalk without @attr_name gives the fid for the lisxattr namespace
1631 */
1632struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid,
1633 const char *attr_name, u64 *attr_size)
1634{
1635 int err;
1636 struct p9_req_t *req;
1637 struct p9_client *clnt;
1638 struct p9_fid *attr_fid;
1639
1640 err = 0;
1641 clnt = file_fid->clnt;
1642 attr_fid = p9_fid_create(clnt);
1643 if (IS_ERR(attr_fid)) {
1644 err = PTR_ERR(attr_fid);
1645 attr_fid = NULL;
1646 goto error;
1647 }
1648 P9_DPRINTK(P9_DEBUG_9P,
1649 ">>> TXATTRWALK file_fid %d, attr_fid %d name %s\n",
1650 file_fid->fid, attr_fid->fid, attr_name);
1651
1652 req = p9_client_rpc(clnt, P9_TXATTRWALK, "dds",
1653 file_fid->fid, attr_fid->fid, attr_name);
1654 if (IS_ERR(req)) {
1655 err = PTR_ERR(req);
1656 goto error;
1657 }
1658 err = p9pdu_readf(req->rc, clnt->proto_version, "q", attr_size);
1659 if (err) {
1660 p9pdu_dump(1, req->rc);
1661 p9_free_req(clnt, req);
1662 goto clunk_fid;
1663 }
1664 p9_free_req(clnt, req);
1665 P9_DPRINTK(P9_DEBUG_9P, "<<< RXATTRWALK fid %d size %llu\n",
1666 attr_fid->fid, *attr_size);
1667 return attr_fid;
1668clunk_fid:
1669 p9_client_clunk(attr_fid);
1670 attr_fid = NULL;
1671error:
1672 if (attr_fid && (attr_fid != file_fid))
1673 p9_fid_destroy(attr_fid);
1674
1675 return ERR_PTR(err);
1676}
1677EXPORT_SYMBOL_GPL(p9_client_xattrwalk);
1678
1679int p9_client_xattrcreate(struct p9_fid *fid, const char *name,
1680 u64 attr_size, int flags)
1681{
1682 int err;
1683 struct p9_req_t *req;
1684 struct p9_client *clnt;
1685
1686 P9_DPRINTK(P9_DEBUG_9P,
1687 ">>> TXATTRCREATE fid %d name %s size %lld flag %d\n",
1688 fid->fid, name, (long long)attr_size, flags);
1689 err = 0;
1690 clnt = fid->clnt;
1691 req = p9_client_rpc(clnt, P9_TXATTRCREATE, "dsqd",
1692 fid->fid, name, attr_size, flags);
1693 if (IS_ERR(req)) {
1694 err = PTR_ERR(req);
1695 goto error;
1696 }
1697 P9_DPRINTK(P9_DEBUG_9P, "<<< RXATTRCREATE fid %d\n", fid->fid);
1698 p9_free_req(clnt, req);
1699error:
1700 return err;
1701}
1702EXPORT_SYMBOL_GPL(p9_client_xattrcreate);
1703
1704int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
1705{
1706 int err, rsize, total;
1707 struct p9_client *clnt;
1708 struct p9_req_t *req;
1709 char *dataptr;
1710
1711 P9_DPRINTK(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
1712 fid->fid, (long long unsigned) offset, count);
1713
1714 err = 0;
1715 clnt = fid->clnt;
1716 total = 0;
1717
1718 rsize = fid->iounit;
1719 if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ)
1720 rsize = clnt->msize - P9_READDIRHDRSZ;
1721
1722 if (count < rsize)
1723 rsize = count;
1724
1725 req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, offset, rsize);
1726 if (IS_ERR(req)) {
1727 err = PTR_ERR(req);
1728 goto error;
1729 }
1730
1731 err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
1732 if (err) {
1733 p9pdu_dump(1, req->rc);
1734 goto free_and_error;
1735 }
1736
1737 P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count);
1738
1739 if (data)
1740 memmove(data, dataptr, count);
1741
1742 p9_free_req(clnt, req);
1743 return count;
1744
1745free_and_error:
1746 p9_free_req(clnt, req);
1747error:
1748 return err;
1749}
1750EXPORT_SYMBOL(p9_client_readdir);
1751
1752int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode,
1753 dev_t rdev, gid_t gid, struct p9_qid *qid)
1754{
1755 int err;
1756 struct p9_client *clnt;
1757 struct p9_req_t *req;
1758
1759 err = 0;
1760 clnt = fid->clnt;
1761 P9_DPRINTK(P9_DEBUG_9P, ">>> TMKNOD fid %d name %s mode %d major %d "
1762 "minor %d\n", fid->fid, name, mode, MAJOR(rdev), MINOR(rdev));
1763 req = p9_client_rpc(clnt, P9_TMKNOD, "dsdddd", fid->fid, name, mode,
1764 MAJOR(rdev), MINOR(rdev), gid);
1765 if (IS_ERR(req))
1766 return PTR_ERR(req);
1767
1768 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
1769 if (err) {
1770 p9pdu_dump(1, req->rc);
1771 goto error;
1772 }
1773 P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type,
1774 (unsigned long long)qid->path, qid->version);
1775
1776error:
1777 p9_free_req(clnt, req);
1778 return err;
1779
1780}
1781EXPORT_SYMBOL(p9_client_mknod_dotl);
1782
1783int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
1784 gid_t gid, struct p9_qid *qid)
1785{
1786 int err;
1787 struct p9_client *clnt;
1788 struct p9_req_t *req;
1789
1790 err = 0;
1791 clnt = fid->clnt;
1792 P9_DPRINTK(P9_DEBUG_9P, ">>> TMKDIR fid %d name %s mode %d gid %d\n",
1793 fid->fid, name, mode, gid);
1794 req = p9_client_rpc(clnt, P9_TMKDIR, "dsdd", fid->fid, name, mode,
1795 gid);
1796 if (IS_ERR(req))
1797 return PTR_ERR(req);
1798
1799 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
1800 if (err) {
1801 p9pdu_dump(1, req->rc);
1802 goto error;
1803 }
1804 P9_DPRINTK(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type,
1805 (unsigned long long)qid->path, qid->version);
1806
1807error:
1808 p9_free_req(clnt, req);
1809 return err;
1810
1811}
1812EXPORT_SYMBOL(p9_client_mkdir_dotl);
diff --git a/net/9p/protocol.c b/net/9p/protocol.c
index fc70147c771e..3acd3afb20c8 100644
--- a/net/9p/protocol.c
+++ b/net/9p/protocol.c
@@ -28,6 +28,7 @@
28#include <linux/module.h> 28#include <linux/module.h>
29#include <linux/errno.h> 29#include <linux/errno.h>
30#include <linux/uaccess.h> 30#include <linux/uaccess.h>
31#include <linux/slab.h>
31#include <linux/sched.h> 32#include <linux/sched.h>
32#include <linux/types.h> 33#include <linux/types.h>
33#include <net/9p/9p.h> 34#include <net/9p/9p.h>
@@ -52,7 +53,7 @@
52#endif 53#endif
53 54
54static int 55static int
55p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...); 56p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
56 57
57#ifdef CONFIG_NET_9P_DEBUG 58#ifdef CONFIG_NET_9P_DEBUG
58void 59void
@@ -140,11 +141,13 @@ pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
140 D - data blob (int32_t size followed by void *, results are not freed) 141 D - data blob (int32_t size followed by void *, results are not freed)
141 T - array of strings (int16_t count, followed by strings) 142 T - array of strings (int16_t count, followed by strings)
142 R - array of qids (int16_t count, followed by qids) 143 R - array of qids (int16_t count, followed by qids)
144 A - stat for 9p2000.L (p9_stat_dotl)
143 ? - if optional = 1, continue parsing 145 ? - if optional = 1, continue parsing
144*/ 146*/
145 147
146static int 148static int
147p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) 149p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
150 va_list ap)
148{ 151{
149 const char *ptr; 152 const char *ptr;
150 int errcode = 0; 153 int errcode = 0;
@@ -194,7 +197,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
194 int16_t len; 197 int16_t len;
195 int size; 198 int size;
196 199
197 errcode = p9pdu_readf(pdu, optional, "w", &len); 200 errcode = p9pdu_readf(pdu, proto_version,
201 "w", &len);
198 if (errcode) 202 if (errcode)
199 break; 203 break;
200 204
@@ -217,7 +221,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
217 struct p9_qid *qid = 221 struct p9_qid *qid =
218 va_arg(ap, struct p9_qid *); 222 va_arg(ap, struct p9_qid *);
219 223
220 errcode = p9pdu_readf(pdu, optional, "bdq", 224 errcode = p9pdu_readf(pdu, proto_version, "bdq",
221 &qid->type, &qid->version, 225 &qid->type, &qid->version,
222 &qid->path); 226 &qid->path);
223 } 227 }
@@ -230,7 +234,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
230 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = 234 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
231 -1; 235 -1;
232 errcode = 236 errcode =
233 p9pdu_readf(pdu, optional, 237 p9pdu_readf(pdu, proto_version,
234 "wwdQdddqssss?sddd", 238 "wwdQdddqssss?sddd",
235 &stbuf->size, &stbuf->type, 239 &stbuf->size, &stbuf->type,
236 &stbuf->dev, &stbuf->qid, 240 &stbuf->dev, &stbuf->qid,
@@ -250,7 +254,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
250 void **data = va_arg(ap, void **); 254 void **data = va_arg(ap, void **);
251 255
252 errcode = 256 errcode =
253 p9pdu_readf(pdu, optional, "d", count); 257 p9pdu_readf(pdu, proto_version, "d", count);
254 if (!errcode) { 258 if (!errcode) {
255 *count = 259 *count =
256 MIN(*count, 260 MIN(*count,
@@ -263,8 +267,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
263 int16_t *nwname = va_arg(ap, int16_t *); 267 int16_t *nwname = va_arg(ap, int16_t *);
264 char ***wnames = va_arg(ap, char ***); 268 char ***wnames = va_arg(ap, char ***);
265 269
266 errcode = 270 errcode = p9pdu_readf(pdu, proto_version,
267 p9pdu_readf(pdu, optional, "w", nwname); 271 "w", nwname);
268 if (!errcode) { 272 if (!errcode) {
269 *wnames = 273 *wnames =
270 kmalloc(sizeof(char *) * *nwname, 274 kmalloc(sizeof(char *) * *nwname,
@@ -278,7 +282,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
278 282
279 for (i = 0; i < *nwname; i++) { 283 for (i = 0; i < *nwname; i++) {
280 errcode = 284 errcode =
281 p9pdu_readf(pdu, optional, 285 p9pdu_readf(pdu,
286 proto_version,
282 "s", 287 "s",
283 &(*wnames)[i]); 288 &(*wnames)[i]);
284 if (errcode) 289 if (errcode)
@@ -306,7 +311,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
306 *wqids = NULL; 311 *wqids = NULL;
307 312
308 errcode = 313 errcode =
309 p9pdu_readf(pdu, optional, "w", nwqid); 314 p9pdu_readf(pdu, proto_version, "w", nwqid);
310 if (!errcode) { 315 if (!errcode) {
311 *wqids = 316 *wqids =
312 kmalloc(*nwqid * 317 kmalloc(*nwqid *
@@ -321,7 +326,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
321 326
322 for (i = 0; i < *nwqid; i++) { 327 for (i = 0; i < *nwqid; i++) {
323 errcode = 328 errcode =
324 p9pdu_readf(pdu, optional, 329 p9pdu_readf(pdu,
330 proto_version,
325 "Q", 331 "Q",
326 &(*wqids)[i]); 332 &(*wqids)[i]);
327 if (errcode) 333 if (errcode)
@@ -335,8 +341,36 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
335 } 341 }
336 } 342 }
337 break; 343 break;
344 case 'A': {
345 struct p9_stat_dotl *stbuf =
346 va_arg(ap, struct p9_stat_dotl *);
347
348 memset(stbuf, 0, sizeof(struct p9_stat_dotl));
349 errcode =
350 p9pdu_readf(pdu, proto_version,
351 "qQdddqqqqqqqqqqqqqqq",
352 &stbuf->st_result_mask,
353 &stbuf->qid,
354 &stbuf->st_mode,
355 &stbuf->st_uid, &stbuf->st_gid,
356 &stbuf->st_nlink,
357 &stbuf->st_rdev, &stbuf->st_size,
358 &stbuf->st_blksize, &stbuf->st_blocks,
359 &stbuf->st_atime_sec,
360 &stbuf->st_atime_nsec,
361 &stbuf->st_mtime_sec,
362 &stbuf->st_mtime_nsec,
363 &stbuf->st_ctime_sec,
364 &stbuf->st_ctime_nsec,
365 &stbuf->st_btime_sec,
366 &stbuf->st_btime_nsec,
367 &stbuf->st_gen,
368 &stbuf->st_data_version);
369 }
370 break;
338 case '?': 371 case '?':
339 if (!optional) 372 if ((proto_version != p9_proto_2000u) &&
373 (proto_version != p9_proto_2000L))
340 return 0; 374 return 0;
341 break; 375 break;
342 default: 376 default:
@@ -352,7 +386,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
352} 386}
353 387
354int 388int
355p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) 389p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
390 va_list ap)
356{ 391{
357 const char *ptr; 392 const char *ptr;
358 int errcode = 0; 393 int errcode = 0;
@@ -387,9 +422,10 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
387 const char *sptr = va_arg(ap, const char *); 422 const char *sptr = va_arg(ap, const char *);
388 int16_t len = 0; 423 int16_t len = 0;
389 if (sptr) 424 if (sptr)
390 len = MIN(strlen(sptr), USHORT_MAX); 425 len = MIN(strlen(sptr), USHRT_MAX);
391 426
392 errcode = p9pdu_writef(pdu, optional, "w", len); 427 errcode = p9pdu_writef(pdu, proto_version,
428 "w", len);
393 if (!errcode && pdu_write(pdu, sptr, len)) 429 if (!errcode && pdu_write(pdu, sptr, len))
394 errcode = -EFAULT; 430 errcode = -EFAULT;
395 } 431 }
@@ -398,7 +434,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
398 const struct p9_qid *qid = 434 const struct p9_qid *qid =
399 va_arg(ap, const struct p9_qid *); 435 va_arg(ap, const struct p9_qid *);
400 errcode = 436 errcode =
401 p9pdu_writef(pdu, optional, "bdq", 437 p9pdu_writef(pdu, proto_version, "bdq",
402 qid->type, qid->version, 438 qid->type, qid->version,
403 qid->path); 439 qid->path);
404 } break; 440 } break;
@@ -406,7 +442,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
406 const struct p9_wstat *stbuf = 442 const struct p9_wstat *stbuf =
407 va_arg(ap, const struct p9_wstat *); 443 va_arg(ap, const struct p9_wstat *);
408 errcode = 444 errcode =
409 p9pdu_writef(pdu, optional, 445 p9pdu_writef(pdu, proto_version,
410 "wwdQdddqssss?sddd", 446 "wwdQdddqssss?sddd",
411 stbuf->size, stbuf->type, 447 stbuf->size, stbuf->type,
412 stbuf->dev, &stbuf->qid, 448 stbuf->dev, &stbuf->qid,
@@ -421,8 +457,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
421 int32_t count = va_arg(ap, int32_t); 457 int32_t count = va_arg(ap, int32_t);
422 const void *data = va_arg(ap, const void *); 458 const void *data = va_arg(ap, const void *);
423 459
424 errcode = 460 errcode = p9pdu_writef(pdu, proto_version, "d",
425 p9pdu_writef(pdu, optional, "d", count); 461 count);
426 if (!errcode && pdu_write(pdu, data, count)) 462 if (!errcode && pdu_write(pdu, data, count))
427 errcode = -EFAULT; 463 errcode = -EFAULT;
428 } 464 }
@@ -431,8 +467,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
431 int32_t count = va_arg(ap, int32_t); 467 int32_t count = va_arg(ap, int32_t);
432 const char __user *udata = 468 const char __user *udata =
433 va_arg(ap, const void __user *); 469 va_arg(ap, const void __user *);
434 errcode = 470 errcode = p9pdu_writef(pdu, proto_version, "d",
435 p9pdu_writef(pdu, optional, "d", count); 471 count);
436 if (!errcode && pdu_write_u(pdu, udata, count)) 472 if (!errcode && pdu_write_u(pdu, udata, count))
437 errcode = -EFAULT; 473 errcode = -EFAULT;
438 } 474 }
@@ -441,14 +477,15 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
441 int16_t nwname = va_arg(ap, int); 477 int16_t nwname = va_arg(ap, int);
442 const char **wnames = va_arg(ap, const char **); 478 const char **wnames = va_arg(ap, const char **);
443 479
444 errcode = 480 errcode = p9pdu_writef(pdu, proto_version, "w",
445 p9pdu_writef(pdu, optional, "w", nwname); 481 nwname);
446 if (!errcode) { 482 if (!errcode) {
447 int i; 483 int i;
448 484
449 for (i = 0; i < nwname; i++) { 485 for (i = 0; i < nwname; i++) {
450 errcode = 486 errcode =
451 p9pdu_writef(pdu, optional, 487 p9pdu_writef(pdu,
488 proto_version,
452 "s", 489 "s",
453 wnames[i]); 490 wnames[i]);
454 if (errcode) 491 if (errcode)
@@ -462,14 +499,15 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
462 struct p9_qid *wqids = 499 struct p9_qid *wqids =
463 va_arg(ap, struct p9_qid *); 500 va_arg(ap, struct p9_qid *);
464 501
465 errcode = 502 errcode = p9pdu_writef(pdu, proto_version, "w",
466 p9pdu_writef(pdu, optional, "w", nwqid); 503 nwqid);
467 if (!errcode) { 504 if (!errcode) {
468 int i; 505 int i;
469 506
470 for (i = 0; i < nwqid; i++) { 507 for (i = 0; i < nwqid; i++) {
471 errcode = 508 errcode =
472 p9pdu_writef(pdu, optional, 509 p9pdu_writef(pdu,
510 proto_version,
473 "Q", 511 "Q",
474 &wqids[i]); 512 &wqids[i]);
475 if (errcode) 513 if (errcode)
@@ -478,8 +516,26 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
478 } 516 }
479 } 517 }
480 break; 518 break;
519 case 'I':{
520 struct p9_iattr_dotl *p9attr = va_arg(ap,
521 struct p9_iattr_dotl *);
522
523 errcode = p9pdu_writef(pdu, proto_version,
524 "ddddqqqqq",
525 p9attr->valid,
526 p9attr->mode,
527 p9attr->uid,
528 p9attr->gid,
529 p9attr->size,
530 p9attr->atime_sec,
531 p9attr->atime_nsec,
532 p9attr->mtime_sec,
533 p9attr->mtime_nsec);
534 }
535 break;
481 case '?': 536 case '?':
482 if (!optional) 537 if ((proto_version != p9_proto_2000u) &&
538 (proto_version != p9_proto_2000L))
483 return 0; 539 return 0;
484 break; 540 break;
485 default: 541 default:
@@ -494,32 +550,32 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
494 return errcode; 550 return errcode;
495} 551}
496 552
497int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...) 553int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
498{ 554{
499 va_list ap; 555 va_list ap;
500 int ret; 556 int ret;
501 557
502 va_start(ap, fmt); 558 va_start(ap, fmt);
503 ret = p9pdu_vreadf(pdu, optional, fmt, ap); 559 ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
504 va_end(ap); 560 va_end(ap);
505 561
506 return ret; 562 return ret;
507} 563}
508 564
509static int 565static int
510p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...) 566p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
511{ 567{
512 va_list ap; 568 va_list ap;
513 int ret; 569 int ret;
514 570
515 va_start(ap, fmt); 571 va_start(ap, fmt);
516 ret = p9pdu_vwritef(pdu, optional, fmt, ap); 572 ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
517 va_end(ap); 573 va_end(ap);
518 574
519 return ret; 575 return ret;
520} 576}
521 577
522int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu) 578int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
523{ 579{
524 struct p9_fcall fake_pdu; 580 struct p9_fcall fake_pdu;
525 int ret; 581 int ret;
@@ -529,7 +585,7 @@ int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu)
529 fake_pdu.sdata = buf; 585 fake_pdu.sdata = buf;
530 fake_pdu.offset = 0; 586 fake_pdu.offset = 0;
531 587
532 ret = p9pdu_readf(&fake_pdu, dotu, "S", st); 588 ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
533 if (ret) { 589 if (ret) {
534 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); 590 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
535 p9pdu_dump(1, &fake_pdu); 591 p9pdu_dump(1, &fake_pdu);
@@ -569,3 +625,30 @@ void p9pdu_reset(struct p9_fcall *pdu)
569 pdu->offset = 0; 625 pdu->offset = 0;
570 pdu->size = 0; 626 pdu->size = 0;
571} 627}
628
629int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
630 int proto_version)
631{
632 struct p9_fcall fake_pdu;
633 int ret;
634 char *nameptr;
635
636 fake_pdu.size = len;
637 fake_pdu.capacity = len;
638 fake_pdu.sdata = buf;
639 fake_pdu.offset = 0;
640
641 ret = p9pdu_readf(&fake_pdu, proto_version, "Qqbs", &dirent->qid,
642 &dirent->d_off, &dirent->d_type, &nameptr);
643 if (ret) {
644 P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
645 p9pdu_dump(1, &fake_pdu);
646 goto out;
647 }
648
649 strcpy(dirent->d_name, nameptr);
650
651out:
652 return fake_pdu.offset;
653}
654EXPORT_SYMBOL(p9dirent_read);
diff --git a/net/9p/protocol.h b/net/9p/protocol.h
index ccde462e7ac5..2431c0f38d56 100644
--- a/net/9p/protocol.h
+++ b/net/9p/protocol.h
@@ -25,9 +25,9 @@
25 * 25 *
26 */ 26 */
27 27
28int 28int p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
29p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap); 29 va_list ap);
30int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...); 30int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
31int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type); 31int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type);
32int p9pdu_finalize(struct p9_fcall *pdu); 32int p9pdu_finalize(struct p9_fcall *pdu);
33void p9pdu_dump(int, struct p9_fcall *); 33void p9pdu_dump(int, struct p9_fcall *);
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index be1cb909d8c0..c85109d809ca 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -38,6 +38,7 @@
38#include <linux/idr.h> 38#include <linux/idr.h>
39#include <linux/file.h> 39#include <linux/file.h>
40#include <linux/parser.h> 40#include <linux/parser.h>
41#include <linux/slab.h>
41#include <net/9p/9p.h> 42#include <net/9p/9p.h>
42#include <net/9p/client.h> 43#include <net/9p/client.h>
43#include <net/9p/transport.h> 44#include <net/9p/transport.h>
@@ -714,7 +715,7 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)
714 char *p; 715 char *p;
715 substring_t args[MAX_OPT_ARGS]; 716 substring_t args[MAX_OPT_ARGS];
716 int option; 717 int option;
717 char *options; 718 char *options, *tmp_options;
718 int ret; 719 int ret;
719 720
720 opts->port = P9_PORT; 721 opts->port = P9_PORT;
@@ -724,12 +725,13 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)
724 if (!params) 725 if (!params)
725 return 0; 726 return 0;
726 727
727 options = kstrdup(params, GFP_KERNEL); 728 tmp_options = kstrdup(params, GFP_KERNEL);
728 if (!options) { 729 if (!tmp_options) {
729 P9_DPRINTK(P9_DEBUG_ERROR, 730 P9_DPRINTK(P9_DEBUG_ERROR,
730 "failed to allocate copy of option string\n"); 731 "failed to allocate copy of option string\n");
731 return -ENOMEM; 732 return -ENOMEM;
732 } 733 }
734 options = tmp_options;
733 735
734 while ((p = strsep(&options, ",")) != NULL) { 736 while ((p = strsep(&options, ",")) != NULL) {
735 int token; 737 int token;
@@ -760,7 +762,8 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)
760 continue; 762 continue;
761 } 763 }
762 } 764 }
763 kfree(options); 765
766 kfree(tmp_options);
764 return 0; 767 return 0;
765} 768}
766 769
@@ -945,7 +948,7 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
945 948
946 csocket = NULL; 949 csocket = NULL;
947 950
948 if (strlen(addr) > UNIX_PATH_MAX) { 951 if (strlen(addr) >= UNIX_PATH_MAX) {
949 P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n", 952 P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
950 addr); 953 addr);
951 return -ENAMETOOLONG; 954 return -ENAMETOOLONG;
diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c
index 65cb29db03f8..17c5ba7551a5 100644
--- a/net/9p/trans_rdma.c
+++ b/net/9p/trans_rdma.c
@@ -40,6 +40,7 @@
40#include <linux/file.h> 40#include <linux/file.h>
41#include <linux/parser.h> 41#include <linux/parser.h>
42#include <linux/semaphore.h> 42#include <linux/semaphore.h>
43#include <linux/slab.h>
43#include <net/9p/9p.h> 44#include <net/9p/9p.h>
44#include <net/9p/client.h> 45#include <net/9p/client.h>
45#include <net/9p/transport.h> 46#include <net/9p/transport.h>
@@ -166,7 +167,7 @@ static int parse_opts(char *params, struct p9_rdma_opts *opts)
166 char *p; 167 char *p;
167 substring_t args[MAX_OPT_ARGS]; 168 substring_t args[MAX_OPT_ARGS];
168 int option; 169 int option;
169 char *options; 170 char *options, *tmp_options;
170 int ret; 171 int ret;
171 172
172 opts->port = P9_PORT; 173 opts->port = P9_PORT;
@@ -177,12 +178,13 @@ static int parse_opts(char *params, struct p9_rdma_opts *opts)
177 if (!params) 178 if (!params)
178 return 0; 179 return 0;
179 180
180 options = kstrdup(params, GFP_KERNEL); 181 tmp_options = kstrdup(params, GFP_KERNEL);
181 if (!options) { 182 if (!tmp_options) {
182 P9_DPRINTK(P9_DEBUG_ERROR, 183 P9_DPRINTK(P9_DEBUG_ERROR,
183 "failed to allocate copy of option string\n"); 184 "failed to allocate copy of option string\n");
184 return -ENOMEM; 185 return -ENOMEM;
185 } 186 }
187 options = tmp_options;
186 188
187 while ((p = strsep(&options, ",")) != NULL) { 189 while ((p = strsep(&options, ",")) != NULL) {
188 int token; 190 int token;
@@ -216,7 +218,7 @@ static int parse_opts(char *params, struct p9_rdma_opts *opts)
216 } 218 }
217 /* RQ must be at least as large as the SQ */ 219 /* RQ must be at least as large as the SQ */
218 opts->rq_depth = max(opts->rq_depth, opts->sq_depth); 220 opts->rq_depth = max(opts->rq_depth, opts->sq_depth);
219 kfree(options); 221 kfree(tmp_options);
220 return 0; 222 return 0;
221} 223}
222 224
@@ -306,7 +308,6 @@ handle_recv(struct p9_client *client, struct p9_trans_rdma *rdma,
306 req, err, status); 308 req, err, status);
307 rdma->state = P9_RDMA_FLUSHING; 309 rdma->state = P9_RDMA_FLUSHING;
308 client->status = Disconnected; 310 client->status = Disconnected;
309 return;
310} 311}
311 312
312static void 313static void
@@ -425,8 +426,10 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
425 426
426 /* Allocate an fcall for the reply */ 427 /* Allocate an fcall for the reply */
427 rpl_context = kmalloc(sizeof *rpl_context, GFP_KERNEL); 428 rpl_context = kmalloc(sizeof *rpl_context, GFP_KERNEL);
428 if (!rpl_context) 429 if (!rpl_context) {
430 err = -ENOMEM;
429 goto err_close; 431 goto err_close;
432 }
430 433
431 /* 434 /*
432 * If the request has a buffer, steal it, otherwise 435 * If the request has a buffer, steal it, otherwise
@@ -444,8 +447,8 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
444 } 447 }
445 rpl_context->rc = req->rc; 448 rpl_context->rc = req->rc;
446 if (!rpl_context->rc) { 449 if (!rpl_context->rc) {
447 kfree(rpl_context); 450 err = -ENOMEM;
448 goto err_close; 451 goto err_free2;
449 } 452 }
450 453
451 /* 454 /*
@@ -457,11 +460,8 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
457 */ 460 */
458 if (atomic_inc_return(&rdma->rq_count) <= rdma->rq_depth) { 461 if (atomic_inc_return(&rdma->rq_count) <= rdma->rq_depth) {
459 err = post_recv(client, rpl_context); 462 err = post_recv(client, rpl_context);
460 if (err) { 463 if (err)
461 kfree(rpl_context->rc); 464 goto err_free1;
462 kfree(rpl_context);
463 goto err_close;
464 }
465 } else 465 } else
466 atomic_dec(&rdma->rq_count); 466 atomic_dec(&rdma->rq_count);
467 467
@@ -470,8 +470,10 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
470 470
471 /* Post the request */ 471 /* Post the request */
472 c = kmalloc(sizeof *c, GFP_KERNEL); 472 c = kmalloc(sizeof *c, GFP_KERNEL);
473 if (!c) 473 if (!c) {
474 goto err_close; 474 err = -ENOMEM;
475 goto err_free1;
476 }
475 c->req = req; 477 c->req = req;
476 478
477 c->busa = ib_dma_map_single(rdma->cm_id->device, 479 c->busa = ib_dma_map_single(rdma->cm_id->device,
@@ -498,9 +500,15 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
498 return ib_post_send(rdma->qp, &wr, &bad_wr); 500 return ib_post_send(rdma->qp, &wr, &bad_wr);
499 501
500 error: 502 error:
503 kfree(c);
504 kfree(rpl_context->rc);
505 kfree(rpl_context);
501 P9_DPRINTK(P9_DEBUG_ERROR, "EIO\n"); 506 P9_DPRINTK(P9_DEBUG_ERROR, "EIO\n");
502 return -EIO; 507 return -EIO;
503 508 err_free1:
509 kfree(rpl_context->rc);
510 err_free2:
511 kfree(rpl_context);
504 err_close: 512 err_close:
505 spin_lock_irqsave(&rdma->req_lock, flags); 513 spin_lock_irqsave(&rdma->req_lock, flags);
506 if (rdma->state < P9_RDMA_CLOSING) { 514 if (rdma->state < P9_RDMA_CLOSING) {
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index ea1e3daabefe..b88515936e4b 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -37,6 +37,7 @@
37#include <linux/inet.h> 37#include <linux/inet.h>
38#include <linux/idr.h> 38#include <linux/idr.h>
39#include <linux/file.h> 39#include <linux/file.h>
40#include <linux/slab.h>
40#include <net/9p/9p.h> 41#include <net/9p/9p.h>
41#include <linux/parser.h> 42#include <linux/parser.h>
42#include <net/9p/client.h> 43#include <net/9p/client.h>
@@ -49,8 +50,6 @@
49 50
50/* a single mutex to manage channel initialization and attachment */ 51/* a single mutex to manage channel initialization and attachment */
51static DEFINE_MUTEX(virtio_9p_lock); 52static DEFINE_MUTEX(virtio_9p_lock);
52/* global which tracks highest initialized channel */
53static int chan_index;
54 53
55/** 54/**
56 * struct virtio_chan - per-instance transport information 55 * struct virtio_chan - per-instance transport information
@@ -68,8 +67,7 @@ static int chan_index;
68 * 67 *
69 */ 68 */
70 69
71static struct virtio_chan { 70struct virtio_chan {
72 bool initialized;
73 bool inuse; 71 bool inuse;
74 72
75 spinlock_t lock; 73 spinlock_t lock;
@@ -80,7 +78,17 @@ static struct virtio_chan {
80 78
81 /* Scatterlist: can be too big for stack. */ 79 /* Scatterlist: can be too big for stack. */
82 struct scatterlist sg[VIRTQUEUE_NUM]; 80 struct scatterlist sg[VIRTQUEUE_NUM];
83} channels[MAX_9P_CHAN]; 81
82 int tag_len;
83 /*
84 * tag name to identify a mount Non-null terminated
85 */
86 char *tag;
87
88 struct list_head chan_list;
89};
90
91static struct list_head virtio_chan_list;
84 92
85/* How many bytes left in this page. */ 93/* How many bytes left in this page. */
86static unsigned int rest_of_page(void *data) 94static unsigned int rest_of_page(void *data)
@@ -102,7 +110,8 @@ static void p9_virtio_close(struct p9_client *client)
102 struct virtio_chan *chan = client->trans; 110 struct virtio_chan *chan = client->trans;
103 111
104 mutex_lock(&virtio_9p_lock); 112 mutex_lock(&virtio_9p_lock);
105 chan->inuse = false; 113 if (chan)
114 chan->inuse = false;
106 mutex_unlock(&virtio_9p_lock); 115 mutex_unlock(&virtio_9p_lock);
107} 116}
108 117
@@ -128,7 +137,7 @@ static void req_done(struct virtqueue *vq)
128 137
129 P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n"); 138 P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n");
130 139
131 while ((rc = chan->vq->vq_ops->get_buf(chan->vq, &len)) != NULL) { 140 while ((rc = virtqueue_get_buf(chan->vq, &len)) != NULL) {
132 P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc); 141 P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
133 P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag); 142 P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
134 req = p9_tag_lookup(chan->client, rc->tag); 143 req = p9_tag_lookup(chan->client, rc->tag);
@@ -200,42 +209,50 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
200 209
201 req->status = REQ_STATUS_SENT; 210 req->status = REQ_STATUS_SENT;
202 211
203 if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, req->tc) < 0) { 212 if (virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc) < 0) {
204 P9_DPRINTK(P9_DEBUG_TRANS, 213 P9_DPRINTK(P9_DEBUG_TRANS,
205 "9p debug: virtio rpc add_buf returned failure"); 214 "9p debug: virtio rpc add_buf returned failure");
206 return -EIO; 215 return -EIO;
207 } 216 }
208 217
209 chan->vq->vq_ops->kick(chan->vq); 218 virtqueue_kick(chan->vq);
210 219
211 P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n"); 220 P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n");
212 return 0; 221 return 0;
213} 222}
214 223
224static ssize_t p9_mount_tag_show(struct device *dev,
225 struct device_attribute *attr, char *buf)
226{
227 struct virtio_chan *chan;
228 struct virtio_device *vdev;
229
230 vdev = dev_to_virtio(dev);
231 chan = vdev->priv;
232
233 return snprintf(buf, chan->tag_len + 1, "%s", chan->tag);
234}
235
236static DEVICE_ATTR(mount_tag, 0444, p9_mount_tag_show, NULL);
237
215/** 238/**
216 * p9_virtio_probe - probe for existence of 9P virtio channels 239 * p9_virtio_probe - probe for existence of 9P virtio channels
217 * @vdev: virtio device to probe 240 * @vdev: virtio device to probe
218 * 241 *
219 * This probes for existing virtio channels. At present only 242 * This probes for existing virtio channels.
220 * a single channel is in use, so in the future more work may need
221 * to be done here.
222 * 243 *
223 */ 244 */
224 245
225static int p9_virtio_probe(struct virtio_device *vdev) 246static int p9_virtio_probe(struct virtio_device *vdev)
226{ 247{
248 __u16 tag_len;
249 char *tag;
227 int err; 250 int err;
228 struct virtio_chan *chan; 251 struct virtio_chan *chan;
229 int index;
230 252
231 mutex_lock(&virtio_9p_lock); 253 chan = kmalloc(sizeof(struct virtio_chan), GFP_KERNEL);
232 index = chan_index++; 254 if (!chan) {
233 chan = &channels[index]; 255 printk(KERN_ERR "9p: Failed to allocate virtio 9P channel\n");
234 mutex_unlock(&virtio_9p_lock);
235
236 if (chan_index > MAX_9P_CHAN) {
237 printk(KERN_ERR "9p: virtio: Maximum channels exceeded\n");
238 BUG();
239 err = -ENOMEM; 256 err = -ENOMEM;
240 goto fail; 257 goto fail;
241 } 258 }
@@ -254,15 +271,37 @@ static int p9_virtio_probe(struct virtio_device *vdev)
254 sg_init_table(chan->sg, VIRTQUEUE_NUM); 271 sg_init_table(chan->sg, VIRTQUEUE_NUM);
255 272
256 chan->inuse = false; 273 chan->inuse = false;
257 chan->initialized = true; 274 if (virtio_has_feature(vdev, VIRTIO_9P_MOUNT_TAG)) {
275 vdev->config->get(vdev,
276 offsetof(struct virtio_9p_config, tag_len),
277 &tag_len, sizeof(tag_len));
278 } else {
279 err = -EINVAL;
280 goto out_free_vq;
281 }
282 tag = kmalloc(tag_len, GFP_KERNEL);
283 if (!tag) {
284 err = -ENOMEM;
285 goto out_free_vq;
286 }
287 vdev->config->get(vdev, offsetof(struct virtio_9p_config, tag),
288 tag, tag_len);
289 chan->tag = tag;
290 chan->tag_len = tag_len;
291 err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
292 if (err) {
293 kfree(tag);
294 goto out_free_vq;
295 }
296 mutex_lock(&virtio_9p_lock);
297 list_add_tail(&chan->chan_list, &virtio_chan_list);
298 mutex_unlock(&virtio_9p_lock);
258 return 0; 299 return 0;
259 300
260out_free_vq: 301out_free_vq:
261 vdev->config->del_vqs(vdev); 302 vdev->config->del_vqs(vdev);
303 kfree(chan);
262fail: 304fail:
263 mutex_lock(&virtio_9p_lock);
264 chan_index--;
265 mutex_unlock(&virtio_9p_lock);
266 return err; 305 return err;
267} 306}
268 307
@@ -279,38 +318,36 @@ fail:
279 * We use a simple reference count mechanism to ensure that only a single 318 * We use a simple reference count mechanism to ensure that only a single
280 * mount has a channel open at a time. 319 * mount has a channel open at a time.
281 * 320 *
282 * Bugs: doesn't allow identification of a specific channel
283 * to allocate, channels are allocated sequentially. This was
284 * a pragmatic decision to get things rolling, but ideally some
285 * way of identifying the channel to attach to would be nice
286 * if we are going to support multiple channels.
287 *
288 */ 321 */
289 322
290static int 323static int
291p9_virtio_create(struct p9_client *client, const char *devname, char *args) 324p9_virtio_create(struct p9_client *client, const char *devname, char *args)
292{ 325{
293 struct virtio_chan *chan = channels; 326 struct virtio_chan *chan;
294 int index = 0; 327 int ret = -ENOENT;
328 int found = 0;
295 329
296 mutex_lock(&virtio_9p_lock); 330 mutex_lock(&virtio_9p_lock);
297 while (index < MAX_9P_CHAN) { 331 list_for_each_entry(chan, &virtio_chan_list, chan_list) {
298 if (chan->initialized && !chan->inuse) { 332 if (!strncmp(devname, chan->tag, chan->tag_len) &&
299 chan->inuse = true; 333 strlen(devname) == chan->tag_len) {
300 break; 334 if (!chan->inuse) {
301 } else { 335 chan->inuse = true;
302 index++; 336 found = 1;
303 chan = &channels[index]; 337 break;
338 }
339 ret = -EBUSY;
304 } 340 }
305 } 341 }
306 mutex_unlock(&virtio_9p_lock); 342 mutex_unlock(&virtio_9p_lock);
307 343
308 if (index >= MAX_9P_CHAN) { 344 if (!found) {
309 printk(KERN_ERR "9p: no channels available\n"); 345 printk(KERN_ERR "9p: no channels available\n");
310 return -ENODEV; 346 return ret;
311 } 347 }
312 348
313 client->trans = (void *)chan; 349 client->trans = (void *)chan;
350 client->status = Connected;
314 chan->client = client; 351 chan->client = client;
315 352
316 return 0; 353 return 0;
@@ -327,11 +364,15 @@ static void p9_virtio_remove(struct virtio_device *vdev)
327 struct virtio_chan *chan = vdev->priv; 364 struct virtio_chan *chan = vdev->priv;
328 365
329 BUG_ON(chan->inuse); 366 BUG_ON(chan->inuse);
367 vdev->config->del_vqs(vdev);
368
369 mutex_lock(&virtio_9p_lock);
370 list_del(&chan->chan_list);
371 mutex_unlock(&virtio_9p_lock);
372 sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
373 kfree(chan->tag);
374 kfree(chan);
330 375
331 if (chan->initialized) {
332 vdev->config->del_vqs(vdev);
333 chan->initialized = false;
334 }
335} 376}
336 377
337static struct virtio_device_id id_table[] = { 378static struct virtio_device_id id_table[] = {
@@ -339,13 +380,19 @@ static struct virtio_device_id id_table[] = {
339 { 0 }, 380 { 0 },
340}; 381};
341 382
383static unsigned int features[] = {
384 VIRTIO_9P_MOUNT_TAG,
385};
386
342/* The standard "struct lguest_driver": */ 387/* The standard "struct lguest_driver": */
343static struct virtio_driver p9_virtio_drv = { 388static struct virtio_driver p9_virtio_drv = {
344 .driver.name = KBUILD_MODNAME, 389 .feature_table = features,
345 .driver.owner = THIS_MODULE, 390 .feature_table_size = ARRAY_SIZE(features),
346 .id_table = id_table, 391 .driver.name = KBUILD_MODNAME,
347 .probe = p9_virtio_probe, 392 .driver.owner = THIS_MODULE,
348 .remove = p9_virtio_remove, 393 .id_table = id_table,
394 .probe = p9_virtio_probe,
395 .remove = p9_virtio_remove,
349}; 396};
350 397
351static struct p9_trans_module p9_virtio_trans = { 398static struct p9_trans_module p9_virtio_trans = {
@@ -362,10 +409,7 @@ static struct p9_trans_module p9_virtio_trans = {
362/* The standard init function */ 409/* The standard init function */
363static int __init p9_virtio_init(void) 410static int __init p9_virtio_init(void)
364{ 411{
365 int count; 412 INIT_LIST_HEAD(&virtio_chan_list);
366
367 for (count = 0; count < MAX_9P_CHAN; count++)
368 channels[count].initialized = false;
369 413
370 v9fs_register_trans(&p9_virtio_trans); 414 v9fs_register_trans(&p9_virtio_trans);
371 return register_virtio_driver(&p9_virtio_drv); 415 return register_virtio_driver(&p9_virtio_drv);
diff --git a/net/9p/util.c b/net/9p/util.c
index dc4ec05ad93d..e048701a72d2 100644
--- a/net/9p/util.c
+++ b/net/9p/util.c
@@ -30,6 +30,7 @@
30#include <linux/sched.h> 30#include <linux/sched.h>
31#include <linux/parser.h> 31#include <linux/parser.h>
32#include <linux/idr.h> 32#include <linux/idr.h>
33#include <linux/slab.h>
33#include <net/9p/9p.h> 34#include <net/9p/9p.h>
34 35
35/** 36/**