diff options
Diffstat (limited to 'net/9p/client.c')
-rw-r--r-- | net/9p/client.c | 134 |
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 | ||
62 | inline int p9_is_proto_dotl(struct p9_client *clnt) | ||
63 | { | ||
64 | return (clnt->proto_version == p9_proto_2000L); | ||
65 | } | ||
66 | EXPORT_SYMBOL(p9_is_proto_dotl); | ||
67 | |||
68 | inline int p9_is_proto_dotu(struct p9_client *clnt) | ||
69 | { | ||
70 | return (clnt->proto_version == p9_proto_2000u); | ||
71 | } | ||
72 | EXPORT_SYMBOL(p9_is_proto_dotu); | ||
73 | |||
74 | /* Interpret mount option for protocol version */ | ||
75 | static 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 | |||
59 | static struct p9_req_t * | 95 | static struct p9_req_t * |
60 | p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); | 96 | p9_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 | } |
759 | EXPORT_SYMBOL(p9_client_disconnect); | 828 | EXPORT_SYMBOL(p9_client_disconnect); |
760 | 829 | ||
830 | void p9_client_begin_disconnect(struct p9_client *clnt) | ||
831 | { | ||
832 | P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); | ||
833 | clnt->status = BeginDisconnect; | ||
834 | } | ||
835 | EXPORT_SYMBOL(p9_client_begin_disconnect); | ||
836 | |||
761 | struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, | 837 | struct 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 | } |
1227 | EXPORT_SYMBOL(p9_client_stat); | 1303 | EXPORT_SYMBOL(p9_client_stat); |
1228 | 1304 | ||
1229 | static int p9_client_statsize(struct p9_wstat *wst, int optional) | 1305 | static 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" |