diff options
Diffstat (limited to 'net/9p')
-rw-r--r-- | net/9p/client.c | 187 | ||||
-rw-r--r-- | net/9p/protocol.c | 75 | ||||
-rw-r--r-- | net/9p/protocol.h | 6 | ||||
-rw-r--r-- | net/9p/trans_fd.c | 127 | ||||
-rw-r--r-- | net/9p/trans_rdma.c | 10 | ||||
-rw-r--r-- | net/9p/trans_virtio.c | 147 | ||||
-rw-r--r-- | net/9p/util.c | 1 |
7 files changed, 342 insertions, 211 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 | ||
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 | ||
@@ -69,24 +105,25 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); | |||
69 | 105 | ||
70 | static int parse_opts(char *opts, struct p9_client *clnt) | 106 | static 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); | 170 | free_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 | ||
709 | error: | 786 | close_trans: |
710 | p9_client_destroy(clnt); | 787 | clnt->trans_mod->close(clnt); |
788 | destroy_fidpool: | ||
789 | p9_idpool_destroy(clnt->fidpool); | ||
790 | put_trans: | ||
791 | v9fs_put_trans(clnt->trans_mod); | ||
792 | free_client: | ||
793 | kfree(clnt); | ||
711 | return ERR_PTR(err); | 794 | return ERR_PTR(err); |
712 | } | 795 | } |
713 | EXPORT_SYMBOL(p9_client_create); | 796 | EXPORT_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 | } |
743 | EXPORT_SYMBOL(p9_client_disconnect); | 828 | EXPORT_SYMBOL(p9_client_disconnect); |
744 | 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 | |||
745 | 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, |
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 | } |
1211 | EXPORT_SYMBOL(p9_client_stat); | 1303 | EXPORT_SYMBOL(p9_client_stat); |
1212 | 1304 | ||
1213 | static int p9_client_statsize(struct p9_wstat *wst, int optional) | 1305 | static 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; |
diff --git a/net/9p/protocol.c b/net/9p/protocol.c index fc70147c771e..e7541d5b0118 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 | ||
54 | static int | 55 | static int |
55 | p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...); | 56 | p9pdu_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 |
58 | void | 59 | void |
@@ -144,7 +145,8 @@ pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) | |||
144 | */ | 145 | */ |
145 | 146 | ||
146 | static int | 147 | static int |
147 | p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | 148 | p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt, |
149 | va_list ap) | ||
148 | { | 150 | { |
149 | const char *ptr; | 151 | const char *ptr; |
150 | int errcode = 0; | 152 | int errcode = 0; |
@@ -194,7 +196,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
194 | int16_t len; | 196 | int16_t len; |
195 | int size; | 197 | int size; |
196 | 198 | ||
197 | errcode = p9pdu_readf(pdu, optional, "w", &len); | 199 | errcode = p9pdu_readf(pdu, proto_version, |
200 | "w", &len); | ||
198 | if (errcode) | 201 | if (errcode) |
199 | break; | 202 | break; |
200 | 203 | ||
@@ -217,7 +220,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
217 | struct p9_qid *qid = | 220 | struct p9_qid *qid = |
218 | va_arg(ap, struct p9_qid *); | 221 | va_arg(ap, struct p9_qid *); |
219 | 222 | ||
220 | errcode = p9pdu_readf(pdu, optional, "bdq", | 223 | errcode = p9pdu_readf(pdu, proto_version, "bdq", |
221 | &qid->type, &qid->version, | 224 | &qid->type, &qid->version, |
222 | &qid->path); | 225 | &qid->path); |
223 | } | 226 | } |
@@ -230,7 +233,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 = | 233 | stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = |
231 | -1; | 234 | -1; |
232 | errcode = | 235 | errcode = |
233 | p9pdu_readf(pdu, optional, | 236 | p9pdu_readf(pdu, proto_version, |
234 | "wwdQdddqssss?sddd", | 237 | "wwdQdddqssss?sddd", |
235 | &stbuf->size, &stbuf->type, | 238 | &stbuf->size, &stbuf->type, |
236 | &stbuf->dev, &stbuf->qid, | 239 | &stbuf->dev, &stbuf->qid, |
@@ -250,7 +253,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
250 | void **data = va_arg(ap, void **); | 253 | void **data = va_arg(ap, void **); |
251 | 254 | ||
252 | errcode = | 255 | errcode = |
253 | p9pdu_readf(pdu, optional, "d", count); | 256 | p9pdu_readf(pdu, proto_version, "d", count); |
254 | if (!errcode) { | 257 | if (!errcode) { |
255 | *count = | 258 | *count = |
256 | MIN(*count, | 259 | MIN(*count, |
@@ -263,8 +266,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
263 | int16_t *nwname = va_arg(ap, int16_t *); | 266 | int16_t *nwname = va_arg(ap, int16_t *); |
264 | char ***wnames = va_arg(ap, char ***); | 267 | char ***wnames = va_arg(ap, char ***); |
265 | 268 | ||
266 | errcode = | 269 | errcode = p9pdu_readf(pdu, proto_version, |
267 | p9pdu_readf(pdu, optional, "w", nwname); | 270 | "w", nwname); |
268 | if (!errcode) { | 271 | if (!errcode) { |
269 | *wnames = | 272 | *wnames = |
270 | kmalloc(sizeof(char *) * *nwname, | 273 | kmalloc(sizeof(char *) * *nwname, |
@@ -278,7 +281,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
278 | 281 | ||
279 | for (i = 0; i < *nwname; i++) { | 282 | for (i = 0; i < *nwname; i++) { |
280 | errcode = | 283 | errcode = |
281 | p9pdu_readf(pdu, optional, | 284 | p9pdu_readf(pdu, |
285 | proto_version, | ||
282 | "s", | 286 | "s", |
283 | &(*wnames)[i]); | 287 | &(*wnames)[i]); |
284 | if (errcode) | 288 | if (errcode) |
@@ -306,7 +310,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
306 | *wqids = NULL; | 310 | *wqids = NULL; |
307 | 311 | ||
308 | errcode = | 312 | errcode = |
309 | p9pdu_readf(pdu, optional, "w", nwqid); | 313 | p9pdu_readf(pdu, proto_version, "w", nwqid); |
310 | if (!errcode) { | 314 | if (!errcode) { |
311 | *wqids = | 315 | *wqids = |
312 | kmalloc(*nwqid * | 316 | kmalloc(*nwqid * |
@@ -321,7 +325,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
321 | 325 | ||
322 | for (i = 0; i < *nwqid; i++) { | 326 | for (i = 0; i < *nwqid; i++) { |
323 | errcode = | 327 | errcode = |
324 | p9pdu_readf(pdu, optional, | 328 | p9pdu_readf(pdu, |
329 | proto_version, | ||
325 | "Q", | 330 | "Q", |
326 | &(*wqids)[i]); | 331 | &(*wqids)[i]); |
327 | if (errcode) | 332 | if (errcode) |
@@ -336,7 +341,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
336 | } | 341 | } |
337 | break; | 342 | break; |
338 | case '?': | 343 | case '?': |
339 | if (!optional) | 344 | if (proto_version != p9_proto_2000u) |
340 | return 0; | 345 | return 0; |
341 | break; | 346 | break; |
342 | default: | 347 | default: |
@@ -352,7 +357,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
352 | } | 357 | } |
353 | 358 | ||
354 | int | 359 | int |
355 | p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | 360 | p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt, |
361 | va_list ap) | ||
356 | { | 362 | { |
357 | const char *ptr; | 363 | const char *ptr; |
358 | int errcode = 0; | 364 | int errcode = 0; |
@@ -389,7 +395,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
389 | if (sptr) | 395 | if (sptr) |
390 | len = MIN(strlen(sptr), USHORT_MAX); | 396 | len = MIN(strlen(sptr), USHORT_MAX); |
391 | 397 | ||
392 | errcode = p9pdu_writef(pdu, optional, "w", len); | 398 | errcode = p9pdu_writef(pdu, proto_version, |
399 | "w", len); | ||
393 | if (!errcode && pdu_write(pdu, sptr, len)) | 400 | if (!errcode && pdu_write(pdu, sptr, len)) |
394 | errcode = -EFAULT; | 401 | errcode = -EFAULT; |
395 | } | 402 | } |
@@ -398,7 +405,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
398 | const struct p9_qid *qid = | 405 | const struct p9_qid *qid = |
399 | va_arg(ap, const struct p9_qid *); | 406 | va_arg(ap, const struct p9_qid *); |
400 | errcode = | 407 | errcode = |
401 | p9pdu_writef(pdu, optional, "bdq", | 408 | p9pdu_writef(pdu, proto_version, "bdq", |
402 | qid->type, qid->version, | 409 | qid->type, qid->version, |
403 | qid->path); | 410 | qid->path); |
404 | } break; | 411 | } break; |
@@ -406,7 +413,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
406 | const struct p9_wstat *stbuf = | 413 | const struct p9_wstat *stbuf = |
407 | va_arg(ap, const struct p9_wstat *); | 414 | va_arg(ap, const struct p9_wstat *); |
408 | errcode = | 415 | errcode = |
409 | p9pdu_writef(pdu, optional, | 416 | p9pdu_writef(pdu, proto_version, |
410 | "wwdQdddqssss?sddd", | 417 | "wwdQdddqssss?sddd", |
411 | stbuf->size, stbuf->type, | 418 | stbuf->size, stbuf->type, |
412 | stbuf->dev, &stbuf->qid, | 419 | stbuf->dev, &stbuf->qid, |
@@ -421,8 +428,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
421 | int32_t count = va_arg(ap, int32_t); | 428 | int32_t count = va_arg(ap, int32_t); |
422 | const void *data = va_arg(ap, const void *); | 429 | const void *data = va_arg(ap, const void *); |
423 | 430 | ||
424 | errcode = | 431 | errcode = p9pdu_writef(pdu, proto_version, "d", |
425 | p9pdu_writef(pdu, optional, "d", count); | 432 | count); |
426 | if (!errcode && pdu_write(pdu, data, count)) | 433 | if (!errcode && pdu_write(pdu, data, count)) |
427 | errcode = -EFAULT; | 434 | errcode = -EFAULT; |
428 | } | 435 | } |
@@ -431,8 +438,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
431 | int32_t count = va_arg(ap, int32_t); | 438 | int32_t count = va_arg(ap, int32_t); |
432 | const char __user *udata = | 439 | const char __user *udata = |
433 | va_arg(ap, const void __user *); | 440 | va_arg(ap, const void __user *); |
434 | errcode = | 441 | errcode = p9pdu_writef(pdu, proto_version, "d", |
435 | p9pdu_writef(pdu, optional, "d", count); | 442 | count); |
436 | if (!errcode && pdu_write_u(pdu, udata, count)) | 443 | if (!errcode && pdu_write_u(pdu, udata, count)) |
437 | errcode = -EFAULT; | 444 | errcode = -EFAULT; |
438 | } | 445 | } |
@@ -441,14 +448,15 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
441 | int16_t nwname = va_arg(ap, int); | 448 | int16_t nwname = va_arg(ap, int); |
442 | const char **wnames = va_arg(ap, const char **); | 449 | const char **wnames = va_arg(ap, const char **); |
443 | 450 | ||
444 | errcode = | 451 | errcode = p9pdu_writef(pdu, proto_version, "w", |
445 | p9pdu_writef(pdu, optional, "w", nwname); | 452 | nwname); |
446 | if (!errcode) { | 453 | if (!errcode) { |
447 | int i; | 454 | int i; |
448 | 455 | ||
449 | for (i = 0; i < nwname; i++) { | 456 | for (i = 0; i < nwname; i++) { |
450 | errcode = | 457 | errcode = |
451 | p9pdu_writef(pdu, optional, | 458 | p9pdu_writef(pdu, |
459 | proto_version, | ||
452 | "s", | 460 | "s", |
453 | wnames[i]); | 461 | wnames[i]); |
454 | if (errcode) | 462 | if (errcode) |
@@ -462,14 +470,15 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
462 | struct p9_qid *wqids = | 470 | struct p9_qid *wqids = |
463 | va_arg(ap, struct p9_qid *); | 471 | va_arg(ap, struct p9_qid *); |
464 | 472 | ||
465 | errcode = | 473 | errcode = p9pdu_writef(pdu, proto_version, "w", |
466 | p9pdu_writef(pdu, optional, "w", nwqid); | 474 | nwqid); |
467 | if (!errcode) { | 475 | if (!errcode) { |
468 | int i; | 476 | int i; |
469 | 477 | ||
470 | for (i = 0; i < nwqid; i++) { | 478 | for (i = 0; i < nwqid; i++) { |
471 | errcode = | 479 | errcode = |
472 | p9pdu_writef(pdu, optional, | 480 | p9pdu_writef(pdu, |
481 | proto_version, | ||
473 | "Q", | 482 | "Q", |
474 | &wqids[i]); | 483 | &wqids[i]); |
475 | if (errcode) | 484 | if (errcode) |
@@ -479,7 +488,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
479 | } | 488 | } |
480 | break; | 489 | break; |
481 | case '?': | 490 | case '?': |
482 | if (!optional) | 491 | if (proto_version != p9_proto_2000u) |
483 | return 0; | 492 | return 0; |
484 | break; | 493 | break; |
485 | default: | 494 | default: |
@@ -494,32 +503,32 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
494 | return errcode; | 503 | return errcode; |
495 | } | 504 | } |
496 | 505 | ||
497 | int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...) | 506 | int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...) |
498 | { | 507 | { |
499 | va_list ap; | 508 | va_list ap; |
500 | int ret; | 509 | int ret; |
501 | 510 | ||
502 | va_start(ap, fmt); | 511 | va_start(ap, fmt); |
503 | ret = p9pdu_vreadf(pdu, optional, fmt, ap); | 512 | ret = p9pdu_vreadf(pdu, proto_version, fmt, ap); |
504 | va_end(ap); | 513 | va_end(ap); |
505 | 514 | ||
506 | return ret; | 515 | return ret; |
507 | } | 516 | } |
508 | 517 | ||
509 | static int | 518 | static int |
510 | p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...) | 519 | p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...) |
511 | { | 520 | { |
512 | va_list ap; | 521 | va_list ap; |
513 | int ret; | 522 | int ret; |
514 | 523 | ||
515 | va_start(ap, fmt); | 524 | va_start(ap, fmt); |
516 | ret = p9pdu_vwritef(pdu, optional, fmt, ap); | 525 | ret = p9pdu_vwritef(pdu, proto_version, fmt, ap); |
517 | va_end(ap); | 526 | va_end(ap); |
518 | 527 | ||
519 | return ret; | 528 | return ret; |
520 | } | 529 | } |
521 | 530 | ||
522 | int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu) | 531 | int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version) |
523 | { | 532 | { |
524 | struct p9_fcall fake_pdu; | 533 | struct p9_fcall fake_pdu; |
525 | int ret; | 534 | int ret; |
@@ -529,7 +538,7 @@ int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu) | |||
529 | fake_pdu.sdata = buf; | 538 | fake_pdu.sdata = buf; |
530 | fake_pdu.offset = 0; | 539 | fake_pdu.offset = 0; |
531 | 540 | ||
532 | ret = p9pdu_readf(&fake_pdu, dotu, "S", st); | 541 | ret = p9pdu_readf(&fake_pdu, proto_version, "S", st); |
533 | if (ret) { | 542 | if (ret) { |
534 | P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); | 543 | P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); |
535 | p9pdu_dump(1, &fake_pdu); | 544 | p9pdu_dump(1, &fake_pdu); |
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 | ||
28 | int | 28 | int p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt, |
29 | p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap); | 29 | va_list ap); |
30 | int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...); | 30 | int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...); |
31 | int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type); | 31 | int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type); |
32 | int p9pdu_finalize(struct p9_fcall *pdu); | 32 | int p9pdu_finalize(struct p9_fcall *pdu); |
33 | void p9pdu_dump(int, struct p9_fcall *); | 33 | void p9pdu_dump(int, struct p9_fcall *); |
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 8d934dd7fd54..98ce9bcb0e15 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c | |||
@@ -38,10 +38,13 @@ | |||
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> |
44 | 45 | ||
46 | #include <linux/syscalls.h> /* killme */ | ||
47 | |||
45 | #define P9_PORT 564 | 48 | #define P9_PORT 564 |
46 | #define MAX_SOCK_BUF (64*1024) | 49 | #define MAX_SOCK_BUF (64*1024) |
47 | #define MAXPOLLWADDR 2 | 50 | #define MAXPOLLWADDR 2 |
@@ -633,8 +636,8 @@ static void p9_poll_mux(struct p9_conn *m) | |||
633 | if (n & POLLOUT) { | 636 | if (n & POLLOUT) { |
634 | set_bit(Wpending, &m->wsched); | 637 | set_bit(Wpending, &m->wsched); |
635 | P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m); | 638 | P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m); |
636 | if ((m->wsize || !list_empty(&m->unsent_req_list)) | 639 | if ((m->wsize || !list_empty(&m->unsent_req_list)) && |
637 | && !test_and_set_bit(Wworksched, &m->wsched)) { | 640 | !test_and_set_bit(Wworksched, &m->wsched)) { |
638 | P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m); | 641 | P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m); |
639 | queue_work(p9_mux_wq, &m->wq); | 642 | queue_work(p9_mux_wq, &m->wq); |
640 | } | 643 | } |
@@ -712,7 +715,7 @@ static int parse_opts(char *params, struct p9_fd_opts *opts) | |||
712 | char *p; | 715 | char *p; |
713 | substring_t args[MAX_OPT_ARGS]; | 716 | substring_t args[MAX_OPT_ARGS]; |
714 | int option; | 717 | int option; |
715 | char *options; | 718 | char *options, *tmp_options; |
716 | int ret; | 719 | int ret; |
717 | 720 | ||
718 | opts->port = P9_PORT; | 721 | opts->port = P9_PORT; |
@@ -722,12 +725,13 @@ static int parse_opts(char *params, struct p9_fd_opts *opts) | |||
722 | if (!params) | 725 | if (!params) |
723 | return 0; | 726 | return 0; |
724 | 727 | ||
725 | options = kstrdup(params, GFP_KERNEL); | 728 | tmp_options = kstrdup(params, GFP_KERNEL); |
726 | if (!options) { | 729 | if (!tmp_options) { |
727 | P9_DPRINTK(P9_DEBUG_ERROR, | 730 | P9_DPRINTK(P9_DEBUG_ERROR, |
728 | "failed to allocate copy of option string\n"); | 731 | "failed to allocate copy of option string\n"); |
729 | return -ENOMEM; | 732 | return -ENOMEM; |
730 | } | 733 | } |
734 | options = tmp_options; | ||
731 | 735 | ||
732 | while ((p = strsep(&options, ",")) != NULL) { | 736 | while ((p = strsep(&options, ",")) != NULL) { |
733 | int token; | 737 | int token; |
@@ -758,7 +762,8 @@ static int parse_opts(char *params, struct p9_fd_opts *opts) | |||
758 | continue; | 762 | continue; |
759 | } | 763 | } |
760 | } | 764 | } |
761 | kfree(options); | 765 | |
766 | kfree(tmp_options); | ||
762 | return 0; | 767 | return 0; |
763 | } | 768 | } |
764 | 769 | ||
@@ -788,24 +793,41 @@ static int p9_fd_open(struct p9_client *client, int rfd, int wfd) | |||
788 | 793 | ||
789 | static int p9_socket_open(struct p9_client *client, struct socket *csocket) | 794 | static int p9_socket_open(struct p9_client *client, struct socket *csocket) |
790 | { | 795 | { |
791 | int fd, ret; | 796 | struct p9_trans_fd *p; |
797 | int ret, fd; | ||
798 | |||
799 | p = kmalloc(sizeof(struct p9_trans_fd), GFP_KERNEL); | ||
800 | if (!p) | ||
801 | return -ENOMEM; | ||
792 | 802 | ||
793 | csocket->sk->sk_allocation = GFP_NOIO; | 803 | csocket->sk->sk_allocation = GFP_NOIO; |
794 | fd = sock_map_fd(csocket, 0); | 804 | fd = sock_map_fd(csocket, 0); |
795 | if (fd < 0) { | 805 | if (fd < 0) { |
796 | P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n"); | 806 | P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n"); |
807 | sock_release(csocket); | ||
808 | kfree(p); | ||
797 | return fd; | 809 | return fd; |
798 | } | 810 | } |
799 | 811 | ||
800 | ret = p9_fd_open(client, fd, fd); | 812 | get_file(csocket->file); |
801 | if (ret < 0) { | 813 | get_file(csocket->file); |
802 | P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n"); | 814 | p->wr = p->rd = csocket->file; |
815 | client->trans = p; | ||
816 | client->status = Connected; | ||
817 | |||
818 | sys_close(fd); /* still racy */ | ||
819 | |||
820 | p->rd->f_flags |= O_NONBLOCK; | ||
821 | |||
822 | p->conn = p9_conn_create(client); | ||
823 | if (IS_ERR(p->conn)) { | ||
824 | ret = PTR_ERR(p->conn); | ||
825 | p->conn = NULL; | ||
826 | kfree(p); | ||
827 | sockfd_put(csocket); | ||
803 | sockfd_put(csocket); | 828 | sockfd_put(csocket); |
804 | return ret; | 829 | return ret; |
805 | } | 830 | } |
806 | |||
807 | ((struct p9_trans_fd *)client->trans)->rd->f_flags |= O_NONBLOCK; | ||
808 | |||
809 | return 0; | 831 | return 0; |
810 | } | 832 | } |
811 | 833 | ||
@@ -883,7 +905,6 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args) | |||
883 | struct socket *csocket; | 905 | struct socket *csocket; |
884 | struct sockaddr_in sin_server; | 906 | struct sockaddr_in sin_server; |
885 | struct p9_fd_opts opts; | 907 | struct p9_fd_opts opts; |
886 | struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */ | ||
887 | 908 | ||
888 | err = parse_opts(args, &opts); | 909 | err = parse_opts(args, &opts); |
889 | if (err < 0) | 910 | if (err < 0) |
@@ -897,12 +918,11 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args) | |||
897 | sin_server.sin_family = AF_INET; | 918 | sin_server.sin_family = AF_INET; |
898 | sin_server.sin_addr.s_addr = in_aton(addr); | 919 | sin_server.sin_addr.s_addr = in_aton(addr); |
899 | sin_server.sin_port = htons(opts.port); | 920 | sin_server.sin_port = htons(opts.port); |
900 | sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket); | 921 | err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket); |
901 | 922 | ||
902 | if (!csocket) { | 923 | if (err) { |
903 | P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n"); | 924 | P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n"); |
904 | err = -EIO; | 925 | return err; |
905 | goto error; | ||
906 | } | 926 | } |
907 | 927 | ||
908 | err = csocket->ops->connect(csocket, | 928 | err = csocket->ops->connect(csocket, |
@@ -912,30 +932,11 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args) | |||
912 | P9_EPRINTK(KERN_ERR, | 932 | P9_EPRINTK(KERN_ERR, |
913 | "p9_trans_tcp: problem connecting socket to %s\n", | 933 | "p9_trans_tcp: problem connecting socket to %s\n", |
914 | addr); | 934 | addr); |
915 | goto error; | ||
916 | } | ||
917 | |||
918 | err = p9_socket_open(client, csocket); | ||
919 | if (err < 0) | ||
920 | goto error; | ||
921 | |||
922 | p = (struct p9_trans_fd *) client->trans; | ||
923 | p->conn = p9_conn_create(client); | ||
924 | if (IS_ERR(p->conn)) { | ||
925 | err = PTR_ERR(p->conn); | ||
926 | p->conn = NULL; | ||
927 | goto error; | ||
928 | } | ||
929 | |||
930 | return 0; | ||
931 | |||
932 | error: | ||
933 | if (csocket) | ||
934 | sock_release(csocket); | 935 | sock_release(csocket); |
936 | return err; | ||
937 | } | ||
935 | 938 | ||
936 | kfree(p); | 939 | return p9_socket_open(client, csocket); |
937 | |||
938 | return err; | ||
939 | } | 940 | } |
940 | 941 | ||
941 | static int | 942 | static int |
@@ -944,49 +945,33 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args) | |||
944 | int err; | 945 | int err; |
945 | struct socket *csocket; | 946 | struct socket *csocket; |
946 | struct sockaddr_un sun_server; | 947 | struct sockaddr_un sun_server; |
947 | struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */ | ||
948 | 948 | ||
949 | csocket = NULL; | 949 | csocket = NULL; |
950 | 950 | ||
951 | if (strlen(addr) > UNIX_PATH_MAX) { | 951 | if (strlen(addr) > UNIX_PATH_MAX) { |
952 | 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", |
953 | addr); | 953 | addr); |
954 | err = -ENAMETOOLONG; | 954 | return -ENAMETOOLONG; |
955 | goto error; | ||
956 | } | 955 | } |
957 | 956 | ||
958 | sun_server.sun_family = PF_UNIX; | 957 | sun_server.sun_family = PF_UNIX; |
959 | strcpy(sun_server.sun_path, addr); | 958 | strcpy(sun_server.sun_path, addr); |
960 | sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket); | 959 | err = sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket); |
960 | if (err < 0) { | ||
961 | P9_EPRINTK(KERN_ERR, "p9_trans_unix: problem creating socket\n"); | ||
962 | return err; | ||
963 | } | ||
961 | err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, | 964 | err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, |
962 | sizeof(struct sockaddr_un) - 1, 0); | 965 | sizeof(struct sockaddr_un) - 1, 0); |
963 | if (err < 0) { | 966 | if (err < 0) { |
964 | P9_EPRINTK(KERN_ERR, | 967 | P9_EPRINTK(KERN_ERR, |
965 | "p9_trans_unix: problem connecting socket: %s: %d\n", | 968 | "p9_trans_unix: problem connecting socket: %s: %d\n", |
966 | addr, err); | 969 | addr, err); |
967 | goto error; | ||
968 | } | ||
969 | |||
970 | err = p9_socket_open(client, csocket); | ||
971 | if (err < 0) | ||
972 | goto error; | ||
973 | |||
974 | p = (struct p9_trans_fd *) client->trans; | ||
975 | p->conn = p9_conn_create(client); | ||
976 | if (IS_ERR(p->conn)) { | ||
977 | err = PTR_ERR(p->conn); | ||
978 | p->conn = NULL; | ||
979 | goto error; | ||
980 | } | ||
981 | |||
982 | return 0; | ||
983 | |||
984 | error: | ||
985 | if (csocket) | ||
986 | sock_release(csocket); | 970 | sock_release(csocket); |
971 | return err; | ||
972 | } | ||
987 | 973 | ||
988 | kfree(p); | 974 | return p9_socket_open(client, csocket); |
989 | return err; | ||
990 | } | 975 | } |
991 | 976 | ||
992 | static int | 977 | static int |
@@ -994,7 +979,7 @@ p9_fd_create(struct p9_client *client, const char *addr, char *args) | |||
994 | { | 979 | { |
995 | int err; | 980 | int err; |
996 | struct p9_fd_opts opts; | 981 | struct p9_fd_opts opts; |
997 | struct p9_trans_fd *p = NULL; /* this get allocated in p9_fd_open */ | 982 | struct p9_trans_fd *p; |
998 | 983 | ||
999 | parse_opts(args, &opts); | 984 | parse_opts(args, &opts); |
1000 | 985 | ||
@@ -1005,21 +990,19 @@ p9_fd_create(struct p9_client *client, const char *addr, char *args) | |||
1005 | 990 | ||
1006 | err = p9_fd_open(client, opts.rfd, opts.wfd); | 991 | err = p9_fd_open(client, opts.rfd, opts.wfd); |
1007 | if (err < 0) | 992 | if (err < 0) |
1008 | goto error; | 993 | return err; |
1009 | 994 | ||
1010 | p = (struct p9_trans_fd *) client->trans; | 995 | p = (struct p9_trans_fd *) client->trans; |
1011 | p->conn = p9_conn_create(client); | 996 | p->conn = p9_conn_create(client); |
1012 | if (IS_ERR(p->conn)) { | 997 | if (IS_ERR(p->conn)) { |
1013 | err = PTR_ERR(p->conn); | 998 | err = PTR_ERR(p->conn); |
1014 | p->conn = NULL; | 999 | p->conn = NULL; |
1015 | goto error; | 1000 | fput(p->rd); |
1001 | fput(p->wr); | ||
1002 | return err; | ||
1016 | } | 1003 | } |
1017 | 1004 | ||
1018 | return 0; | 1005 | return 0; |
1019 | |||
1020 | error: | ||
1021 | kfree(p); | ||
1022 | return err; | ||
1023 | } | 1006 | } |
1024 | 1007 | ||
1025 | static struct p9_trans_module p9_tcp_trans = { | 1008 | static struct p9_trans_module p9_tcp_trans = { |
diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c index 65cb29db03f8..041101ab4aa5 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 | ||
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index ea1e3daabefe..7eb78ecc1618 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 */ |
51 | static DEFINE_MUTEX(virtio_9p_lock); | 52 | static DEFINE_MUTEX(virtio_9p_lock); |
52 | /* global which tracks highest initialized channel */ | ||
53 | static 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 | ||
71 | static struct virtio_chan { | 70 | struct 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 | |||
91 | static struct list_head virtio_chan_list; | ||
84 | 92 | ||
85 | /* How many bytes left in this page. */ | 93 | /* How many bytes left in this page. */ |
86 | static unsigned int rest_of_page(void *data) | 94 | static 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 | ||
@@ -212,30 +221,38 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) | |||
212 | return 0; | 221 | return 0; |
213 | } | 222 | } |
214 | 223 | ||
224 | static 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 | |||
236 | static 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 | ||
225 | static int p9_virtio_probe(struct virtio_device *vdev) | 246 | static 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 | ||
260 | out_free_vq: | 301 | out_free_vq: |
261 | vdev->config->del_vqs(vdev); | 302 | vdev->config->del_vqs(vdev); |
303 | kfree(chan); | ||
262 | fail: | 304 | fail: |
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,35 @@ 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 | ||
290 | static int | 323 | static int |
291 | p9_virtio_create(struct p9_client *client, const char *devname, char *args) | 324 | p9_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 | if (!chan->inuse) { |
300 | break; | 334 | chan->inuse = true; |
301 | } else { | 335 | found = 1; |
302 | index++; | 336 | break; |
303 | chan = &channels[index]; | 337 | } |
338 | ret = -EBUSY; | ||
304 | } | 339 | } |
305 | } | 340 | } |
306 | mutex_unlock(&virtio_9p_lock); | 341 | mutex_unlock(&virtio_9p_lock); |
307 | 342 | ||
308 | if (index >= MAX_9P_CHAN) { | 343 | if (!found) { |
309 | printk(KERN_ERR "9p: no channels available\n"); | 344 | printk(KERN_ERR "9p: no channels available\n"); |
310 | return -ENODEV; | 345 | return ret; |
311 | } | 346 | } |
312 | 347 | ||
313 | client->trans = (void *)chan; | 348 | client->trans = (void *)chan; |
349 | client->status = Connected; | ||
314 | chan->client = client; | 350 | chan->client = client; |
315 | 351 | ||
316 | return 0; | 352 | return 0; |
@@ -327,11 +363,15 @@ static void p9_virtio_remove(struct virtio_device *vdev) | |||
327 | struct virtio_chan *chan = vdev->priv; | 363 | struct virtio_chan *chan = vdev->priv; |
328 | 364 | ||
329 | BUG_ON(chan->inuse); | 365 | BUG_ON(chan->inuse); |
366 | vdev->config->del_vqs(vdev); | ||
367 | |||
368 | mutex_lock(&virtio_9p_lock); | ||
369 | list_del(&chan->chan_list); | ||
370 | mutex_unlock(&virtio_9p_lock); | ||
371 | sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); | ||
372 | kfree(chan->tag); | ||
373 | kfree(chan); | ||
330 | 374 | ||
331 | if (chan->initialized) { | ||
332 | vdev->config->del_vqs(vdev); | ||
333 | chan->initialized = false; | ||
334 | } | ||
335 | } | 375 | } |
336 | 376 | ||
337 | static struct virtio_device_id id_table[] = { | 377 | static struct virtio_device_id id_table[] = { |
@@ -339,13 +379,19 @@ static struct virtio_device_id id_table[] = { | |||
339 | { 0 }, | 379 | { 0 }, |
340 | }; | 380 | }; |
341 | 381 | ||
382 | static unsigned int features[] = { | ||
383 | VIRTIO_9P_MOUNT_TAG, | ||
384 | }; | ||
385 | |||
342 | /* The standard "struct lguest_driver": */ | 386 | /* The standard "struct lguest_driver": */ |
343 | static struct virtio_driver p9_virtio_drv = { | 387 | static struct virtio_driver p9_virtio_drv = { |
344 | .driver.name = KBUILD_MODNAME, | 388 | .feature_table = features, |
345 | .driver.owner = THIS_MODULE, | 389 | .feature_table_size = ARRAY_SIZE(features), |
346 | .id_table = id_table, | 390 | .driver.name = KBUILD_MODNAME, |
347 | .probe = p9_virtio_probe, | 391 | .driver.owner = THIS_MODULE, |
348 | .remove = p9_virtio_remove, | 392 | .id_table = id_table, |
393 | .probe = p9_virtio_probe, | ||
394 | .remove = p9_virtio_remove, | ||
349 | }; | 395 | }; |
350 | 396 | ||
351 | static struct p9_trans_module p9_virtio_trans = { | 397 | static struct p9_trans_module p9_virtio_trans = { |
@@ -362,10 +408,7 @@ static struct p9_trans_module p9_virtio_trans = { | |||
362 | /* The standard init function */ | 408 | /* The standard init function */ |
363 | static int __init p9_virtio_init(void) | 409 | static int __init p9_virtio_init(void) |
364 | { | 410 | { |
365 | int count; | 411 | INIT_LIST_HEAD(&virtio_chan_list); |
366 | |||
367 | for (count = 0; count < MAX_9P_CHAN; count++) | ||
368 | channels[count].initialized = false; | ||
369 | 412 | ||
370 | v9fs_register_trans(&p9_virtio_trans); | 413 | v9fs_register_trans(&p9_virtio_trans); |
371 | return register_virtio_driver(&p9_virtio_drv); | 414 | 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 | /** |