aboutsummaryrefslogtreecommitdiffstats
path: root/net/9p/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/9p/client.c')
-rw-r--r--net/9p/client.c187
1 files changed, 140 insertions, 47 deletions
diff --git a/net/9p/client.c b/net/9p/client.c
index 8af95b2dddd6..0aa79faa9850 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
@@ -401,14 +452,15 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
401 int ecode; 452 int ecode;
402 char *ename; 453 char *ename;
403 454
404 err = p9pdu_readf(req->rc, c->dotu, "s?d", &ename, &ecode); 455 err = p9pdu_readf(req->rc, c->proto_version, "s?d",
456 &ename, &ecode);
405 if (err) { 457 if (err) {
406 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", 458 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
407 err); 459 err);
408 return err; 460 return err;
409 } 461 }
410 462
411 if (c->dotu) 463 if (p9_is_proto_dotu(c))
412 err = -ecode; 464 err = -ecode;
413 465
414 if (!err || !IS_ERR_VALUE(err)) 466 if (!err || !IS_ERR_VALUE(err))
@@ -483,7 +535,12 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
483 535
484 P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type); 536 P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type);
485 537
486 if (c->status != Connected) 538 /* we allow for any status other than disconnected */
539 if (c->status == Disconnected)
540 return ERR_PTR(-EIO);
541
542 /* if status is begin_disconnected we allow only clunk request */
543 if ((c->status == BeginDisconnect) && (type != P9_TCLUNK))
487 return ERR_PTR(-EIO); 544 return ERR_PTR(-EIO);
488 545
489 if (signal_pending(current)) { 546 if (signal_pending(current)) {
@@ -506,7 +563,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
506 /* marshall the data */ 563 /* marshall the data */
507 p9pdu_prepare(req->tc, tag, type); 564 p9pdu_prepare(req->tc, tag, type);
508 va_start(ap, fmt); 565 va_start(ap, fmt);
509 err = p9pdu_vwritef(req->tc, c->dotu, fmt, ap); 566 err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap);
510 va_end(ap); 567 va_end(ap);
511 p9pdu_finalize(req->tc); 568 p9pdu_finalize(req->tc);
512 569
@@ -618,14 +675,31 @@ int p9_client_version(struct p9_client *c)
618 char *version; 675 char *version;
619 int msize; 676 int msize;
620 677
621 P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n", 678 P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n",
622 c->msize, c->dotu); 679 c->msize, c->proto_version);
623 req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize, 680
624 c->dotu ? "9P2000.u" : "9P2000"); 681 switch (c->proto_version) {
682 case p9_proto_2000L:
683 req = p9_client_rpc(c, P9_TVERSION, "ds",
684 c->msize, "9P2000.L");
685 break;
686 case p9_proto_2000u:
687 req = p9_client_rpc(c, P9_TVERSION, "ds",
688 c->msize, "9P2000.u");
689 break;
690 case p9_proto_legacy:
691 req = p9_client_rpc(c, P9_TVERSION, "ds",
692 c->msize, "9P2000");
693 break;
694 default:
695 return -EINVAL;
696 break;
697 }
698
625 if (IS_ERR(req)) 699 if (IS_ERR(req))
626 return PTR_ERR(req); 700 return PTR_ERR(req);
627 701
628 err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version); 702 err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version);
629 if (err) { 703 if (err) {
630 P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); 704 P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
631 p9pdu_dump(1, req->rc); 705 p9pdu_dump(1, req->rc);
@@ -633,10 +707,12 @@ int p9_client_version(struct p9_client *c)
633 } 707 }
634 708
635 P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version); 709 P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
636 if (!memcmp(version, "9P2000.u", 8)) 710 if (!strncmp(version, "9P2000.L", 8))
637 c->dotu = 1; 711 c->proto_version = p9_proto_2000L;
638 else if (!memcmp(version, "9P2000", 6)) 712 else if (!strncmp(version, "9P2000.u", 8))
639 c->dotu = 0; 713 c->proto_version = p9_proto_2000u;
714 else if (!strncmp(version, "9P2000", 6))
715 c->proto_version = p9_proto_legacy;
640 else { 716 else {
641 err = -EREMOTEIO; 717 err = -EREMOTEIO;
642 goto error; 718 goto error;
@@ -667,18 +743,12 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
667 clnt->trans = NULL; 743 clnt->trans = NULL;
668 spin_lock_init(&clnt->lock); 744 spin_lock_init(&clnt->lock);
669 INIT_LIST_HEAD(&clnt->fidlist); 745 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 746
677 p9_tag_init(clnt); 747 p9_tag_init(clnt);
678 748
679 err = parse_opts(options, clnt); 749 err = parse_opts(options, clnt);
680 if (err < 0) 750 if (err < 0)
681 goto error; 751 goto free_client;
682 752
683 if (!clnt->trans_mod) 753 if (!clnt->trans_mod)
684 clnt->trans_mod = v9fs_get_default_trans(); 754 clnt->trans_mod = v9fs_get_default_trans();
@@ -687,27 +757,40 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
687 err = -EPROTONOSUPPORT; 757 err = -EPROTONOSUPPORT;
688 P9_DPRINTK(P9_DEBUG_ERROR, 758 P9_DPRINTK(P9_DEBUG_ERROR,
689 "No transport defined or default transport\n"); 759 "No transport defined or default transport\n");
690 goto error; 760 goto free_client;
761 }
762
763 clnt->fidpool = p9_idpool_create();
764 if (IS_ERR(clnt->fidpool)) {
765 err = PTR_ERR(clnt->fidpool);
766 clnt->fidpool = NULL;
767 goto put_trans;
691 } 768 }
692 769
693 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d dotu %d\n", 770 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n",
694 clnt, clnt->trans_mod, clnt->msize, clnt->dotu); 771 clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
695 772
696 err = clnt->trans_mod->create(clnt, dev_name, options); 773 err = clnt->trans_mod->create(clnt, dev_name, options);
697 if (err) 774 if (err)
698 goto error; 775 goto destroy_fidpool;
699 776
700 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) 777 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize)
701 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; 778 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ;
702 779
703 err = p9_client_version(clnt); 780 err = p9_client_version(clnt);
704 if (err) 781 if (err)
705 goto error; 782 goto close_trans;
706 783
707 return clnt; 784 return clnt;
708 785
709error: 786close_trans:
710 p9_client_destroy(clnt); 787 clnt->trans_mod->close(clnt);
788destroy_fidpool:
789 p9_idpool_destroy(clnt->fidpool);
790put_trans:
791 v9fs_put_trans(clnt->trans_mod);
792free_client:
793 kfree(clnt);
711 return ERR_PTR(err); 794 return ERR_PTR(err);
712} 795}
713EXPORT_SYMBOL(p9_client_create); 796EXPORT_SYMBOL(p9_client_create);
@@ -723,8 +806,10 @@ void p9_client_destroy(struct p9_client *clnt)
723 806
724 v9fs_put_trans(clnt->trans_mod); 807 v9fs_put_trans(clnt->trans_mod);
725 808
726 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) 809 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) {
810 printk(KERN_INFO "Found fid %d not clunked\n", fid->fid);
727 p9_fid_destroy(fid); 811 p9_fid_destroy(fid);
812 }
728 813
729 if (clnt->fidpool) 814 if (clnt->fidpool)
730 p9_idpool_destroy(clnt->fidpool); 815 p9_idpool_destroy(clnt->fidpool);
@@ -742,6 +827,13 @@ void p9_client_disconnect(struct p9_client *clnt)
742} 827}
743EXPORT_SYMBOL(p9_client_disconnect); 828EXPORT_SYMBOL(p9_client_disconnect);
744 829
830void p9_client_begin_disconnect(struct p9_client *clnt)
831{
832 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
833 clnt->status = BeginDisconnect;
834}
835EXPORT_SYMBOL(p9_client_begin_disconnect);
836
745struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, 837struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
746 char *uname, u32 n_uname, char *aname) 838 char *uname, u32 n_uname, char *aname)
747{ 839{
@@ -768,7 +860,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
768 goto error; 860 goto error;
769 } 861 }
770 862
771 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); 863 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
772 if (err) { 864 if (err) {
773 p9pdu_dump(1, req->rc); 865 p9pdu_dump(1, req->rc);
774 p9_free_req(clnt, req); 866 p9_free_req(clnt, req);
@@ -817,7 +909,7 @@ p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname)
817 goto error; 909 goto error;
818 } 910 }
819 911
820 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); 912 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
821 if (err) { 913 if (err) {
822 p9pdu_dump(1, req->rc); 914 p9pdu_dump(1, req->rc);
823 p9_free_req(clnt, req); 915 p9_free_req(clnt, req);
@@ -875,7 +967,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
875 goto error; 967 goto error;
876 } 968 }
877 969
878 err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids); 970 err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids);
879 if (err) { 971 if (err) {
880 p9pdu_dump(1, req->rc); 972 p9pdu_dump(1, req->rc);
881 p9_free_req(clnt, req); 973 p9_free_req(clnt, req);
@@ -936,7 +1028,7 @@ int p9_client_open(struct p9_fid *fid, int mode)
936 goto error; 1028 goto error;
937 } 1029 }
938 1030
939 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); 1031 err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
940 if (err) { 1032 if (err) {
941 p9pdu_dump(1, req->rc); 1033 p9pdu_dump(1, req->rc);
942 goto free_and_error; 1034 goto free_and_error;
@@ -981,7 +1073,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
981 goto error; 1073 goto error;
982 } 1074 }
983 1075
984 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); 1076 err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
985 if (err) { 1077 if (err) {
986 p9pdu_dump(1, req->rc); 1078 p9pdu_dump(1, req->rc);
987 goto free_and_error; 1079 goto free_and_error;
@@ -1082,7 +1174,7 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
1082 goto error; 1174 goto error;
1083 } 1175 }
1084 1176
1085 err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr); 1177 err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
1086 if (err) { 1178 if (err) {
1087 p9pdu_dump(1, req->rc); 1179 p9pdu_dump(1, req->rc);
1088 goto free_and_error; 1180 goto free_and_error;
@@ -1143,7 +1235,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
1143 goto error; 1235 goto error;
1144 } 1236 }
1145 1237
1146 err = p9pdu_readf(req->rc, clnt->dotu, "d", &count); 1238 err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count);
1147 if (err) { 1239 if (err) {
1148 p9pdu_dump(1, req->rc); 1240 p9pdu_dump(1, req->rc);
1149 goto free_and_error; 1241 goto free_and_error;
@@ -1183,7 +1275,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
1183 goto error; 1275 goto error;
1184 } 1276 }
1185 1277
1186 err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret); 1278 err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret);
1187 if (err) { 1279 if (err) {
1188 p9pdu_dump(1, req->rc); 1280 p9pdu_dump(1, req->rc);
1189 p9_free_req(clnt, req); 1281 p9_free_req(clnt, req);
@@ -1210,14 +1302,15 @@ error:
1210} 1302}
1211EXPORT_SYMBOL(p9_client_stat); 1303EXPORT_SYMBOL(p9_client_stat);
1212 1304
1213static int p9_client_statsize(struct p9_wstat *wst, int optional) 1305static int p9_client_statsize(struct p9_wstat *wst, int proto_version)
1214{ 1306{
1215 int ret; 1307 int ret;
1216 1308
1309 /* NOTE: size shouldn't include its own length */
1217 /* size[2] type[2] dev[4] qid[13] */ 1310 /* size[2] type[2] dev[4] qid[13] */
1218 /* mode[4] atime[4] mtime[4] length[8]*/ 1311 /* mode[4] atime[4] mtime[4] length[8]*/
1219 /* name[s] uid[s] gid[s] muid[s] */ 1312 /* name[s] uid[s] gid[s] muid[s] */
1220 ret = 2+2+4+13+4+4+4+8+2+2+2+2; 1313 ret = 2+4+13+4+4+4+8+2+2+2+2;
1221 1314
1222 if (wst->name) 1315 if (wst->name)
1223 ret += strlen(wst->name); 1316 ret += strlen(wst->name);
@@ -1228,7 +1321,7 @@ static int p9_client_statsize(struct p9_wstat *wst, int optional)
1228 if (wst->muid) 1321 if (wst->muid)
1229 ret += strlen(wst->muid); 1322 ret += strlen(wst->muid);
1230 1323
1231 if (optional) { 1324 if (proto_version == p9_proto_2000u) {
1232 ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */ 1325 ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */
1233 if (wst->extension) 1326 if (wst->extension)
1234 ret += strlen(wst->extension); 1327 ret += strlen(wst->extension);
@@ -1245,7 +1338,7 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
1245 1338
1246 err = 0; 1339 err = 0;
1247 clnt = fid->clnt; 1340 clnt = fid->clnt;
1248 wst->size = p9_client_statsize(wst, clnt->dotu); 1341 wst->size = p9_client_statsize(wst, clnt->proto_version);
1249 P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid); 1342 P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid);
1250 P9_DPRINTK(P9_DEBUG_9P, 1343 P9_DPRINTK(P9_DEBUG_9P,
1251 " sz=%x type=%x dev=%x qid=%x.%llx.%x\n" 1344 " sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
@@ -1258,7 +1351,7 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
1258 wst->name, wst->uid, wst->gid, wst->muid, wst->extension, 1351 wst->name, wst->uid, wst->gid, wst->muid, wst->extension,
1259 wst->n_uid, wst->n_gid, wst->n_muid); 1352 wst->n_uid, wst->n_gid, wst->n_muid);
1260 1353
1261 req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, wst->size, wst); 1354 req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, wst->size+2, wst);
1262 if (IS_ERR(req)) { 1355 if (IS_ERR(req)) {
1263 err = PTR_ERR(req); 1356 err = PTR_ERR(req);
1264 goto error; 1357 goto error;