diff options
Diffstat (limited to 'net/9p/client.c')
-rw-r--r-- | net/9p/client.c | 377 |
1 files changed, 260 insertions, 117 deletions
diff --git a/net/9p/client.c b/net/9p/client.c index 9eb72505308f..9e3b0e640da1 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -61,13 +61,13 @@ static const match_table_t tokens = { | |||
61 | 61 | ||
62 | inline int p9_is_proto_dotl(struct p9_client *clnt) | 62 | inline int p9_is_proto_dotl(struct p9_client *clnt) |
63 | { | 63 | { |
64 | return (clnt->proto_version == p9_proto_2000L); | 64 | return clnt->proto_version == p9_proto_2000L; |
65 | } | 65 | } |
66 | EXPORT_SYMBOL(p9_is_proto_dotl); | 66 | EXPORT_SYMBOL(p9_is_proto_dotl); |
67 | 67 | ||
68 | inline int p9_is_proto_dotu(struct p9_client *clnt) | 68 | inline int p9_is_proto_dotu(struct p9_client *clnt) |
69 | { | 69 | { |
70 | return (clnt->proto_version == p9_proto_2000u); | 70 | return clnt->proto_version == p9_proto_2000u; |
71 | } | 71 | } |
72 | EXPORT_SYMBOL(p9_is_proto_dotu); | 72 | EXPORT_SYMBOL(p9_is_proto_dotu); |
73 | 73 | ||
@@ -92,9 +92,6 @@ static int get_protocol_version(const substring_t *name) | |||
92 | return version; | 92 | return version; |
93 | } | 93 | } |
94 | 94 | ||
95 | static struct p9_req_t * | ||
96 | p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); | ||
97 | |||
98 | /** | 95 | /** |
99 | * parse_options - parse mount options into client structure | 96 | * parse_options - parse mount options into client structure |
100 | * @opts: options string passed from mount | 97 | * @opts: options string passed from mount |
@@ -178,7 +175,7 @@ free_and_return: | |||
178 | * @tag: numeric id for transaction | 175 | * @tag: numeric id for transaction |
179 | * | 176 | * |
180 | * this is a simple array lookup, but will grow the | 177 | * this is a simple array lookup, but will grow the |
181 | * request_slots as necessary to accomodate transaction | 178 | * request_slots as necessary to accommodate transaction |
182 | * ids which did not previously have a slot. | 179 | * ids which did not previously have a slot. |
183 | * | 180 | * |
184 | * this code relies on the client spinlock to manage locks, its | 181 | * this code relies on the client spinlock to manage locks, its |
@@ -223,16 +220,29 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | |||
223 | 220 | ||
224 | req = &c->reqs[row][col]; | 221 | req = &c->reqs[row][col]; |
225 | if (!req->tc) { | 222 | if (!req->tc) { |
226 | req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); | 223 | req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_NOFS); |
227 | if (!req->wq) { | 224 | if (!req->wq) { |
228 | printk(KERN_ERR "Couldn't grow tag array\n"); | 225 | printk(KERN_ERR "Couldn't grow tag array\n"); |
229 | return ERR_PTR(-ENOMEM); | 226 | return ERR_PTR(-ENOMEM); |
230 | } | 227 | } |
231 | init_waitqueue_head(req->wq); | 228 | init_waitqueue_head(req->wq); |
232 | req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, | 229 | if ((c->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == |
233 | GFP_KERNEL); | 230 | P9_TRANS_PREF_PAYLOAD_SEP) { |
234 | req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, | 231 | int alloc_msize = min(c->msize, 4096); |
235 | GFP_KERNEL); | 232 | req->tc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, |
233 | GFP_NOFS); | ||
234 | req->tc->capacity = alloc_msize; | ||
235 | req->rc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, | ||
236 | GFP_NOFS); | ||
237 | req->rc->capacity = alloc_msize; | ||
238 | } else { | ||
239 | req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, | ||
240 | GFP_NOFS); | ||
241 | req->tc->capacity = c->msize; | ||
242 | req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, | ||
243 | GFP_NOFS); | ||
244 | req->rc->capacity = c->msize; | ||
245 | } | ||
236 | if ((!req->tc) || (!req->rc)) { | 246 | if ((!req->tc) || (!req->rc)) { |
237 | printk(KERN_ERR "Couldn't grow tag array\n"); | 247 | printk(KERN_ERR "Couldn't grow tag array\n"); |
238 | kfree(req->tc); | 248 | kfree(req->tc); |
@@ -243,9 +253,7 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | |||
243 | return ERR_PTR(-ENOMEM); | 253 | return ERR_PTR(-ENOMEM); |
244 | } | 254 | } |
245 | req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall); | 255 | req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall); |
246 | req->tc->capacity = c->msize; | ||
247 | req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall); | 256 | req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall); |
248 | req->rc->capacity = c->msize; | ||
249 | } | 257 | } |
250 | 258 | ||
251 | p9pdu_reset(req->tc); | 259 | p9pdu_reset(req->tc); |
@@ -296,12 +304,13 @@ static int p9_tag_init(struct p9_client *c) | |||
296 | c->tagpool = p9_idpool_create(); | 304 | c->tagpool = p9_idpool_create(); |
297 | if (IS_ERR(c->tagpool)) { | 305 | if (IS_ERR(c->tagpool)) { |
298 | err = PTR_ERR(c->tagpool); | 306 | err = PTR_ERR(c->tagpool); |
299 | c->tagpool = NULL; | ||
300 | goto error; | 307 | goto error; |
301 | } | 308 | } |
302 | 309 | err = p9_idpool_get(c->tagpool); /* reserve tag 0 */ | |
303 | p9_idpool_get(c->tagpool); /* reserve tag 0 */ | 310 | if (err < 0) { |
304 | 311 | p9_idpool_destroy(c->tagpool); | |
312 | goto error; | ||
313 | } | ||
305 | c->max_tag = 0; | 314 | c->max_tag = 0; |
306 | error: | 315 | error: |
307 | return err; | 316 | return err; |
@@ -443,6 +452,7 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) | |||
443 | { | 452 | { |
444 | int8_t type; | 453 | int8_t type; |
445 | int err; | 454 | int err; |
455 | int ecode; | ||
446 | 456 | ||
447 | err = p9_parse_header(req->rc, NULL, &type, NULL, 0); | 457 | err = p9_parse_header(req->rc, NULL, &type, NULL, 0); |
448 | if (err) { | 458 | if (err) { |
@@ -450,40 +460,71 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) | |||
450 | return err; | 460 | return err; |
451 | } | 461 | } |
452 | 462 | ||
453 | if (type == P9_RERROR) { | 463 | if (type != P9_RERROR && type != P9_RLERROR) |
454 | int ecode; | 464 | return 0; |
465 | |||
466 | if (!p9_is_proto_dotl(c)) { | ||
455 | char *ename; | 467 | char *ename; |
456 | 468 | ||
457 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", | 469 | if (req->tc->pbuf_size) { |
458 | &ename, &ecode); | 470 | /* Handle user buffers */ |
459 | if (err) { | 471 | size_t len = req->rc->size - req->rc->offset; |
460 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", | 472 | if (req->tc->pubuf) { |
461 | err); | 473 | /* User Buffer */ |
462 | return err; | 474 | err = copy_from_user( |
475 | &req->rc->sdata[req->rc->offset], | ||
476 | req->tc->pubuf, len); | ||
477 | if (err) { | ||
478 | err = -EFAULT; | ||
479 | goto out_err; | ||
480 | } | ||
481 | } else { | ||
482 | /* Kernel Buffer */ | ||
483 | memmove(&req->rc->sdata[req->rc->offset], | ||
484 | req->tc->pkbuf, len); | ||
485 | } | ||
463 | } | 486 | } |
487 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", | ||
488 | &ename, &ecode); | ||
489 | if (err) | ||
490 | goto out_err; | ||
464 | 491 | ||
465 | if (p9_is_proto_dotu(c) || | 492 | if (p9_is_proto_dotu(c)) |
466 | p9_is_proto_dotl(c)) | ||
467 | err = -ecode; | 493 | err = -ecode; |
468 | 494 | ||
469 | if (!err || !IS_ERR_VALUE(err)) | 495 | if (!err || !IS_ERR_VALUE(err)) { |
470 | err = p9_errstr2errno(ename, strlen(ename)); | 496 | err = p9_errstr2errno(ename, strlen(ename)); |
471 | 497 | ||
472 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); | 498 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, |
499 | ename); | ||
473 | 500 | ||
474 | kfree(ename); | 501 | kfree(ename); |
475 | } else | 502 | } |
476 | err = 0; | 503 | } else { |
504 | err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode); | ||
505 | err = -ecode; | ||
506 | |||
507 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); | ||
508 | } | ||
509 | |||
510 | |||
511 | return err; | ||
512 | |||
513 | out_err: | ||
514 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", err); | ||
477 | 515 | ||
478 | return err; | 516 | return err; |
479 | } | 517 | } |
480 | 518 | ||
519 | static struct p9_req_t * | ||
520 | p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); | ||
521 | |||
481 | /** | 522 | /** |
482 | * p9_client_flush - flush (cancel) a request | 523 | * p9_client_flush - flush (cancel) a request |
483 | * @c: client state | 524 | * @c: client state |
484 | * @oldreq: request to cancel | 525 | * @oldreq: request to cancel |
485 | * | 526 | * |
486 | * This sents a flush for a particular requests and links | 527 | * This sents a flush for a particular request and links |
487 | * the flush request to the original request. The current | 528 | * the flush request to the original request. The current |
488 | * code only supports a single flush request although the protocol | 529 | * code only supports a single flush request although the protocol |
489 | * allows for multiple flush requests to be sent for a single request. | 530 | * allows for multiple flush requests to be sent for a single request. |
@@ -568,11 +609,14 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) | |||
568 | va_start(ap, fmt); | 609 | va_start(ap, fmt); |
569 | err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap); | 610 | err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap); |
570 | va_end(ap); | 611 | va_end(ap); |
612 | if (err) | ||
613 | goto reterr; | ||
571 | p9pdu_finalize(req->tc); | 614 | p9pdu_finalize(req->tc); |
572 | 615 | ||
573 | err = c->trans_mod->request(c, req); | 616 | err = c->trans_mod->request(c, req); |
574 | if (err < 0) { | 617 | if (err < 0) { |
575 | c->status = Disconnected; | 618 | if (err != -ERESTARTSYS && err != -EFAULT) |
619 | c->status = Disconnected; | ||
576 | goto reterr; | 620 | goto reterr; |
577 | } | 621 | } |
578 | 622 | ||
@@ -671,7 +715,7 @@ static void p9_fid_destroy(struct p9_fid *fid) | |||
671 | kfree(fid); | 715 | kfree(fid); |
672 | } | 716 | } |
673 | 717 | ||
674 | int p9_client_version(struct p9_client *c) | 718 | static int p9_client_version(struct p9_client *c) |
675 | { | 719 | { |
676 | int err = 0; | 720 | int err = 0; |
677 | struct p9_req_t *req; | 721 | struct p9_req_t *req; |
@@ -730,7 +774,6 @@ error: | |||
730 | 774 | ||
731 | return err; | 775 | return err; |
732 | } | 776 | } |
733 | EXPORT_SYMBOL(p9_client_version); | ||
734 | 777 | ||
735 | struct p9_client *p9_client_create(const char *dev_name, char *options) | 778 | struct p9_client *p9_client_create(const char *dev_name, char *options) |
736 | { | 779 | { |
@@ -747,11 +790,13 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) | |||
747 | spin_lock_init(&clnt->lock); | 790 | spin_lock_init(&clnt->lock); |
748 | INIT_LIST_HEAD(&clnt->fidlist); | 791 | INIT_LIST_HEAD(&clnt->fidlist); |
749 | 792 | ||
750 | p9_tag_init(clnt); | 793 | err = p9_tag_init(clnt); |
794 | if (err < 0) | ||
795 | goto free_client; | ||
751 | 796 | ||
752 | err = parse_opts(options, clnt); | 797 | err = parse_opts(options, clnt); |
753 | if (err < 0) | 798 | if (err < 0) |
754 | goto free_client; | 799 | goto destroy_tagpool; |
755 | 800 | ||
756 | if (!clnt->trans_mod) | 801 | if (!clnt->trans_mod) |
757 | clnt->trans_mod = v9fs_get_default_trans(); | 802 | clnt->trans_mod = v9fs_get_default_trans(); |
@@ -760,13 +805,12 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) | |||
760 | err = -EPROTONOSUPPORT; | 805 | err = -EPROTONOSUPPORT; |
761 | P9_DPRINTK(P9_DEBUG_ERROR, | 806 | P9_DPRINTK(P9_DEBUG_ERROR, |
762 | "No transport defined or default transport\n"); | 807 | "No transport defined or default transport\n"); |
763 | goto free_client; | 808 | goto destroy_tagpool; |
764 | } | 809 | } |
765 | 810 | ||
766 | clnt->fidpool = p9_idpool_create(); | 811 | clnt->fidpool = p9_idpool_create(); |
767 | if (IS_ERR(clnt->fidpool)) { | 812 | if (IS_ERR(clnt->fidpool)) { |
768 | err = PTR_ERR(clnt->fidpool); | 813 | err = PTR_ERR(clnt->fidpool); |
769 | clnt->fidpool = NULL; | ||
770 | goto put_trans; | 814 | goto put_trans; |
771 | } | 815 | } |
772 | 816 | ||
@@ -792,6 +836,8 @@ destroy_fidpool: | |||
792 | p9_idpool_destroy(clnt->fidpool); | 836 | p9_idpool_destroy(clnt->fidpool); |
793 | put_trans: | 837 | put_trans: |
794 | v9fs_put_trans(clnt->trans_mod); | 838 | v9fs_put_trans(clnt->trans_mod); |
839 | destroy_tagpool: | ||
840 | p9_idpool_destroy(clnt->tagpool); | ||
795 | free_client: | 841 | free_client: |
796 | kfree(clnt); | 842 | kfree(clnt); |
797 | return ERR_PTR(err); | 843 | return ERR_PTR(err); |
@@ -887,63 +933,15 @@ error: | |||
887 | } | 933 | } |
888 | EXPORT_SYMBOL(p9_client_attach); | 934 | EXPORT_SYMBOL(p9_client_attach); |
889 | 935 | ||
890 | struct p9_fid * | 936 | struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname, |
891 | p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname) | 937 | char **wnames, int clone) |
892 | { | ||
893 | int err; | ||
894 | struct p9_req_t *req; | ||
895 | struct p9_qid qid; | ||
896 | struct p9_fid *afid; | ||
897 | |||
898 | P9_DPRINTK(P9_DEBUG_9P, ">>> TAUTH uname %s aname %s\n", uname, aname); | ||
899 | err = 0; | ||
900 | |||
901 | afid = p9_fid_create(clnt); | ||
902 | if (IS_ERR(afid)) { | ||
903 | err = PTR_ERR(afid); | ||
904 | afid = NULL; | ||
905 | goto error; | ||
906 | } | ||
907 | |||
908 | req = p9_client_rpc(clnt, P9_TAUTH, "dss?d", | ||
909 | afid ? afid->fid : P9_NOFID, uname, aname, n_uname); | ||
910 | if (IS_ERR(req)) { | ||
911 | err = PTR_ERR(req); | ||
912 | goto error; | ||
913 | } | ||
914 | |||
915 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid); | ||
916 | if (err) { | ||
917 | p9pdu_dump(1, req->rc); | ||
918 | p9_free_req(clnt, req); | ||
919 | goto error; | ||
920 | } | ||
921 | |||
922 | P9_DPRINTK(P9_DEBUG_9P, "<<< RAUTH qid %x.%llx.%x\n", | ||
923 | qid.type, | ||
924 | (unsigned long long)qid.path, | ||
925 | qid.version); | ||
926 | |||
927 | memmove(&afid->qid, &qid, sizeof(struct p9_qid)); | ||
928 | p9_free_req(clnt, req); | ||
929 | return afid; | ||
930 | |||
931 | error: | ||
932 | if (afid) | ||
933 | p9_fid_destroy(afid); | ||
934 | return ERR_PTR(err); | ||
935 | } | ||
936 | EXPORT_SYMBOL(p9_client_auth); | ||
937 | |||
938 | struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, | ||
939 | int clone) | ||
940 | { | 938 | { |
941 | int err; | 939 | int err; |
942 | struct p9_client *clnt; | 940 | struct p9_client *clnt; |
943 | struct p9_fid *fid; | 941 | struct p9_fid *fid; |
944 | struct p9_qid *wqids; | 942 | struct p9_qid *wqids; |
945 | struct p9_req_t *req; | 943 | struct p9_req_t *req; |
946 | int16_t nwqids, count; | 944 | uint16_t nwqids, count; |
947 | 945 | ||
948 | err = 0; | 946 | err = 0; |
949 | wqids = NULL; | 947 | wqids = NULL; |
@@ -961,7 +959,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, | |||
961 | fid = oldfid; | 959 | fid = oldfid; |
962 | 960 | ||
963 | 961 | ||
964 | P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n", | 962 | P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %ud wname[0] %s\n", |
965 | oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL); | 963 | oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL); |
966 | 964 | ||
967 | req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid, | 965 | req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid, |
@@ -1200,12 +1198,44 @@ int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname) | |||
1200 | } | 1198 | } |
1201 | EXPORT_SYMBOL(p9_client_link); | 1199 | EXPORT_SYMBOL(p9_client_link); |
1202 | 1200 | ||
1201 | int p9_client_fsync(struct p9_fid *fid, int datasync) | ||
1202 | { | ||
1203 | int err; | ||
1204 | struct p9_client *clnt; | ||
1205 | struct p9_req_t *req; | ||
1206 | |||
1207 | P9_DPRINTK(P9_DEBUG_9P, ">>> TFSYNC fid %d datasync:%d\n", | ||
1208 | fid->fid, datasync); | ||
1209 | err = 0; | ||
1210 | clnt = fid->clnt; | ||
1211 | |||
1212 | req = p9_client_rpc(clnt, P9_TFSYNC, "dd", fid->fid, datasync); | ||
1213 | if (IS_ERR(req)) { | ||
1214 | err = PTR_ERR(req); | ||
1215 | goto error; | ||
1216 | } | ||
1217 | |||
1218 | P9_DPRINTK(P9_DEBUG_9P, "<<< RFSYNC fid %d\n", fid->fid); | ||
1219 | |||
1220 | p9_free_req(clnt, req); | ||
1221 | |||
1222 | error: | ||
1223 | return err; | ||
1224 | } | ||
1225 | EXPORT_SYMBOL(p9_client_fsync); | ||
1226 | |||
1203 | int p9_client_clunk(struct p9_fid *fid) | 1227 | int p9_client_clunk(struct p9_fid *fid) |
1204 | { | 1228 | { |
1205 | int err; | 1229 | int err; |
1206 | struct p9_client *clnt; | 1230 | struct p9_client *clnt; |
1207 | struct p9_req_t *req; | 1231 | struct p9_req_t *req; |
1208 | 1232 | ||
1233 | if (!fid) { | ||
1234 | P9_EPRINTK(KERN_WARNING, "Trying to clunk with NULL fid\n"); | ||
1235 | dump_stack(); | ||
1236 | return 0; | ||
1237 | } | ||
1238 | |||
1209 | P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid); | 1239 | P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid); |
1210 | err = 0; | 1240 | err = 0; |
1211 | clnt = fid->clnt; | 1241 | clnt = fid->clnt; |
@@ -1255,7 +1285,7 @@ int | |||
1255 | p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | 1285 | p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, |
1256 | u32 count) | 1286 | u32 count) |
1257 | { | 1287 | { |
1258 | int err, rsize, total; | 1288 | int err, rsize; |
1259 | struct p9_client *clnt; | 1289 | struct p9_client *clnt; |
1260 | struct p9_req_t *req; | 1290 | struct p9_req_t *req; |
1261 | char *dataptr; | 1291 | char *dataptr; |
@@ -1264,7 +1294,6 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
1264 | (long long unsigned) offset, count); | 1294 | (long long unsigned) offset, count); |
1265 | err = 0; | 1295 | err = 0; |
1266 | clnt = fid->clnt; | 1296 | clnt = fid->clnt; |
1267 | total = 0; | ||
1268 | 1297 | ||
1269 | rsize = fid->iounit; | 1298 | rsize = fid->iounit; |
1270 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) | 1299 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) |
@@ -1273,7 +1302,15 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
1273 | if (count < rsize) | 1302 | if (count < rsize) |
1274 | rsize = count; | 1303 | rsize = count; |
1275 | 1304 | ||
1276 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize); | 1305 | /* Don't bother zerocopy for small IO (< 1024) */ |
1306 | if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == | ||
1307 | P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) { | ||
1308 | req = p9_client_rpc(clnt, P9_TREAD, "dqE", fid->fid, offset, | ||
1309 | rsize, data, udata); | ||
1310 | } else { | ||
1311 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, | ||
1312 | rsize); | ||
1313 | } | ||
1277 | if (IS_ERR(req)) { | 1314 | if (IS_ERR(req)) { |
1278 | err = PTR_ERR(req); | 1315 | err = PTR_ERR(req); |
1279 | goto error; | 1316 | goto error; |
@@ -1287,18 +1324,17 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
1287 | 1324 | ||
1288 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); | 1325 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); |
1289 | 1326 | ||
1290 | if (data) { | 1327 | if (!req->tc->pbuf_size) { |
1291 | memmove(data, dataptr, count); | 1328 | if (data) { |
1292 | } | 1329 | memmove(data, dataptr, count); |
1293 | 1330 | } else { | |
1294 | if (udata) { | 1331 | err = copy_to_user(udata, dataptr, count); |
1295 | err = copy_to_user(udata, dataptr, count); | 1332 | if (err) { |
1296 | if (err) { | 1333 | err = -EFAULT; |
1297 | err = -EFAULT; | 1334 | goto free_and_error; |
1298 | goto free_and_error; | 1335 | } |
1299 | } | 1336 | } |
1300 | } | 1337 | } |
1301 | |||
1302 | p9_free_req(clnt, req); | 1338 | p9_free_req(clnt, req); |
1303 | return count; | 1339 | return count; |
1304 | 1340 | ||
@@ -1313,7 +1349,7 @@ int | |||
1313 | p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | 1349 | p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, |
1314 | u64 offset, u32 count) | 1350 | u64 offset, u32 count) |
1315 | { | 1351 | { |
1316 | int err, rsize, total; | 1352 | int err, rsize; |
1317 | struct p9_client *clnt; | 1353 | struct p9_client *clnt; |
1318 | struct p9_req_t *req; | 1354 | struct p9_req_t *req; |
1319 | 1355 | ||
@@ -1321,7 +1357,6 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | |||
1321 | fid->fid, (long long unsigned) offset, count); | 1357 | fid->fid, (long long unsigned) offset, count); |
1322 | err = 0; | 1358 | err = 0; |
1323 | clnt = fid->clnt; | 1359 | clnt = fid->clnt; |
1324 | total = 0; | ||
1325 | 1360 | ||
1326 | rsize = fid->iounit; | 1361 | rsize = fid->iounit; |
1327 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) | 1362 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) |
@@ -1329,12 +1364,21 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | |||
1329 | 1364 | ||
1330 | if (count < rsize) | 1365 | if (count < rsize) |
1331 | rsize = count; | 1366 | rsize = count; |
1332 | if (data) | 1367 | |
1333 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset, | 1368 | /* Don't bother zerocopy form small IO (< 1024) */ |
1334 | rsize, data); | 1369 | if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == |
1335 | else | 1370 | P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) { |
1336 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset, | 1371 | req = p9_client_rpc(clnt, P9_TWRITE, "dqE", fid->fid, offset, |
1337 | rsize, udata); | 1372 | rsize, data, udata); |
1373 | } else { | ||
1374 | |||
1375 | if (data) | ||
1376 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, | ||
1377 | offset, rsize, data); | ||
1378 | else | ||
1379 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, | ||
1380 | offset, rsize, udata); | ||
1381 | } | ||
1338 | if (IS_ERR(req)) { | 1382 | if (IS_ERR(req)) { |
1339 | err = PTR_ERR(req); | 1383 | err = PTR_ERR(req); |
1340 | goto error; | 1384 | goto error; |
@@ -1703,7 +1747,7 @@ EXPORT_SYMBOL_GPL(p9_client_xattrcreate); | |||
1703 | 1747 | ||
1704 | int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | 1748 | int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) |
1705 | { | 1749 | { |
1706 | int err, rsize, total; | 1750 | int err, rsize; |
1707 | struct p9_client *clnt; | 1751 | struct p9_client *clnt; |
1708 | struct p9_req_t *req; | 1752 | struct p9_req_t *req; |
1709 | char *dataptr; | 1753 | char *dataptr; |
@@ -1713,7 +1757,6 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
1713 | 1757 | ||
1714 | err = 0; | 1758 | err = 0; |
1715 | clnt = fid->clnt; | 1759 | clnt = fid->clnt; |
1716 | total = 0; | ||
1717 | 1760 | ||
1718 | rsize = fid->iounit; | 1761 | rsize = fid->iounit; |
1719 | if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ) | 1762 | if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ) |
@@ -1722,7 +1765,14 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
1722 | if (count < rsize) | 1765 | if (count < rsize) |
1723 | rsize = count; | 1766 | rsize = count; |
1724 | 1767 | ||
1725 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, offset, rsize); | 1768 | if ((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == |
1769 | P9_TRANS_PREF_PAYLOAD_SEP) { | ||
1770 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqF", fid->fid, | ||
1771 | offset, rsize, data); | ||
1772 | } else { | ||
1773 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, | ||
1774 | offset, rsize); | ||
1775 | } | ||
1726 | if (IS_ERR(req)) { | 1776 | if (IS_ERR(req)) { |
1727 | err = PTR_ERR(req); | 1777 | err = PTR_ERR(req); |
1728 | goto error; | 1778 | goto error; |
@@ -1736,7 +1786,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
1736 | 1786 | ||
1737 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); | 1787 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); |
1738 | 1788 | ||
1739 | if (data) | 1789 | if (!req->tc->pbuf_size && data) |
1740 | memmove(data, dataptr, count); | 1790 | memmove(data, dataptr, count); |
1741 | 1791 | ||
1742 | p9_free_req(clnt, req); | 1792 | p9_free_req(clnt, req); |
@@ -1810,3 +1860,96 @@ error: | |||
1810 | 1860 | ||
1811 | } | 1861 | } |
1812 | EXPORT_SYMBOL(p9_client_mkdir_dotl); | 1862 | EXPORT_SYMBOL(p9_client_mkdir_dotl); |
1863 | |||
1864 | int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status) | ||
1865 | { | ||
1866 | int err; | ||
1867 | struct p9_client *clnt; | ||
1868 | struct p9_req_t *req; | ||
1869 | |||
1870 | err = 0; | ||
1871 | clnt = fid->clnt; | ||
1872 | P9_DPRINTK(P9_DEBUG_9P, ">>> TLOCK fid %d type %i flags %d " | ||
1873 | "start %lld length %lld proc_id %d client_id %s\n", | ||
1874 | fid->fid, flock->type, flock->flags, flock->start, | ||
1875 | flock->length, flock->proc_id, flock->client_id); | ||
1876 | |||
1877 | req = p9_client_rpc(clnt, P9_TLOCK, "dbdqqds", fid->fid, flock->type, | ||
1878 | flock->flags, flock->start, flock->length, | ||
1879 | flock->proc_id, flock->client_id); | ||
1880 | |||
1881 | if (IS_ERR(req)) | ||
1882 | return PTR_ERR(req); | ||
1883 | |||
1884 | err = p9pdu_readf(req->rc, clnt->proto_version, "b", status); | ||
1885 | if (err) { | ||
1886 | p9pdu_dump(1, req->rc); | ||
1887 | goto error; | ||
1888 | } | ||
1889 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status); | ||
1890 | error: | ||
1891 | p9_free_req(clnt, req); | ||
1892 | return err; | ||
1893 | |||
1894 | } | ||
1895 | EXPORT_SYMBOL(p9_client_lock_dotl); | ||
1896 | |||
1897 | int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock) | ||
1898 | { | ||
1899 | int err; | ||
1900 | struct p9_client *clnt; | ||
1901 | struct p9_req_t *req; | ||
1902 | |||
1903 | err = 0; | ||
1904 | clnt = fid->clnt; | ||
1905 | P9_DPRINTK(P9_DEBUG_9P, ">>> TGETLOCK fid %d, type %i start %lld " | ||
1906 | "length %lld proc_id %d client_id %s\n", fid->fid, glock->type, | ||
1907 | glock->start, glock->length, glock->proc_id, glock->client_id); | ||
1908 | |||
1909 | req = p9_client_rpc(clnt, P9_TGETLOCK, "dbqqds", fid->fid, glock->type, | ||
1910 | glock->start, glock->length, glock->proc_id, glock->client_id); | ||
1911 | |||
1912 | if (IS_ERR(req)) | ||
1913 | return PTR_ERR(req); | ||
1914 | |||
1915 | err = p9pdu_readf(req->rc, clnt->proto_version, "bqqds", &glock->type, | ||
1916 | &glock->start, &glock->length, &glock->proc_id, | ||
1917 | &glock->client_id); | ||
1918 | if (err) { | ||
1919 | p9pdu_dump(1, req->rc); | ||
1920 | goto error; | ||
1921 | } | ||
1922 | P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld " | ||
1923 | "proc_id %d client_id %s\n", glock->type, glock->start, | ||
1924 | glock->length, glock->proc_id, glock->client_id); | ||
1925 | error: | ||
1926 | p9_free_req(clnt, req); | ||
1927 | return err; | ||
1928 | } | ||
1929 | EXPORT_SYMBOL(p9_client_getlock_dotl); | ||
1930 | |||
1931 | int p9_client_readlink(struct p9_fid *fid, char **target) | ||
1932 | { | ||
1933 | int err; | ||
1934 | struct p9_client *clnt; | ||
1935 | struct p9_req_t *req; | ||
1936 | |||
1937 | err = 0; | ||
1938 | clnt = fid->clnt; | ||
1939 | P9_DPRINTK(P9_DEBUG_9P, ">>> TREADLINK fid %d\n", fid->fid); | ||
1940 | |||
1941 | req = p9_client_rpc(clnt, P9_TREADLINK, "d", fid->fid); | ||
1942 | if (IS_ERR(req)) | ||
1943 | return PTR_ERR(req); | ||
1944 | |||
1945 | err = p9pdu_readf(req->rc, clnt->proto_version, "s", target); | ||
1946 | if (err) { | ||
1947 | p9pdu_dump(1, req->rc); | ||
1948 | goto error; | ||
1949 | } | ||
1950 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target); | ||
1951 | error: | ||
1952 | p9_free_req(clnt, req); | ||
1953 | return err; | ||
1954 | } | ||
1955 | EXPORT_SYMBOL(p9_client_readlink); | ||