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.c134
1 files changed, 105 insertions, 29 deletions
diff --git a/net/9p/client.c b/net/9p/client.c
index 09d4f1e2e4a8..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
@@ -75,7 +111,7 @@ static int parse_opts(char *opts, struct p9_client *clnt)
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)
@@ -118,7 +154,13 @@ static int parse_opts(char *opts, struct p9_client *clnt)
118 } 154 }
119 break; 155 break;
120 case Opt_legacy: 156 case Opt_legacy:
121 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;
122 break; 164 break;
123 default: 165 default:
124 continue; 166 continue;
@@ -410,14 +452,15 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
410 int ecode; 452 int ecode;
411 char *ename; 453 char *ename;
412 454
413 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);
414 if (err) { 457 if (err) {
415 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", 458 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
416 err); 459 err);
417 return err; 460 return err;
418 } 461 }
419 462
420 if (c->dotu) 463 if (p9_is_proto_dotu(c))
421 err = -ecode; 464 err = -ecode;
422 465
423 if (!err || !IS_ERR_VALUE(err)) 466 if (!err || !IS_ERR_VALUE(err))
@@ -492,7 +535,12 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
492 535
493 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);
494 537
495 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))
496 return ERR_PTR(-EIO); 544 return ERR_PTR(-EIO);
497 545
498 if (signal_pending(current)) { 546 if (signal_pending(current)) {
@@ -515,7 +563,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
515 /* marshall the data */ 563 /* marshall the data */
516 p9pdu_prepare(req->tc, tag, type); 564 p9pdu_prepare(req->tc, tag, type);
517 va_start(ap, fmt); 565 va_start(ap, fmt);
518 err = p9pdu_vwritef(req->tc, c->dotu, fmt, ap); 566 err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap);
519 va_end(ap); 567 va_end(ap);
520 p9pdu_finalize(req->tc); 568 p9pdu_finalize(req->tc);
521 569
@@ -627,14 +675,31 @@ int p9_client_version(struct p9_client *c)
627 char *version; 675 char *version;
628 int msize; 676 int msize;
629 677
630 P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n", 678 P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n",
631 c->msize, c->dotu); 679 c->msize, c->proto_version);
632 req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize, 680
633 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
634 if (IS_ERR(req)) 699 if (IS_ERR(req))
635 return PTR_ERR(req); 700 return PTR_ERR(req);
636 701
637 err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version); 702 err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version);
638 if (err) { 703 if (err) {
639 P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); 704 P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
640 p9pdu_dump(1, req->rc); 705 p9pdu_dump(1, req->rc);
@@ -642,10 +707,12 @@ int p9_client_version(struct p9_client *c)
642 } 707 }
643 708
644 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);
645 if (!memcmp(version, "9P2000.u", 8)) 710 if (!strncmp(version, "9P2000.L", 8))
646 c->dotu = 1; 711 c->proto_version = p9_proto_2000L;
647 else if (!memcmp(version, "9P2000", 6)) 712 else if (!strncmp(version, "9P2000.u", 8))
648 c->dotu = 0; 713 c->proto_version = p9_proto_2000u;
714 else if (!strncmp(version, "9P2000", 6))
715 c->proto_version = p9_proto_legacy;
649 else { 716 else {
650 err = -EREMOTEIO; 717 err = -EREMOTEIO;
651 goto error; 718 goto error;
@@ -700,8 +767,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
700 goto put_trans; 767 goto put_trans;
701 } 768 }
702 769
703 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",
704 clnt, clnt->trans_mod, clnt->msize, clnt->dotu); 771 clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
705 772
706 err = clnt->trans_mod->create(clnt, dev_name, options); 773 err = clnt->trans_mod->create(clnt, dev_name, options);
707 if (err) 774 if (err)
@@ -739,8 +806,10 @@ void p9_client_destroy(struct p9_client *clnt)
739 806
740 v9fs_put_trans(clnt->trans_mod); 807 v9fs_put_trans(clnt->trans_mod);
741 808
742 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);
743 p9_fid_destroy(fid); 811 p9_fid_destroy(fid);
812 }
744 813
745 if (clnt->fidpool) 814 if (clnt->fidpool)
746 p9_idpool_destroy(clnt->fidpool); 815 p9_idpool_destroy(clnt->fidpool);
@@ -758,6 +827,13 @@ void p9_client_disconnect(struct p9_client *clnt)
758} 827}
759EXPORT_SYMBOL(p9_client_disconnect); 828EXPORT_SYMBOL(p9_client_disconnect);
760 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
761struct 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,
762 char *uname, u32 n_uname, char *aname) 838 char *uname, u32 n_uname, char *aname)
763{ 839{
@@ -784,7 +860,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
784 goto error; 860 goto error;
785 } 861 }
786 862
787 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); 863 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
788 if (err) { 864 if (err) {
789 p9pdu_dump(1, req->rc); 865 p9pdu_dump(1, req->rc);
790 p9_free_req(clnt, req); 866 p9_free_req(clnt, req);
@@ -833,7 +909,7 @@ p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname)
833 goto error; 909 goto error;
834 } 910 }
835 911
836 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); 912 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
837 if (err) { 913 if (err) {
838 p9pdu_dump(1, req->rc); 914 p9pdu_dump(1, req->rc);
839 p9_free_req(clnt, req); 915 p9_free_req(clnt, req);
@@ -891,7 +967,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
891 goto error; 967 goto error;
892 } 968 }
893 969
894 err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids); 970 err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids);
895 if (err) { 971 if (err) {
896 p9pdu_dump(1, req->rc); 972 p9pdu_dump(1, req->rc);
897 p9_free_req(clnt, req); 973 p9_free_req(clnt, req);
@@ -952,7 +1028,7 @@ int p9_client_open(struct p9_fid *fid, int mode)
952 goto error; 1028 goto error;
953 } 1029 }
954 1030
955 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); 1031 err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
956 if (err) { 1032 if (err) {
957 p9pdu_dump(1, req->rc); 1033 p9pdu_dump(1, req->rc);
958 goto free_and_error; 1034 goto free_and_error;
@@ -997,7 +1073,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
997 goto error; 1073 goto error;
998 } 1074 }
999 1075
1000 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); 1076 err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
1001 if (err) { 1077 if (err) {
1002 p9pdu_dump(1, req->rc); 1078 p9pdu_dump(1, req->rc);
1003 goto free_and_error; 1079 goto free_and_error;
@@ -1098,7 +1174,7 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
1098 goto error; 1174 goto error;
1099 } 1175 }
1100 1176
1101 err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr); 1177 err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
1102 if (err) { 1178 if (err) {
1103 p9pdu_dump(1, req->rc); 1179 p9pdu_dump(1, req->rc);
1104 goto free_and_error; 1180 goto free_and_error;
@@ -1159,7 +1235,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
1159 goto error; 1235 goto error;
1160 } 1236 }
1161 1237
1162 err = p9pdu_readf(req->rc, clnt->dotu, "d", &count); 1238 err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count);
1163 if (err) { 1239 if (err) {
1164 p9pdu_dump(1, req->rc); 1240 p9pdu_dump(1, req->rc);
1165 goto free_and_error; 1241 goto free_and_error;
@@ -1199,7 +1275,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
1199 goto error; 1275 goto error;
1200 } 1276 }
1201 1277
1202 err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret); 1278 err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret);
1203 if (err) { 1279 if (err) {
1204 p9pdu_dump(1, req->rc); 1280 p9pdu_dump(1, req->rc);
1205 p9_free_req(clnt, req); 1281 p9_free_req(clnt, req);
@@ -1226,7 +1302,7 @@ error:
1226} 1302}
1227EXPORT_SYMBOL(p9_client_stat); 1303EXPORT_SYMBOL(p9_client_stat);
1228 1304
1229static int p9_client_statsize(struct p9_wstat *wst, int optional) 1305static int p9_client_statsize(struct p9_wstat *wst, int proto_version)
1230{ 1306{
1231 int ret; 1307 int ret;
1232 1308
@@ -1245,7 +1321,7 @@ static int p9_client_statsize(struct p9_wstat *wst, int optional)
1245 if (wst->muid) 1321 if (wst->muid)
1246 ret += strlen(wst->muid); 1322 ret += strlen(wst->muid);
1247 1323
1248 if (optional) { 1324 if (proto_version == p9_proto_2000u) {
1249 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] */
1250 if (wst->extension) 1326 if (wst->extension)
1251 ret += strlen(wst->extension); 1327 ret += strlen(wst->extension);
@@ -1262,7 +1338,7 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
1262 1338
1263 err = 0; 1339 err = 0;
1264 clnt = fid->clnt; 1340 clnt = fid->clnt;
1265 wst->size = p9_client_statsize(wst, clnt->dotu); 1341 wst->size = p9_client_statsize(wst, clnt->proto_version);
1266 P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid); 1342 P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid);
1267 P9_DPRINTK(P9_DEBUG_9P, 1343 P9_DPRINTK(P9_DEBUG_9P,
1268 " sz=%x type=%x dev=%x qid=%x.%llx.%x\n" 1344 " sz=%x type=%x dev=%x qid=%x.%llx.%x\n"