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.c653
1 files changed, 596 insertions, 57 deletions
diff --git a/net/9p/client.c b/net/9p/client.c
index 8af95b2dddd6..9eb72505308f 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -29,6 +29,7 @@
29#include <linux/poll.h> 29#include <linux/poll.h>
30#include <linux/idr.h> 30#include <linux/idr.h>
31#include <linux/mutex.h> 31#include <linux/mutex.h>
32#include <linux/slab.h>
32#include <linux/sched.h> 33#include <linux/sched.h>
33#include <linux/uaccess.h> 34#include <linux/uaccess.h>
34#include <net/9p/9p.h> 35#include <net/9p/9p.h>
@@ -46,6 +47,7 @@ enum {
46 Opt_msize, 47 Opt_msize,
47 Opt_trans, 48 Opt_trans,
48 Opt_legacy, 49 Opt_legacy,
50 Opt_version,
49 Opt_err, 51 Opt_err,
50}; 52};
51 53
@@ -53,9 +55,43 @@ static const match_table_t tokens = {
53 {Opt_msize, "msize=%u"}, 55 {Opt_msize, "msize=%u"},
54 {Opt_legacy, "noextend"}, 56 {Opt_legacy, "noextend"},
55 {Opt_trans, "trans=%s"}, 57 {Opt_trans, "trans=%s"},
58 {Opt_version, "version=%s"},
56 {Opt_err, NULL}, 59 {Opt_err, NULL},
57}; 60};
58 61
62inline int p9_is_proto_dotl(struct p9_client *clnt)
63{
64 return (clnt->proto_version == p9_proto_2000L);
65}
66EXPORT_SYMBOL(p9_is_proto_dotl);
67
68inline int p9_is_proto_dotu(struct p9_client *clnt)
69{
70 return (clnt->proto_version == p9_proto_2000u);
71}
72EXPORT_SYMBOL(p9_is_proto_dotu);
73
74/* Interpret mount option for protocol version */
75static int get_protocol_version(const substring_t *name)
76{
77 int version = -EINVAL;
78
79 if (!strncmp("9p2000", name->from, name->to-name->from)) {
80 version = p9_proto_legacy;
81 P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n");
82 } else if (!strncmp("9p2000.u", name->from, name->to-name->from)) {
83 version = p9_proto_2000u;
84 P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.u\n");
85 } else if (!strncmp("9p2000.L", name->from, name->to-name->from)) {
86 version = p9_proto_2000L;
87 P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.L\n");
88 } else {
89 P9_DPRINTK(P9_DEBUG_ERROR, "Unknown protocol version %s. ",
90 name->from);
91 }
92 return version;
93}
94
59static struct p9_req_t * 95static struct p9_req_t *
60p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); 96p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
61 97
@@ -69,24 +105,25 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
69 105
70static int parse_opts(char *opts, struct p9_client *clnt) 106static int parse_opts(char *opts, struct p9_client *clnt)
71{ 107{
72 char *options; 108 char *options, *tmp_options;
73 char *p; 109 char *p;
74 substring_t args[MAX_OPT_ARGS]; 110 substring_t args[MAX_OPT_ARGS];
75 int option; 111 int option;
76 int ret = 0; 112 int ret = 0;
77 113
78 clnt->dotu = 1; 114 clnt->proto_version = p9_proto_2000u;
79 clnt->msize = 8192; 115 clnt->msize = 8192;
80 116
81 if (!opts) 117 if (!opts)
82 return 0; 118 return 0;
83 119
84 options = kstrdup(opts, GFP_KERNEL); 120 tmp_options = kstrdup(opts, GFP_KERNEL);
85 if (!options) { 121 if (!tmp_options) {
86 P9_DPRINTK(P9_DEBUG_ERROR, 122 P9_DPRINTK(P9_DEBUG_ERROR,
87 "failed to allocate copy of option string\n"); 123 "failed to allocate copy of option string\n");
88 return -ENOMEM; 124 return -ENOMEM;
89 } 125 }
126 options = tmp_options;
90 127
91 while ((p = strsep(&options, ",")) != NULL) { 128 while ((p = strsep(&options, ",")) != NULL) {
92 int token; 129 int token;
@@ -108,16 +145,30 @@ static int parse_opts(char *opts, struct p9_client *clnt)
108 break; 145 break;
109 case Opt_trans: 146 case Opt_trans:
110 clnt->trans_mod = v9fs_get_trans_by_name(&args[0]); 147 clnt->trans_mod = v9fs_get_trans_by_name(&args[0]);
148 if(clnt->trans_mod == NULL) {
149 P9_DPRINTK(P9_DEBUG_ERROR,
150 "Could not find request transport: %s\n",
151 (char *) &args[0]);
152 ret = -EINVAL;
153 goto free_and_return;
154 }
111 break; 155 break;
112 case Opt_legacy: 156 case Opt_legacy:
113 clnt->dotu = 0; 157 clnt->proto_version = p9_proto_legacy;
158 break;
159 case Opt_version:
160 ret = get_protocol_version(&args[0]);
161 if (ret == -EINVAL)
162 goto free_and_return;
163 clnt->proto_version = ret;
114 break; 164 break;
115 default: 165 default:
116 continue; 166 continue;
117 } 167 }
118 } 168 }
119 169
120 kfree(options); 170free_and_return:
171 kfree(tmp_options);
121 return ret; 172 return ret;
122} 173}
123 174
@@ -280,8 +331,10 @@ static void p9_tag_cleanup(struct p9_client *c)
280 } 331 }
281 } 332 }
282 333
283 if (c->tagpool) 334 if (c->tagpool) {
335 p9_idpool_put(0, c->tagpool); /* free reserved tag 0 */
284 p9_idpool_destroy(c->tagpool); 336 p9_idpool_destroy(c->tagpool);
337 }
285 338
286 /* free requests associated with tags */ 339 /* free requests associated with tags */
287 for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { 340 for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
@@ -401,14 +454,16 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
401 int ecode; 454 int ecode;
402 char *ename; 455 char *ename;
403 456
404 err = p9pdu_readf(req->rc, c->dotu, "s?d", &ename, &ecode); 457 err = p9pdu_readf(req->rc, c->proto_version, "s?d",
458 &ename, &ecode);
405 if (err) { 459 if (err) {
406 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", 460 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
407 err); 461 err);
408 return err; 462 return err;
409 } 463 }
410 464
411 if (c->dotu) 465 if (p9_is_proto_dotu(c) ||
466 p9_is_proto_dotl(c))
412 err = -ecode; 467 err = -ecode;
413 468
414 if (!err || !IS_ERR_VALUE(err)) 469 if (!err || !IS_ERR_VALUE(err))
@@ -483,7 +538,12 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
483 538
484 P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type); 539 P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type);
485 540
486 if (c->status != Connected) 541 /* we allow for any status other than disconnected */
542 if (c->status == Disconnected)
543 return ERR_PTR(-EIO);
544
545 /* if status is begin_disconnected we allow only clunk request */
546 if ((c->status == BeginDisconnect) && (type != P9_TCLUNK))
487 return ERR_PTR(-EIO); 547 return ERR_PTR(-EIO);
488 548
489 if (signal_pending(current)) { 549 if (signal_pending(current)) {
@@ -506,7 +566,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
506 /* marshall the data */ 566 /* marshall the data */
507 p9pdu_prepare(req->tc, tag, type); 567 p9pdu_prepare(req->tc, tag, type);
508 va_start(ap, fmt); 568 va_start(ap, fmt);
509 err = p9pdu_vwritef(req->tc, c->dotu, fmt, ap); 569 err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap);
510 va_end(ap); 570 va_end(ap);
511 p9pdu_finalize(req->tc); 571 p9pdu_finalize(req->tc);
512 572
@@ -618,14 +678,31 @@ int p9_client_version(struct p9_client *c)
618 char *version; 678 char *version;
619 int msize; 679 int msize;
620 680
621 P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n", 681 P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n",
622 c->msize, c->dotu); 682 c->msize, c->proto_version);
623 req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize, 683
624 c->dotu ? "9P2000.u" : "9P2000"); 684 switch (c->proto_version) {
685 case p9_proto_2000L:
686 req = p9_client_rpc(c, P9_TVERSION, "ds",
687 c->msize, "9P2000.L");
688 break;
689 case p9_proto_2000u:
690 req = p9_client_rpc(c, P9_TVERSION, "ds",
691 c->msize, "9P2000.u");
692 break;
693 case p9_proto_legacy:
694 req = p9_client_rpc(c, P9_TVERSION, "ds",
695 c->msize, "9P2000");
696 break;
697 default:
698 return -EINVAL;
699 break;
700 }
701
625 if (IS_ERR(req)) 702 if (IS_ERR(req))
626 return PTR_ERR(req); 703 return PTR_ERR(req);
627 704
628 err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version); 705 err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version);
629 if (err) { 706 if (err) {
630 P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); 707 P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
631 p9pdu_dump(1, req->rc); 708 p9pdu_dump(1, req->rc);
@@ -633,10 +710,12 @@ int p9_client_version(struct p9_client *c)
633 } 710 }
634 711
635 P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version); 712 P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
636 if (!memcmp(version, "9P2000.u", 8)) 713 if (!strncmp(version, "9P2000.L", 8))
637 c->dotu = 1; 714 c->proto_version = p9_proto_2000L;
638 else if (!memcmp(version, "9P2000", 6)) 715 else if (!strncmp(version, "9P2000.u", 8))
639 c->dotu = 0; 716 c->proto_version = p9_proto_2000u;
717 else if (!strncmp(version, "9P2000", 6))
718 c->proto_version = p9_proto_legacy;
640 else { 719 else {
641 err = -EREMOTEIO; 720 err = -EREMOTEIO;
642 goto error; 721 goto error;
@@ -667,18 +746,12 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
667 clnt->trans = NULL; 746 clnt->trans = NULL;
668 spin_lock_init(&clnt->lock); 747 spin_lock_init(&clnt->lock);
669 INIT_LIST_HEAD(&clnt->fidlist); 748 INIT_LIST_HEAD(&clnt->fidlist);
670 clnt->fidpool = p9_idpool_create();
671 if (IS_ERR(clnt->fidpool)) {
672 err = PTR_ERR(clnt->fidpool);
673 clnt->fidpool = NULL;
674 goto error;
675 }
676 749
677 p9_tag_init(clnt); 750 p9_tag_init(clnt);
678 751
679 err = parse_opts(options, clnt); 752 err = parse_opts(options, clnt);
680 if (err < 0) 753 if (err < 0)
681 goto error; 754 goto free_client;
682 755
683 if (!clnt->trans_mod) 756 if (!clnt->trans_mod)
684 clnt->trans_mod = v9fs_get_default_trans(); 757 clnt->trans_mod = v9fs_get_default_trans();
@@ -687,27 +760,40 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
687 err = -EPROTONOSUPPORT; 760 err = -EPROTONOSUPPORT;
688 P9_DPRINTK(P9_DEBUG_ERROR, 761 P9_DPRINTK(P9_DEBUG_ERROR,
689 "No transport defined or default transport\n"); 762 "No transport defined or default transport\n");
690 goto error; 763 goto free_client;
764 }
765
766 clnt->fidpool = p9_idpool_create();
767 if (IS_ERR(clnt->fidpool)) {
768 err = PTR_ERR(clnt->fidpool);
769 clnt->fidpool = NULL;
770 goto put_trans;
691 } 771 }
692 772
693 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d dotu %d\n", 773 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n",
694 clnt, clnt->trans_mod, clnt->msize, clnt->dotu); 774 clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
695 775
696 err = clnt->trans_mod->create(clnt, dev_name, options); 776 err = clnt->trans_mod->create(clnt, dev_name, options);
697 if (err) 777 if (err)
698 goto error; 778 goto destroy_fidpool;
699 779
700 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) 780 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize)
701 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; 781 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ;
702 782
703 err = p9_client_version(clnt); 783 err = p9_client_version(clnt);
704 if (err) 784 if (err)
705 goto error; 785 goto close_trans;
706 786
707 return clnt; 787 return clnt;
708 788
709error: 789close_trans:
710 p9_client_destroy(clnt); 790 clnt->trans_mod->close(clnt);
791destroy_fidpool:
792 p9_idpool_destroy(clnt->fidpool);
793put_trans:
794 v9fs_put_trans(clnt->trans_mod);
795free_client:
796 kfree(clnt);
711 return ERR_PTR(err); 797 return ERR_PTR(err);
712} 798}
713EXPORT_SYMBOL(p9_client_create); 799EXPORT_SYMBOL(p9_client_create);
@@ -723,8 +809,10 @@ void p9_client_destroy(struct p9_client *clnt)
723 809
724 v9fs_put_trans(clnt->trans_mod); 810 v9fs_put_trans(clnt->trans_mod);
725 811
726 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) 812 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) {
813 printk(KERN_INFO "Found fid %d not clunked\n", fid->fid);
727 p9_fid_destroy(fid); 814 p9_fid_destroy(fid);
815 }
728 816
729 if (clnt->fidpool) 817 if (clnt->fidpool)
730 p9_idpool_destroy(clnt->fidpool); 818 p9_idpool_destroy(clnt->fidpool);
@@ -742,6 +830,13 @@ void p9_client_disconnect(struct p9_client *clnt)
742} 830}
743EXPORT_SYMBOL(p9_client_disconnect); 831EXPORT_SYMBOL(p9_client_disconnect);
744 832
833void p9_client_begin_disconnect(struct p9_client *clnt)
834{
835 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
836 clnt->status = BeginDisconnect;
837}
838EXPORT_SYMBOL(p9_client_begin_disconnect);
839
745struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, 840struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
746 char *uname, u32 n_uname, char *aname) 841 char *uname, u32 n_uname, char *aname)
747{ 842{
@@ -768,7 +863,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
768 goto error; 863 goto error;
769 } 864 }
770 865
771 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); 866 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
772 if (err) { 867 if (err) {
773 p9pdu_dump(1, req->rc); 868 p9pdu_dump(1, req->rc);
774 p9_free_req(clnt, req); 869 p9_free_req(clnt, req);
@@ -817,7 +912,7 @@ p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname)
817 goto error; 912 goto error;
818 } 913 }
819 914
820 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); 915 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
821 if (err) { 916 if (err) {
822 p9pdu_dump(1, req->rc); 917 p9pdu_dump(1, req->rc);
823 p9_free_req(clnt, req); 918 p9_free_req(clnt, req);
@@ -851,6 +946,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
851 int16_t nwqids, count; 946 int16_t nwqids, count;
852 947
853 err = 0; 948 err = 0;
949 wqids = NULL;
854 clnt = oldfid->clnt; 950 clnt = oldfid->clnt;
855 if (clone) { 951 if (clone) {
856 fid = p9_fid_create(clnt); 952 fid = p9_fid_create(clnt);
@@ -875,7 +971,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
875 goto error; 971 goto error;
876 } 972 }
877 973
878 err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids); 974 err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids);
879 if (err) { 975 if (err) {
880 p9pdu_dump(1, req->rc); 976 p9pdu_dump(1, req->rc);
881 p9_free_req(clnt, req); 977 p9_free_req(clnt, req);
@@ -901,9 +997,11 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
901 else 997 else
902 fid->qid = oldfid->qid; 998 fid->qid = oldfid->qid;
903 999
1000 kfree(wqids);
904 return fid; 1001 return fid;
905 1002
906clunk_fid: 1003clunk_fid:
1004 kfree(wqids);
907 p9_client_clunk(fid); 1005 p9_client_clunk(fid);
908 fid = NULL; 1006 fid = NULL;
909 1007
@@ -923,29 +1021,32 @@ int p9_client_open(struct p9_fid *fid, int mode)
923 struct p9_qid qid; 1021 struct p9_qid qid;
924 int iounit; 1022 int iounit;
925 1023
926 P9_DPRINTK(P9_DEBUG_9P, ">>> TOPEN fid %d mode %d\n", fid->fid, mode);
927 err = 0;
928 clnt = fid->clnt; 1024 clnt = fid->clnt;
1025 P9_DPRINTK(P9_DEBUG_9P, ">>> %s fid %d mode %d\n",
1026 p9_is_proto_dotl(clnt) ? "TLOPEN" : "TOPEN", fid->fid, mode);
1027 err = 0;
929 1028
930 if (fid->mode != -1) 1029 if (fid->mode != -1)
931 return -EINVAL; 1030 return -EINVAL;
932 1031
933 req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode); 1032 if (p9_is_proto_dotl(clnt))
1033 req = p9_client_rpc(clnt, P9_TLOPEN, "dd", fid->fid, mode);
1034 else
1035 req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode);
934 if (IS_ERR(req)) { 1036 if (IS_ERR(req)) {
935 err = PTR_ERR(req); 1037 err = PTR_ERR(req);
936 goto error; 1038 goto error;
937 } 1039 }
938 1040
939 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); 1041 err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
940 if (err) { 1042 if (err) {
941 p9pdu_dump(1, req->rc); 1043 p9pdu_dump(1, req->rc);
942 goto free_and_error; 1044 goto free_and_error;
943 } 1045 }
944 1046
945 P9_DPRINTK(P9_DEBUG_9P, "<<< ROPEN qid %x.%llx.%x iounit %x\n", 1047 P9_DPRINTK(P9_DEBUG_9P, "<<< %s qid %x.%llx.%x iounit %x\n",
946 qid.type, 1048 p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN", qid.type,
947 (unsigned long long)qid.path, 1049 (unsigned long long)qid.path, qid.version, iounit);
948 qid.version, iounit);
949 1050
950 fid->mode = mode; 1051 fid->mode = mode;
951 fid->iounit = iounit; 1052 fid->iounit = iounit;
@@ -957,6 +1058,50 @@ error:
957} 1058}
958EXPORT_SYMBOL(p9_client_open); 1059EXPORT_SYMBOL(p9_client_open);
959 1060
1061int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
1062 gid_t gid, struct p9_qid *qid)
1063{
1064 int err = 0;
1065 struct p9_client *clnt;
1066 struct p9_req_t *req;
1067 int iounit;
1068
1069 P9_DPRINTK(P9_DEBUG_9P,
1070 ">>> TLCREATE fid %d name %s flags %d mode %d gid %d\n",
1071 ofid->fid, name, flags, mode, gid);
1072 clnt = ofid->clnt;
1073
1074 if (ofid->mode != -1)
1075 return -EINVAL;
1076
1077 req = p9_client_rpc(clnt, P9_TLCREATE, "dsddd", ofid->fid, name, flags,
1078 mode, gid);
1079 if (IS_ERR(req)) {
1080 err = PTR_ERR(req);
1081 goto error;
1082 }
1083
1084 err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit);
1085 if (err) {
1086 p9pdu_dump(1, req->rc);
1087 goto free_and_error;
1088 }
1089
1090 P9_DPRINTK(P9_DEBUG_9P, "<<< RLCREATE qid %x.%llx.%x iounit %x\n",
1091 qid->type,
1092 (unsigned long long)qid->path,
1093 qid->version, iounit);
1094
1095 ofid->mode = mode;
1096 ofid->iounit = iounit;
1097
1098free_and_error:
1099 p9_free_req(clnt, req);
1100error:
1101 return err;
1102}
1103EXPORT_SYMBOL(p9_client_create_dotl);
1104
960int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, 1105int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
961 char *extension) 1106 char *extension)
962{ 1107{
@@ -981,7 +1126,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
981 goto error; 1126 goto error;
982 } 1127 }
983 1128
984 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); 1129 err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
985 if (err) { 1130 if (err) {
986 p9pdu_dump(1, req->rc); 1131 p9pdu_dump(1, req->rc);
987 goto free_and_error; 1132 goto free_and_error;
@@ -1002,6 +1147,59 @@ error:
1002} 1147}
1003EXPORT_SYMBOL(p9_client_fcreate); 1148EXPORT_SYMBOL(p9_client_fcreate);
1004 1149
1150int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid,
1151 struct p9_qid *qid)
1152{
1153 int err = 0;
1154 struct p9_client *clnt;
1155 struct p9_req_t *req;
1156
1157 P9_DPRINTK(P9_DEBUG_9P, ">>> TSYMLINK dfid %d name %s symtgt %s\n",
1158 dfid->fid, name, symtgt);
1159 clnt = dfid->clnt;
1160
1161 req = p9_client_rpc(clnt, P9_TSYMLINK, "dssd", dfid->fid, name, symtgt,
1162 gid);
1163 if (IS_ERR(req)) {
1164 err = PTR_ERR(req);
1165 goto error;
1166 }
1167
1168 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
1169 if (err) {
1170 p9pdu_dump(1, req->rc);
1171 goto free_and_error;
1172 }
1173
1174 P9_DPRINTK(P9_DEBUG_9P, "<<< RSYMLINK qid %x.%llx.%x\n",
1175 qid->type, (unsigned long long)qid->path, qid->version);
1176
1177free_and_error:
1178 p9_free_req(clnt, req);
1179error:
1180 return err;
1181}
1182EXPORT_SYMBOL(p9_client_symlink);
1183
1184int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname)
1185{
1186 struct p9_client *clnt;
1187 struct p9_req_t *req;
1188
1189 P9_DPRINTK(P9_DEBUG_9P, ">>> TLINK dfid %d oldfid %d newname %s\n",
1190 dfid->fid, oldfid->fid, newname);
1191 clnt = dfid->clnt;
1192 req = p9_client_rpc(clnt, P9_TLINK, "dds", dfid->fid, oldfid->fid,
1193 newname);
1194 if (IS_ERR(req))
1195 return PTR_ERR(req);
1196
1197 P9_DPRINTK(P9_DEBUG_9P, "<<< RLINK\n");
1198 p9_free_req(clnt, req);
1199 return 0;
1200}
1201EXPORT_SYMBOL(p9_client_link);
1202
1005int p9_client_clunk(struct p9_fid *fid) 1203int p9_client_clunk(struct p9_fid *fid)
1006{ 1204{
1007 int err; 1205 int err;
@@ -1047,9 +1245,8 @@ int p9_client_remove(struct p9_fid *fid)
1047 P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid); 1245 P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid);
1048 1246
1049 p9_free_req(clnt, req); 1247 p9_free_req(clnt, req);
1050 p9_fid_destroy(fid);
1051
1052error: 1248error:
1249 p9_fid_destroy(fid);
1053 return err; 1250 return err;
1054} 1251}
1055EXPORT_SYMBOL(p9_client_remove); 1252EXPORT_SYMBOL(p9_client_remove);
@@ -1082,7 +1279,7 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
1082 goto error; 1279 goto error;
1083 } 1280 }
1084 1281
1085 err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr); 1282 err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
1086 if (err) { 1283 if (err) {
1087 p9pdu_dump(1, req->rc); 1284 p9pdu_dump(1, req->rc);
1088 goto free_and_error; 1285 goto free_and_error;
@@ -1143,7 +1340,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
1143 goto error; 1340 goto error;
1144 } 1341 }
1145 1342
1146 err = p9pdu_readf(req->rc, clnt->dotu, "d", &count); 1343 err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count);
1147 if (err) { 1344 if (err) {
1148 p9pdu_dump(1, req->rc); 1345 p9pdu_dump(1, req->rc);
1149 goto free_and_error; 1346 goto free_and_error;
@@ -1183,7 +1380,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
1183 goto error; 1380 goto error;
1184 } 1381 }
1185 1382
1186 err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret); 1383 err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret);
1187 if (err) { 1384 if (err) {
1188 p9pdu_dump(1, req->rc); 1385 p9pdu_dump(1, req->rc);
1189 p9_free_req(clnt, req); 1386 p9_free_req(clnt, req);
@@ -1210,14 +1407,74 @@ error:
1210} 1407}
1211EXPORT_SYMBOL(p9_client_stat); 1408EXPORT_SYMBOL(p9_client_stat);
1212 1409
1213static int p9_client_statsize(struct p9_wstat *wst, int optional) 1410struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
1411 u64 request_mask)
1412{
1413 int err;
1414 struct p9_client *clnt;
1415 struct p9_stat_dotl *ret = kmalloc(sizeof(struct p9_stat_dotl),
1416 GFP_KERNEL);
1417 struct p9_req_t *req;
1418
1419 P9_DPRINTK(P9_DEBUG_9P, ">>> TGETATTR fid %d, request_mask %lld\n",
1420 fid->fid, request_mask);
1421
1422 if (!ret)
1423 return ERR_PTR(-ENOMEM);
1424
1425 err = 0;
1426 clnt = fid->clnt;
1427
1428 req = p9_client_rpc(clnt, P9_TGETATTR, "dq", fid->fid, request_mask);
1429 if (IS_ERR(req)) {
1430 err = PTR_ERR(req);
1431 goto error;
1432 }
1433
1434 err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret);
1435 if (err) {
1436 p9pdu_dump(1, req->rc);
1437 p9_free_req(clnt, req);
1438 goto error;
1439 }
1440
1441 P9_DPRINTK(P9_DEBUG_9P,
1442 "<<< RGETATTR st_result_mask=%lld\n"
1443 "<<< qid=%x.%llx.%x\n"
1444 "<<< st_mode=%8.8x st_nlink=%llu\n"
1445 "<<< st_uid=%d st_gid=%d\n"
1446 "<<< st_rdev=%llx st_size=%llx st_blksize=%llu st_blocks=%llu\n"
1447 "<<< st_atime_sec=%lld st_atime_nsec=%lld\n"
1448 "<<< st_mtime_sec=%lld st_mtime_nsec=%lld\n"
1449 "<<< st_ctime_sec=%lld st_ctime_nsec=%lld\n"
1450 "<<< st_btime_sec=%lld st_btime_nsec=%lld\n"
1451 "<<< st_gen=%lld st_data_version=%lld",
1452 ret->st_result_mask, ret->qid.type, ret->qid.path,
1453 ret->qid.version, ret->st_mode, ret->st_nlink, ret->st_uid,
1454 ret->st_gid, ret->st_rdev, ret->st_size, ret->st_blksize,
1455 ret->st_blocks, ret->st_atime_sec, ret->st_atime_nsec,
1456 ret->st_mtime_sec, ret->st_mtime_nsec, ret->st_ctime_sec,
1457 ret->st_ctime_nsec, ret->st_btime_sec, ret->st_btime_nsec,
1458 ret->st_gen, ret->st_data_version);
1459
1460 p9_free_req(clnt, req);
1461 return ret;
1462
1463error:
1464 kfree(ret);
1465 return ERR_PTR(err);
1466}
1467EXPORT_SYMBOL(p9_client_getattr_dotl);
1468
1469static int p9_client_statsize(struct p9_wstat *wst, int proto_version)
1214{ 1470{
1215 int ret; 1471 int ret;
1216 1472
1473 /* NOTE: size shouldn't include its own length */
1217 /* size[2] type[2] dev[4] qid[13] */ 1474 /* size[2] type[2] dev[4] qid[13] */
1218 /* mode[4] atime[4] mtime[4] length[8]*/ 1475 /* mode[4] atime[4] mtime[4] length[8]*/
1219 /* name[s] uid[s] gid[s] muid[s] */ 1476 /* name[s] uid[s] gid[s] muid[s] */
1220 ret = 2+2+4+13+4+4+4+8+2+2+2+2; 1477 ret = 2+4+13+4+4+4+8+2+2+2+2;
1221 1478
1222 if (wst->name) 1479 if (wst->name)
1223 ret += strlen(wst->name); 1480 ret += strlen(wst->name);
@@ -1228,7 +1485,8 @@ static int p9_client_statsize(struct p9_wstat *wst, int optional)
1228 if (wst->muid) 1485 if (wst->muid)
1229 ret += strlen(wst->muid); 1486 ret += strlen(wst->muid);
1230 1487
1231 if (optional) { 1488 if ((proto_version == p9_proto_2000u) ||
1489 (proto_version == p9_proto_2000L)) {
1232 ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */ 1490 ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */
1233 if (wst->extension) 1491 if (wst->extension)
1234 ret += strlen(wst->extension); 1492 ret += strlen(wst->extension);
@@ -1245,7 +1503,7 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
1245 1503
1246 err = 0; 1504 err = 0;
1247 clnt = fid->clnt; 1505 clnt = fid->clnt;
1248 wst->size = p9_client_statsize(wst, clnt->dotu); 1506 wst->size = p9_client_statsize(wst, clnt->proto_version);
1249 P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid); 1507 P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid);
1250 P9_DPRINTK(P9_DEBUG_9P, 1508 P9_DPRINTK(P9_DEBUG_9P,
1251 " sz=%x type=%x dev=%x qid=%x.%llx.%x\n" 1509 " sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
@@ -1258,7 +1516,7 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
1258 wst->name, wst->uid, wst->gid, wst->muid, wst->extension, 1516 wst->name, wst->uid, wst->gid, wst->muid, wst->extension,
1259 wst->n_uid, wst->n_gid, wst->n_muid); 1517 wst->n_uid, wst->n_gid, wst->n_muid);
1260 1518
1261 req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, wst->size, wst); 1519 req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, wst->size+2, wst);
1262 if (IS_ERR(req)) { 1520 if (IS_ERR(req)) {
1263 err = PTR_ERR(req); 1521 err = PTR_ERR(req);
1264 goto error; 1522 goto error;
@@ -1271,3 +1529,284 @@ error:
1271 return err; 1529 return err;
1272} 1530}
1273EXPORT_SYMBOL(p9_client_wstat); 1531EXPORT_SYMBOL(p9_client_wstat);
1532
1533int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr)
1534{
1535 int err;
1536 struct p9_req_t *req;
1537 struct p9_client *clnt;
1538
1539 err = 0;
1540 clnt = fid->clnt;
1541 P9_DPRINTK(P9_DEBUG_9P, ">>> TSETATTR fid %d\n", fid->fid);
1542 P9_DPRINTK(P9_DEBUG_9P,
1543 " valid=%x mode=%x uid=%d gid=%d size=%lld\n"
1544 " atime_sec=%lld atime_nsec=%lld\n"
1545 " mtime_sec=%lld mtime_nsec=%lld\n",
1546 p9attr->valid, p9attr->mode, p9attr->uid, p9attr->gid,
1547 p9attr->size, p9attr->atime_sec, p9attr->atime_nsec,
1548 p9attr->mtime_sec, p9attr->mtime_nsec);
1549
1550 req = p9_client_rpc(clnt, P9_TSETATTR, "dI", fid->fid, p9attr);
1551
1552 if (IS_ERR(req)) {
1553 err = PTR_ERR(req);
1554 goto error;
1555 }
1556 P9_DPRINTK(P9_DEBUG_9P, "<<< RSETATTR fid %d\n", fid->fid);
1557 p9_free_req(clnt, req);
1558error:
1559 return err;
1560}
1561EXPORT_SYMBOL(p9_client_setattr);
1562
1563int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
1564{
1565 int err;
1566 struct p9_req_t *req;
1567 struct p9_client *clnt;
1568
1569 err = 0;
1570 clnt = fid->clnt;
1571
1572 P9_DPRINTK(P9_DEBUG_9P, ">>> TSTATFS fid %d\n", fid->fid);
1573
1574 req = p9_client_rpc(clnt, P9_TSTATFS, "d", fid->fid);
1575 if (IS_ERR(req)) {
1576 err = PTR_ERR(req);
1577 goto error;
1578 }
1579
1580 err = p9pdu_readf(req->rc, clnt->proto_version, "ddqqqqqqd", &sb->type,
1581 &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail,
1582 &sb->files, &sb->ffree, &sb->fsid, &sb->namelen);
1583 if (err) {
1584 p9pdu_dump(1, req->rc);
1585 p9_free_req(clnt, req);
1586 goto error;
1587 }
1588
1589 P9_DPRINTK(P9_DEBUG_9P, "<<< RSTATFS fid %d type 0x%lx bsize %ld "
1590 "blocks %llu bfree %llu bavail %llu files %llu ffree %llu "
1591 "fsid %llu namelen %ld\n",
1592 fid->fid, (long unsigned int)sb->type, (long int)sb->bsize,
1593 sb->blocks, sb->bfree, sb->bavail, sb->files, sb->ffree,
1594 sb->fsid, (long int)sb->namelen);
1595
1596 p9_free_req(clnt, req);
1597error:
1598 return err;
1599}
1600EXPORT_SYMBOL(p9_client_statfs);
1601
1602int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name)
1603{
1604 int err;
1605 struct p9_req_t *req;
1606 struct p9_client *clnt;
1607
1608 err = 0;
1609 clnt = fid->clnt;
1610
1611 P9_DPRINTK(P9_DEBUG_9P, ">>> TRENAME fid %d newdirfid %d name %s\n",
1612 fid->fid, newdirfid->fid, name);
1613
1614 req = p9_client_rpc(clnt, P9_TRENAME, "dds", fid->fid,
1615 newdirfid->fid, name);
1616 if (IS_ERR(req)) {
1617 err = PTR_ERR(req);
1618 goto error;
1619 }
1620
1621 P9_DPRINTK(P9_DEBUG_9P, "<<< RRENAME fid %d\n", fid->fid);
1622
1623 p9_free_req(clnt, req);
1624error:
1625 return err;
1626}
1627EXPORT_SYMBOL(p9_client_rename);
1628
1629/*
1630 * An xattrwalk without @attr_name gives the fid for the lisxattr namespace
1631 */
1632struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid,
1633 const char *attr_name, u64 *attr_size)
1634{
1635 int err;
1636 struct p9_req_t *req;
1637 struct p9_client *clnt;
1638 struct p9_fid *attr_fid;
1639
1640 err = 0;
1641 clnt = file_fid->clnt;
1642 attr_fid = p9_fid_create(clnt);
1643 if (IS_ERR(attr_fid)) {
1644 err = PTR_ERR(attr_fid);
1645 attr_fid = NULL;
1646 goto error;
1647 }
1648 P9_DPRINTK(P9_DEBUG_9P,
1649 ">>> TXATTRWALK file_fid %d, attr_fid %d name %s\n",
1650 file_fid->fid, attr_fid->fid, attr_name);
1651
1652 req = p9_client_rpc(clnt, P9_TXATTRWALK, "dds",
1653 file_fid->fid, attr_fid->fid, attr_name);
1654 if (IS_ERR(req)) {
1655 err = PTR_ERR(req);
1656 goto error;
1657 }
1658 err = p9pdu_readf(req->rc, clnt->proto_version, "q", attr_size);
1659 if (err) {
1660 p9pdu_dump(1, req->rc);
1661 p9_free_req(clnt, req);
1662 goto clunk_fid;
1663 }
1664 p9_free_req(clnt, req);
1665 P9_DPRINTK(P9_DEBUG_9P, "<<< RXATTRWALK fid %d size %llu\n",
1666 attr_fid->fid, *attr_size);
1667 return attr_fid;
1668clunk_fid:
1669 p9_client_clunk(attr_fid);
1670 attr_fid = NULL;
1671error:
1672 if (attr_fid && (attr_fid != file_fid))
1673 p9_fid_destroy(attr_fid);
1674
1675 return ERR_PTR(err);
1676}
1677EXPORT_SYMBOL_GPL(p9_client_xattrwalk);
1678
1679int p9_client_xattrcreate(struct p9_fid *fid, const char *name,
1680 u64 attr_size, int flags)
1681{
1682 int err;
1683 struct p9_req_t *req;
1684 struct p9_client *clnt;
1685
1686 P9_DPRINTK(P9_DEBUG_9P,
1687 ">>> TXATTRCREATE fid %d name %s size %lld flag %d\n",
1688 fid->fid, name, (long long)attr_size, flags);
1689 err = 0;
1690 clnt = fid->clnt;
1691 req = p9_client_rpc(clnt, P9_TXATTRCREATE, "dsqd",
1692 fid->fid, name, attr_size, flags);
1693 if (IS_ERR(req)) {
1694 err = PTR_ERR(req);
1695 goto error;
1696 }
1697 P9_DPRINTK(P9_DEBUG_9P, "<<< RXATTRCREATE fid %d\n", fid->fid);
1698 p9_free_req(clnt, req);
1699error:
1700 return err;
1701}
1702EXPORT_SYMBOL_GPL(p9_client_xattrcreate);
1703
1704int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
1705{
1706 int err, rsize, total;
1707 struct p9_client *clnt;
1708 struct p9_req_t *req;
1709 char *dataptr;
1710
1711 P9_DPRINTK(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
1712 fid->fid, (long long unsigned) offset, count);
1713
1714 err = 0;
1715 clnt = fid->clnt;
1716 total = 0;
1717
1718 rsize = fid->iounit;
1719 if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ)
1720 rsize = clnt->msize - P9_READDIRHDRSZ;
1721
1722 if (count < rsize)
1723 rsize = count;
1724
1725 req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, offset, rsize);
1726 if (IS_ERR(req)) {
1727 err = PTR_ERR(req);
1728 goto error;
1729 }
1730
1731 err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
1732 if (err) {
1733 p9pdu_dump(1, req->rc);
1734 goto free_and_error;
1735 }
1736
1737 P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count);
1738
1739 if (data)
1740 memmove(data, dataptr, count);
1741
1742 p9_free_req(clnt, req);
1743 return count;
1744
1745free_and_error:
1746 p9_free_req(clnt, req);
1747error:
1748 return err;
1749}
1750EXPORT_SYMBOL(p9_client_readdir);
1751
1752int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode,
1753 dev_t rdev, gid_t gid, struct p9_qid *qid)
1754{
1755 int err;
1756 struct p9_client *clnt;
1757 struct p9_req_t *req;
1758
1759 err = 0;
1760 clnt = fid->clnt;
1761 P9_DPRINTK(P9_DEBUG_9P, ">>> TMKNOD fid %d name %s mode %d major %d "
1762 "minor %d\n", fid->fid, name, mode, MAJOR(rdev), MINOR(rdev));
1763 req = p9_client_rpc(clnt, P9_TMKNOD, "dsdddd", fid->fid, name, mode,
1764 MAJOR(rdev), MINOR(rdev), gid);
1765 if (IS_ERR(req))
1766 return PTR_ERR(req);
1767
1768 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
1769 if (err) {
1770 p9pdu_dump(1, req->rc);
1771 goto error;
1772 }
1773 P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type,
1774 (unsigned long long)qid->path, qid->version);
1775
1776error:
1777 p9_free_req(clnt, req);
1778 return err;
1779
1780}
1781EXPORT_SYMBOL(p9_client_mknod_dotl);
1782
1783int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
1784 gid_t gid, struct p9_qid *qid)
1785{
1786 int err;
1787 struct p9_client *clnt;
1788 struct p9_req_t *req;
1789
1790 err = 0;
1791 clnt = fid->clnt;
1792 P9_DPRINTK(P9_DEBUG_9P, ">>> TMKDIR fid %d name %s mode %d gid %d\n",
1793 fid->fid, name, mode, gid);
1794 req = p9_client_rpc(clnt, P9_TMKDIR, "dsdd", fid->fid, name, mode,
1795 gid);
1796 if (IS_ERR(req))
1797 return PTR_ERR(req);
1798
1799 err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
1800 if (err) {
1801 p9pdu_dump(1, req->rc);
1802 goto error;
1803 }
1804 P9_DPRINTK(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type,
1805 (unsigned long long)qid->path, qid->version);
1806
1807error:
1808 p9_free_req(clnt, req);
1809 return err;
1810
1811}
1812EXPORT_SYMBOL(p9_client_mkdir_dotl);