diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-26 08:20:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-26 08:20:53 -0400 |
commit | e33bae14fd8da449d735552d78e6dd33ece0458c (patch) | |
tree | 048c062c47f7bfdb0ea8ad19c5b5849a58ff3022 /net | |
parent | 7670c7010c7b367ca40c3aba02afb36149764a6e (diff) | |
parent | 14211d026dad4641d4dffd7a4c520bcaa8fd4a65 (diff) |
Merge branch 'for-linus' of git://github.com/ericvh/linux
* 'for-linus' of git://github.com/ericvh/linux:
9p: fix 9p.txt to advertise msize instead of maxdata
net/9p: Convert net/9p protocol dumps to tracepoints
fs/9p: change an int to unsigned int
fs/9p: Cleanup option parsing in 9p
9p: move dereference after NULL check
fs/9p: inode file operation is properly initialized init_special_inode
fs/9p: Update zero-copy implementation in 9p
Diffstat (limited to 'net')
-rw-r--r-- | net/9p/client.c | 469 | ||||
-rw-r--r-- | net/9p/protocol.c | 99 | ||||
-rw-r--r-- | net/9p/protocol.h | 4 | ||||
-rw-r--r-- | net/9p/trans_common.c | 53 | ||||
-rw-r--r-- | net/9p/trans_common.h | 21 | ||||
-rw-r--r-- | net/9p/trans_virtio.c | 319 |
6 files changed, 554 insertions, 411 deletions
diff --git a/net/9p/client.c b/net/9p/client.c index 0505a03c374c..854ca7a911c4 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -38,6 +38,9 @@ | |||
38 | #include <net/9p/transport.h> | 38 | #include <net/9p/transport.h> |
39 | #include "protocol.h" | 39 | #include "protocol.h" |
40 | 40 | ||
41 | #define CREATE_TRACE_POINTS | ||
42 | #include <trace/events/9p.h> | ||
43 | |||
41 | /* | 44 | /* |
42 | * Client Option Parsing (code inspired by NFS code) | 45 | * Client Option Parsing (code inspired by NFS code) |
43 | * - a little lazy - parse all client options | 46 | * - a little lazy - parse all client options |
@@ -123,21 +126,19 @@ static int parse_opts(char *opts, struct p9_client *clnt) | |||
123 | options = tmp_options; | 126 | options = tmp_options; |
124 | 127 | ||
125 | while ((p = strsep(&options, ",")) != NULL) { | 128 | while ((p = strsep(&options, ",")) != NULL) { |
126 | int token; | 129 | int token, r; |
127 | if (!*p) | 130 | if (!*p) |
128 | continue; | 131 | continue; |
129 | token = match_token(p, tokens, args); | 132 | token = match_token(p, tokens, args); |
130 | if (token < Opt_trans) { | 133 | switch (token) { |
131 | int r = match_int(&args[0], &option); | 134 | case Opt_msize: |
135 | r = match_int(&args[0], &option); | ||
132 | if (r < 0) { | 136 | if (r < 0) { |
133 | P9_DPRINTK(P9_DEBUG_ERROR, | 137 | P9_DPRINTK(P9_DEBUG_ERROR, |
134 | "integer field, but no integer?\n"); | 138 | "integer field, but no integer?\n"); |
135 | ret = r; | 139 | ret = r; |
136 | continue; | 140 | continue; |
137 | } | 141 | } |
138 | } | ||
139 | switch (token) { | ||
140 | case Opt_msize: | ||
141 | clnt->msize = option; | 142 | clnt->msize = option; |
142 | break; | 143 | break; |
143 | case Opt_trans: | 144 | case Opt_trans: |
@@ -203,11 +204,13 @@ free_and_return: | |||
203 | * | 204 | * |
204 | */ | 205 | */ |
205 | 206 | ||
206 | static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | 207 | static struct p9_req_t * |
208 | p9_tag_alloc(struct p9_client *c, u16 tag, unsigned int max_size) | ||
207 | { | 209 | { |
208 | unsigned long flags; | 210 | unsigned long flags; |
209 | int row, col; | 211 | int row, col; |
210 | struct p9_req_t *req; | 212 | struct p9_req_t *req; |
213 | int alloc_msize = min(c->msize, max_size); | ||
211 | 214 | ||
212 | /* This looks up the original request by tag so we know which | 215 | /* This looks up the original request by tag so we know which |
213 | * buffer to read the data into */ | 216 | * buffer to read the data into */ |
@@ -245,23 +248,10 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | |||
245 | return ERR_PTR(-ENOMEM); | 248 | return ERR_PTR(-ENOMEM); |
246 | } | 249 | } |
247 | init_waitqueue_head(req->wq); | 250 | init_waitqueue_head(req->wq); |
248 | if ((c->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == | 251 | req->tc = kmalloc(sizeof(struct p9_fcall) + alloc_msize, |
249 | P9_TRANS_PREF_PAYLOAD_SEP) { | 252 | GFP_NOFS); |
250 | int alloc_msize = min(c->msize, 4096); | 253 | req->rc = kmalloc(sizeof(struct p9_fcall) + alloc_msize, |
251 | req->tc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, | 254 | GFP_NOFS); |
252 | GFP_NOFS); | ||
253 | req->tc->capacity = alloc_msize; | ||
254 | req->rc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, | ||
255 | GFP_NOFS); | ||
256 | req->rc->capacity = alloc_msize; | ||
257 | } else { | ||
258 | req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, | ||
259 | GFP_NOFS); | ||
260 | req->tc->capacity = c->msize; | ||
261 | req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, | ||
262 | GFP_NOFS); | ||
263 | req->rc->capacity = c->msize; | ||
264 | } | ||
265 | if ((!req->tc) || (!req->rc)) { | 255 | if ((!req->tc) || (!req->rc)) { |
266 | printk(KERN_ERR "Couldn't grow tag array\n"); | 256 | printk(KERN_ERR "Couldn't grow tag array\n"); |
267 | kfree(req->tc); | 257 | kfree(req->tc); |
@@ -271,6 +261,8 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | |||
271 | req->wq = NULL; | 261 | req->wq = NULL; |
272 | return ERR_PTR(-ENOMEM); | 262 | return ERR_PTR(-ENOMEM); |
273 | } | 263 | } |
264 | req->tc->capacity = alloc_msize; | ||
265 | req->rc->capacity = alloc_msize; | ||
274 | req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall); | 266 | req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall); |
275 | req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall); | 267 | req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall); |
276 | } | 268 | } |
@@ -475,37 +467,22 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) | |||
475 | int ecode; | 467 | int ecode; |
476 | 468 | ||
477 | err = p9_parse_header(req->rc, NULL, &type, NULL, 0); | 469 | err = p9_parse_header(req->rc, NULL, &type, NULL, 0); |
470 | /* | ||
471 | * dump the response from server | ||
472 | * This should be after check errors which poplulate pdu_fcall. | ||
473 | */ | ||
474 | trace_9p_protocol_dump(c, req->rc); | ||
478 | if (err) { | 475 | if (err) { |
479 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err); | 476 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err); |
480 | return err; | 477 | return err; |
481 | } | 478 | } |
482 | |||
483 | if (type != P9_RERROR && type != P9_RLERROR) | 479 | if (type != P9_RERROR && type != P9_RLERROR) |
484 | return 0; | 480 | return 0; |
485 | 481 | ||
486 | if (!p9_is_proto_dotl(c)) { | 482 | if (!p9_is_proto_dotl(c)) { |
487 | char *ename; | 483 | char *ename; |
488 | |||
489 | if (req->tc->pbuf_size) { | ||
490 | /* Handle user buffers */ | ||
491 | size_t len = req->rc->size - req->rc->offset; | ||
492 | if (req->tc->pubuf) { | ||
493 | /* User Buffer */ | ||
494 | err = copy_from_user( | ||
495 | &req->rc->sdata[req->rc->offset], | ||
496 | req->tc->pubuf, len); | ||
497 | if (err) { | ||
498 | err = -EFAULT; | ||
499 | goto out_err; | ||
500 | } | ||
501 | } else { | ||
502 | /* Kernel Buffer */ | ||
503 | memmove(&req->rc->sdata[req->rc->offset], | ||
504 | req->tc->pkbuf, len); | ||
505 | } | ||
506 | } | ||
507 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", | 484 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", |
508 | &ename, &ecode); | 485 | &ename, &ecode); |
509 | if (err) | 486 | if (err) |
510 | goto out_err; | 487 | goto out_err; |
511 | 488 | ||
@@ -515,11 +492,10 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) | |||
515 | if (!err || !IS_ERR_VALUE(err)) { | 492 | if (!err || !IS_ERR_VALUE(err)) { |
516 | err = p9_errstr2errno(ename, strlen(ename)); | 493 | err = p9_errstr2errno(ename, strlen(ename)); |
517 | 494 | ||
518 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, | 495 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", |
519 | ename); | 496 | -ecode, ename); |
520 | |||
521 | kfree(ename); | ||
522 | } | 497 | } |
498 | kfree(ename); | ||
523 | } else { | 499 | } else { |
524 | err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode); | 500 | err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode); |
525 | err = -ecode; | 501 | err = -ecode; |
@@ -527,7 +503,6 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) | |||
527 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); | 503 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); |
528 | } | 504 | } |
529 | 505 | ||
530 | |||
531 | return err; | 506 | return err; |
532 | 507 | ||
533 | out_err: | 508 | out_err: |
@@ -536,6 +511,115 @@ out_err: | |||
536 | return err; | 511 | return err; |
537 | } | 512 | } |
538 | 513 | ||
514 | /** | ||
515 | * p9_check_zc_errors - check 9p packet for error return and process it | ||
516 | * @c: current client instance | ||
517 | * @req: request to parse and check for error conditions | ||
518 | * @in_hdrlen: Size of response protocol buffer. | ||
519 | * | ||
520 | * returns error code if one is discovered, otherwise returns 0 | ||
521 | * | ||
522 | * this will have to be more complicated if we have multiple | ||
523 | * error packet types | ||
524 | */ | ||
525 | |||
526 | static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req, | ||
527 | char *uidata, int in_hdrlen, int kern_buf) | ||
528 | { | ||
529 | int err; | ||
530 | int ecode; | ||
531 | int8_t type; | ||
532 | char *ename = NULL; | ||
533 | |||
534 | err = p9_parse_header(req->rc, NULL, &type, NULL, 0); | ||
535 | /* | ||
536 | * dump the response from server | ||
537 | * This should be after parse_header which poplulate pdu_fcall. | ||
538 | */ | ||
539 | trace_9p_protocol_dump(c, req->rc); | ||
540 | if (err) { | ||
541 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err); | ||
542 | return err; | ||
543 | } | ||
544 | |||
545 | if (type != P9_RERROR && type != P9_RLERROR) | ||
546 | return 0; | ||
547 | |||
548 | if (!p9_is_proto_dotl(c)) { | ||
549 | /* Error is reported in string format */ | ||
550 | uint16_t len; | ||
551 | /* 7 = header size for RERROR, 2 is the size of string len; */ | ||
552 | int inline_len = in_hdrlen - (7 + 2); | ||
553 | |||
554 | /* Read the size of error string */ | ||
555 | err = p9pdu_readf(req->rc, c->proto_version, "w", &len); | ||
556 | if (err) | ||
557 | goto out_err; | ||
558 | |||
559 | ename = kmalloc(len + 1, GFP_NOFS); | ||
560 | if (!ename) { | ||
561 | err = -ENOMEM; | ||
562 | goto out_err; | ||
563 | } | ||
564 | if (len <= inline_len) { | ||
565 | /* We have error in protocol buffer itself */ | ||
566 | if (pdu_read(req->rc, ename, len)) { | ||
567 | err = -EFAULT; | ||
568 | goto out_free; | ||
569 | |||
570 | } | ||
571 | } else { | ||
572 | /* | ||
573 | * Part of the data is in user space buffer. | ||
574 | */ | ||
575 | if (pdu_read(req->rc, ename, inline_len)) { | ||
576 | err = -EFAULT; | ||
577 | goto out_free; | ||
578 | |||
579 | } | ||
580 | if (kern_buf) { | ||
581 | memcpy(ename + inline_len, uidata, | ||
582 | len - inline_len); | ||
583 | } else { | ||
584 | err = copy_from_user(ename + inline_len, | ||
585 | uidata, len - inline_len); | ||
586 | if (err) { | ||
587 | err = -EFAULT; | ||
588 | goto out_free; | ||
589 | } | ||
590 | } | ||
591 | } | ||
592 | ename[len] = 0; | ||
593 | if (p9_is_proto_dotu(c)) { | ||
594 | /* For dotu we also have error code */ | ||
595 | err = p9pdu_readf(req->rc, | ||
596 | c->proto_version, "d", &ecode); | ||
597 | if (err) | ||
598 | goto out_free; | ||
599 | err = -ecode; | ||
600 | } | ||
601 | if (!err || !IS_ERR_VALUE(err)) { | ||
602 | err = p9_errstr2errno(ename, strlen(ename)); | ||
603 | |||
604 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", | ||
605 | -ecode, ename); | ||
606 | } | ||
607 | kfree(ename); | ||
608 | } else { | ||
609 | err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode); | ||
610 | err = -ecode; | ||
611 | |||
612 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); | ||
613 | } | ||
614 | return err; | ||
615 | |||
616 | out_free: | ||
617 | kfree(ename); | ||
618 | out_err: | ||
619 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", err); | ||
620 | return err; | ||
621 | } | ||
622 | |||
539 | static struct p9_req_t * | 623 | static struct p9_req_t * |
540 | p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); | 624 | p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); |
541 | 625 | ||
@@ -579,23 +663,12 @@ static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq) | |||
579 | return 0; | 663 | return 0; |
580 | } | 664 | } |
581 | 665 | ||
582 | /** | 666 | static struct p9_req_t *p9_client_prepare_req(struct p9_client *c, |
583 | * p9_client_rpc - issue a request and wait for a response | 667 | int8_t type, int req_size, |
584 | * @c: client session | 668 | const char *fmt, va_list ap) |
585 | * @type: type of request | ||
586 | * @fmt: protocol format string (see protocol.c) | ||
587 | * | ||
588 | * Returns request structure (which client must free using p9_free_req) | ||
589 | */ | ||
590 | |||
591 | static struct p9_req_t * | ||
592 | p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) | ||
593 | { | 669 | { |
594 | va_list ap; | ||
595 | int tag, err; | 670 | int tag, err; |
596 | struct p9_req_t *req; | 671 | struct p9_req_t *req; |
597 | unsigned long flags; | ||
598 | int sigpending; | ||
599 | 672 | ||
600 | P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type); | 673 | P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type); |
601 | 674 | ||
@@ -607,12 +680,6 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) | |||
607 | if ((c->status == BeginDisconnect) && (type != P9_TCLUNK)) | 680 | if ((c->status == BeginDisconnect) && (type != P9_TCLUNK)) |
608 | return ERR_PTR(-EIO); | 681 | return ERR_PTR(-EIO); |
609 | 682 | ||
610 | if (signal_pending(current)) { | ||
611 | sigpending = 1; | ||
612 | clear_thread_flag(TIF_SIGPENDING); | ||
613 | } else | ||
614 | sigpending = 0; | ||
615 | |||
616 | tag = P9_NOTAG; | 683 | tag = P9_NOTAG; |
617 | if (type != P9_TVERSION) { | 684 | if (type != P9_TVERSION) { |
618 | tag = p9_idpool_get(c->tagpool); | 685 | tag = p9_idpool_get(c->tagpool); |
@@ -620,18 +687,51 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) | |||
620 | return ERR_PTR(-ENOMEM); | 687 | return ERR_PTR(-ENOMEM); |
621 | } | 688 | } |
622 | 689 | ||
623 | req = p9_tag_alloc(c, tag); | 690 | req = p9_tag_alloc(c, tag, req_size); |
624 | if (IS_ERR(req)) | 691 | if (IS_ERR(req)) |
625 | return req; | 692 | return req; |
626 | 693 | ||
627 | /* marshall the data */ | 694 | /* marshall the data */ |
628 | p9pdu_prepare(req->tc, tag, type); | 695 | p9pdu_prepare(req->tc, tag, type); |
629 | va_start(ap, fmt); | ||
630 | err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap); | 696 | err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap); |
631 | va_end(ap); | ||
632 | if (err) | 697 | if (err) |
633 | goto reterr; | 698 | goto reterr; |
634 | p9pdu_finalize(req->tc); | 699 | p9pdu_finalize(c, req->tc); |
700 | trace_9p_client_req(c, type, tag); | ||
701 | return req; | ||
702 | reterr: | ||
703 | p9_free_req(c, req); | ||
704 | return ERR_PTR(err); | ||
705 | } | ||
706 | |||
707 | /** | ||
708 | * p9_client_rpc - issue a request and wait for a response | ||
709 | * @c: client session | ||
710 | * @type: type of request | ||
711 | * @fmt: protocol format string (see protocol.c) | ||
712 | * | ||
713 | * Returns request structure (which client must free using p9_free_req) | ||
714 | */ | ||
715 | |||
716 | static struct p9_req_t * | ||
717 | p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) | ||
718 | { | ||
719 | va_list ap; | ||
720 | int sigpending, err; | ||
721 | unsigned long flags; | ||
722 | struct p9_req_t *req; | ||
723 | |||
724 | va_start(ap, fmt); | ||
725 | req = p9_client_prepare_req(c, type, c->msize, fmt, ap); | ||
726 | va_end(ap); | ||
727 | if (IS_ERR(req)) | ||
728 | return req; | ||
729 | |||
730 | if (signal_pending(current)) { | ||
731 | sigpending = 1; | ||
732 | clear_thread_flag(TIF_SIGPENDING); | ||
733 | } else | ||
734 | sigpending = 0; | ||
635 | 735 | ||
636 | err = c->trans_mod->request(c, req); | 736 | err = c->trans_mod->request(c, req); |
637 | if (err < 0) { | 737 | if (err < 0) { |
@@ -639,18 +739,14 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) | |||
639 | c->status = Disconnected; | 739 | c->status = Disconnected; |
640 | goto reterr; | 740 | goto reterr; |
641 | } | 741 | } |
642 | 742 | /* Wait for the response */ | |
643 | P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d\n", req->wq, tag); | ||
644 | err = wait_event_interruptible(*req->wq, | 743 | err = wait_event_interruptible(*req->wq, |
645 | req->status >= REQ_STATUS_RCVD); | 744 | req->status >= REQ_STATUS_RCVD); |
646 | P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d returned %d\n", | ||
647 | req->wq, tag, err); | ||
648 | 745 | ||
649 | if (req->status == REQ_STATUS_ERROR) { | 746 | if (req->status == REQ_STATUS_ERROR) { |
650 | P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); | 747 | P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); |
651 | err = req->t_err; | 748 | err = req->t_err; |
652 | } | 749 | } |
653 | |||
654 | if ((err == -ERESTARTSYS) && (c->status == Connected)) { | 750 | if ((err == -ERESTARTSYS) && (c->status == Connected)) { |
655 | P9_DPRINTK(P9_DEBUG_MUX, "flushing\n"); | 751 | P9_DPRINTK(P9_DEBUG_MUX, "flushing\n"); |
656 | sigpending = 1; | 752 | sigpending = 1; |
@@ -663,25 +759,102 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) | |||
663 | if (req->status == REQ_STATUS_RCVD) | 759 | if (req->status == REQ_STATUS_RCVD) |
664 | err = 0; | 760 | err = 0; |
665 | } | 761 | } |
666 | |||
667 | if (sigpending) { | 762 | if (sigpending) { |
668 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 763 | spin_lock_irqsave(¤t->sighand->siglock, flags); |
669 | recalc_sigpending(); | 764 | recalc_sigpending(); |
670 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 765 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); |
671 | } | 766 | } |
672 | |||
673 | if (err < 0) | 767 | if (err < 0) |
674 | goto reterr; | 768 | goto reterr; |
675 | 769 | ||
676 | err = p9_check_errors(c, req); | 770 | err = p9_check_errors(c, req); |
677 | if (!err) { | 771 | trace_9p_client_res(c, type, req->rc->tag, err); |
678 | P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d\n", c, type); | 772 | if (!err) |
773 | return req; | ||
774 | reterr: | ||
775 | p9_free_req(c, req); | ||
776 | return ERR_PTR(err); | ||
777 | } | ||
778 | |||
779 | /** | ||
780 | * p9_client_zc_rpc - issue a request and wait for a response | ||
781 | * @c: client session | ||
782 | * @type: type of request | ||
783 | * @uidata: user bffer that should be ued for zero copy read | ||
784 | * @uodata: user buffer that shoud be user for zero copy write | ||
785 | * @inlen: read buffer size | ||
786 | * @olen: write buffer size | ||
787 | * @hdrlen: reader header size, This is the size of response protocol data | ||
788 | * @fmt: protocol format string (see protocol.c) | ||
789 | * | ||
790 | * Returns request structure (which client must free using p9_free_req) | ||
791 | */ | ||
792 | static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, | ||
793 | char *uidata, char *uodata, | ||
794 | int inlen, int olen, int in_hdrlen, | ||
795 | int kern_buf, const char *fmt, ...) | ||
796 | { | ||
797 | va_list ap; | ||
798 | int sigpending, err; | ||
799 | unsigned long flags; | ||
800 | struct p9_req_t *req; | ||
801 | |||
802 | va_start(ap, fmt); | ||
803 | /* | ||
804 | * We allocate a inline protocol data of only 4k bytes. | ||
805 | * The actual content is passed in zero-copy fashion. | ||
806 | */ | ||
807 | req = p9_client_prepare_req(c, type, P9_ZC_HDR_SZ, fmt, ap); | ||
808 | va_end(ap); | ||
809 | if (IS_ERR(req)) | ||
679 | return req; | 810 | return req; |
811 | |||
812 | if (signal_pending(current)) { | ||
813 | sigpending = 1; | ||
814 | clear_thread_flag(TIF_SIGPENDING); | ||
815 | } else | ||
816 | sigpending = 0; | ||
817 | |||
818 | /* If we are called with KERNEL_DS force kern_buf */ | ||
819 | if (segment_eq(get_fs(), KERNEL_DS)) | ||
820 | kern_buf = 1; | ||
821 | |||
822 | err = c->trans_mod->zc_request(c, req, uidata, uodata, | ||
823 | inlen, olen, in_hdrlen, kern_buf); | ||
824 | if (err < 0) { | ||
825 | if (err == -EIO) | ||
826 | c->status = Disconnected; | ||
827 | goto reterr; | ||
828 | } | ||
829 | if (req->status == REQ_STATUS_ERROR) { | ||
830 | P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); | ||
831 | err = req->t_err; | ||
832 | } | ||
833 | if ((err == -ERESTARTSYS) && (c->status == Connected)) { | ||
834 | P9_DPRINTK(P9_DEBUG_MUX, "flushing\n"); | ||
835 | sigpending = 1; | ||
836 | clear_thread_flag(TIF_SIGPENDING); | ||
837 | |||
838 | if (c->trans_mod->cancel(c, req)) | ||
839 | p9_client_flush(c, req); | ||
840 | |||
841 | /* if we received the response anyway, don't signal error */ | ||
842 | if (req->status == REQ_STATUS_RCVD) | ||
843 | err = 0; | ||
844 | } | ||
845 | if (sigpending) { | ||
846 | spin_lock_irqsave(¤t->sighand->siglock, flags); | ||
847 | recalc_sigpending(); | ||
848 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
680 | } | 849 | } |
850 | if (err < 0) | ||
851 | goto reterr; | ||
681 | 852 | ||
853 | err = p9_check_zc_errors(c, req, uidata, in_hdrlen, kern_buf); | ||
854 | trace_9p_client_res(c, type, req->rc->tag, err); | ||
855 | if (!err) | ||
856 | return req; | ||
682 | reterr: | 857 | reterr: |
683 | P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d error: %d\n", c, type, | ||
684 | err); | ||
685 | p9_free_req(c, req); | 858 | p9_free_req(c, req); |
686 | return ERR_PTR(err); | 859 | return ERR_PTR(err); |
687 | } | 860 | } |
@@ -769,7 +942,7 @@ static int p9_client_version(struct p9_client *c) | |||
769 | err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version); | 942 | err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version); |
770 | if (err) { | 943 | if (err) { |
771 | P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); | 944 | P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); |
772 | P9_DUMP_PKT(1, req->rc); | 945 | trace_9p_protocol_dump(c, req->rc); |
773 | goto error; | 946 | goto error; |
774 | } | 947 | } |
775 | 948 | ||
@@ -906,15 +1079,14 @@ EXPORT_SYMBOL(p9_client_begin_disconnect); | |||
906 | struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, | 1079 | struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, |
907 | char *uname, u32 n_uname, char *aname) | 1080 | char *uname, u32 n_uname, char *aname) |
908 | { | 1081 | { |
909 | int err; | 1082 | int err = 0; |
910 | struct p9_req_t *req; | 1083 | struct p9_req_t *req; |
911 | struct p9_fid *fid; | 1084 | struct p9_fid *fid; |
912 | struct p9_qid qid; | 1085 | struct p9_qid qid; |
913 | 1086 | ||
914 | P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n", | ||
915 | afid ? afid->fid : -1, uname, aname); | ||
916 | err = 0; | ||
917 | 1087 | ||
1088 | P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n", | ||
1089 | afid ? afid->fid : -1, uname, aname); | ||
918 | fid = p9_fid_create(clnt); | 1090 | fid = p9_fid_create(clnt); |
919 | if (IS_ERR(fid)) { | 1091 | if (IS_ERR(fid)) { |
920 | err = PTR_ERR(fid); | 1092 | err = PTR_ERR(fid); |
@@ -931,7 +1103,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, | |||
931 | 1103 | ||
932 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid); | 1104 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid); |
933 | if (err) { | 1105 | if (err) { |
934 | P9_DUMP_PKT(1, req->rc); | 1106 | trace_9p_protocol_dump(clnt, req->rc); |
935 | p9_free_req(clnt, req); | 1107 | p9_free_req(clnt, req); |
936 | goto error; | 1108 | goto error; |
937 | } | 1109 | } |
@@ -991,7 +1163,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname, | |||
991 | 1163 | ||
992 | err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids); | 1164 | err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids); |
993 | if (err) { | 1165 | if (err) { |
994 | P9_DUMP_PKT(1, req->rc); | 1166 | trace_9p_protocol_dump(clnt, req->rc); |
995 | p9_free_req(clnt, req); | 1167 | p9_free_req(clnt, req); |
996 | goto clunk_fid; | 1168 | goto clunk_fid; |
997 | } | 1169 | } |
@@ -1058,7 +1230,7 @@ int p9_client_open(struct p9_fid *fid, int mode) | |||
1058 | 1230 | ||
1059 | err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit); | 1231 | err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit); |
1060 | if (err) { | 1232 | if (err) { |
1061 | P9_DUMP_PKT(1, req->rc); | 1233 | trace_9p_protocol_dump(clnt, req->rc); |
1062 | goto free_and_error; | 1234 | goto free_and_error; |
1063 | } | 1235 | } |
1064 | 1236 | ||
@@ -1101,7 +1273,7 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, | |||
1101 | 1273 | ||
1102 | err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit); | 1274 | err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit); |
1103 | if (err) { | 1275 | if (err) { |
1104 | P9_DUMP_PKT(1, req->rc); | 1276 | trace_9p_protocol_dump(clnt, req->rc); |
1105 | goto free_and_error; | 1277 | goto free_and_error; |
1106 | } | 1278 | } |
1107 | 1279 | ||
@@ -1146,7 +1318,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, | |||
1146 | 1318 | ||
1147 | err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit); | 1319 | err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit); |
1148 | if (err) { | 1320 | if (err) { |
1149 | P9_DUMP_PKT(1, req->rc); | 1321 | trace_9p_protocol_dump(clnt, req->rc); |
1150 | goto free_and_error; | 1322 | goto free_and_error; |
1151 | } | 1323 | } |
1152 | 1324 | ||
@@ -1185,7 +1357,7 @@ int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid, | |||
1185 | 1357 | ||
1186 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); | 1358 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); |
1187 | if (err) { | 1359 | if (err) { |
1188 | P9_DUMP_PKT(1, req->rc); | 1360 | trace_9p_protocol_dump(clnt, req->rc); |
1189 | goto free_and_error; | 1361 | goto free_and_error; |
1190 | } | 1362 | } |
1191 | 1363 | ||
@@ -1330,13 +1502,15 @@ int | |||
1330 | p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | 1502 | p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, |
1331 | u32 count) | 1503 | u32 count) |
1332 | { | 1504 | { |
1333 | int err, rsize; | ||
1334 | struct p9_client *clnt; | ||
1335 | struct p9_req_t *req; | ||
1336 | char *dataptr; | 1505 | char *dataptr; |
1506 | int kernel_buf = 0; | ||
1507 | struct p9_req_t *req; | ||
1508 | struct p9_client *clnt; | ||
1509 | int err, rsize, non_zc = 0; | ||
1510 | |||
1337 | 1511 | ||
1338 | P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", fid->fid, | 1512 | P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", |
1339 | (long long unsigned) offset, count); | 1513 | fid->fid, (long long unsigned) offset, count); |
1340 | err = 0; | 1514 | err = 0; |
1341 | clnt = fid->clnt; | 1515 | clnt = fid->clnt; |
1342 | 1516 | ||
@@ -1348,13 +1522,24 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
1348 | rsize = count; | 1522 | rsize = count; |
1349 | 1523 | ||
1350 | /* Don't bother zerocopy for small IO (< 1024) */ | 1524 | /* Don't bother zerocopy for small IO (< 1024) */ |
1351 | if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == | 1525 | if (clnt->trans_mod->zc_request && rsize > 1024) { |
1352 | P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) { | 1526 | char *indata; |
1353 | req = p9_client_rpc(clnt, P9_TREAD, "dqE", fid->fid, offset, | 1527 | if (data) { |
1354 | rsize, data, udata); | 1528 | kernel_buf = 1; |
1529 | indata = data; | ||
1530 | } else | ||
1531 | indata = (char *)udata; | ||
1532 | /* | ||
1533 | * response header len is 11 | ||
1534 | * PDU Header(7) + IO Size (4) | ||
1535 | */ | ||
1536 | req = p9_client_zc_rpc(clnt, P9_TREAD, indata, NULL, rsize, 0, | ||
1537 | 11, kernel_buf, "dqd", fid->fid, | ||
1538 | offset, rsize); | ||
1355 | } else { | 1539 | } else { |
1540 | non_zc = 1; | ||
1356 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, | 1541 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, |
1357 | rsize); | 1542 | rsize); |
1358 | } | 1543 | } |
1359 | if (IS_ERR(req)) { | 1544 | if (IS_ERR(req)) { |
1360 | err = PTR_ERR(req); | 1545 | err = PTR_ERR(req); |
@@ -1363,14 +1548,13 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
1363 | 1548 | ||
1364 | err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); | 1549 | err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); |
1365 | if (err) { | 1550 | if (err) { |
1366 | P9_DUMP_PKT(1, req->rc); | 1551 | trace_9p_protocol_dump(clnt, req->rc); |
1367 | goto free_and_error; | 1552 | goto free_and_error; |
1368 | } | 1553 | } |
1369 | 1554 | ||
1370 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); | 1555 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); |
1371 | P9_DUMP_PKT(1, req->rc); | ||
1372 | 1556 | ||
1373 | if (!req->tc->pbuf_size) { | 1557 | if (non_zc) { |
1374 | if (data) { | 1558 | if (data) { |
1375 | memmove(data, dataptr, count); | 1559 | memmove(data, dataptr, count); |
1376 | } else { | 1560 | } else { |
@@ -1396,6 +1580,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | |||
1396 | u64 offset, u32 count) | 1580 | u64 offset, u32 count) |
1397 | { | 1581 | { |
1398 | int err, rsize; | 1582 | int err, rsize; |
1583 | int kernel_buf = 0; | ||
1399 | struct p9_client *clnt; | 1584 | struct p9_client *clnt; |
1400 | struct p9_req_t *req; | 1585 | struct p9_req_t *req; |
1401 | 1586 | ||
@@ -1411,19 +1596,24 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | |||
1411 | if (count < rsize) | 1596 | if (count < rsize) |
1412 | rsize = count; | 1597 | rsize = count; |
1413 | 1598 | ||
1414 | /* Don't bother zerocopy form small IO (< 1024) */ | 1599 | /* Don't bother zerocopy for small IO (< 1024) */ |
1415 | if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == | 1600 | if (clnt->trans_mod->zc_request && rsize > 1024) { |
1416 | P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) { | 1601 | char *odata; |
1417 | req = p9_client_rpc(clnt, P9_TWRITE, "dqE", fid->fid, offset, | 1602 | if (data) { |
1418 | rsize, data, udata); | 1603 | kernel_buf = 1; |
1604 | odata = data; | ||
1605 | } else | ||
1606 | odata = (char *)udata; | ||
1607 | req = p9_client_zc_rpc(clnt, P9_TWRITE, NULL, odata, 0, rsize, | ||
1608 | P9_ZC_HDR_SZ, kernel_buf, "dqd", | ||
1609 | fid->fid, offset, rsize); | ||
1419 | } else { | 1610 | } else { |
1420 | |||
1421 | if (data) | 1611 | if (data) |
1422 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, | 1612 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, |
1423 | offset, rsize, data); | 1613 | offset, rsize, data); |
1424 | else | 1614 | else |
1425 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, | 1615 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, |
1426 | offset, rsize, udata); | 1616 | offset, rsize, udata); |
1427 | } | 1617 | } |
1428 | if (IS_ERR(req)) { | 1618 | if (IS_ERR(req)) { |
1429 | err = PTR_ERR(req); | 1619 | err = PTR_ERR(req); |
@@ -1432,7 +1622,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | |||
1432 | 1622 | ||
1433 | err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count); | 1623 | err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count); |
1434 | if (err) { | 1624 | if (err) { |
1435 | P9_DUMP_PKT(1, req->rc); | 1625 | trace_9p_protocol_dump(clnt, req->rc); |
1436 | goto free_and_error; | 1626 | goto free_and_error; |
1437 | } | 1627 | } |
1438 | 1628 | ||
@@ -1472,7 +1662,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid) | |||
1472 | 1662 | ||
1473 | err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret); | 1663 | err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret); |
1474 | if (err) { | 1664 | if (err) { |
1475 | P9_DUMP_PKT(1, req->rc); | 1665 | trace_9p_protocol_dump(clnt, req->rc); |
1476 | p9_free_req(clnt, req); | 1666 | p9_free_req(clnt, req); |
1477 | goto error; | 1667 | goto error; |
1478 | } | 1668 | } |
@@ -1523,7 +1713,7 @@ struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid, | |||
1523 | 1713 | ||
1524 | err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret); | 1714 | err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret); |
1525 | if (err) { | 1715 | if (err) { |
1526 | P9_DUMP_PKT(1, req->rc); | 1716 | trace_9p_protocol_dump(clnt, req->rc); |
1527 | p9_free_req(clnt, req); | 1717 | p9_free_req(clnt, req); |
1528 | goto error; | 1718 | goto error; |
1529 | } | 1719 | } |
@@ -1671,7 +1861,7 @@ int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb) | |||
1671 | &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail, | 1861 | &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail, |
1672 | &sb->files, &sb->ffree, &sb->fsid, &sb->namelen); | 1862 | &sb->files, &sb->ffree, &sb->fsid, &sb->namelen); |
1673 | if (err) { | 1863 | if (err) { |
1674 | P9_DUMP_PKT(1, req->rc); | 1864 | trace_9p_protocol_dump(clnt, req->rc); |
1675 | p9_free_req(clnt, req); | 1865 | p9_free_req(clnt, req); |
1676 | goto error; | 1866 | goto error; |
1677 | } | 1867 | } |
@@ -1778,7 +1968,7 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid, | |||
1778 | } | 1968 | } |
1779 | err = p9pdu_readf(req->rc, clnt->proto_version, "q", attr_size); | 1969 | err = p9pdu_readf(req->rc, clnt->proto_version, "q", attr_size); |
1780 | if (err) { | 1970 | if (err) { |
1781 | P9_DUMP_PKT(1, req->rc); | 1971 | trace_9p_protocol_dump(clnt, req->rc); |
1782 | p9_free_req(clnt, req); | 1972 | p9_free_req(clnt, req); |
1783 | goto clunk_fid; | 1973 | goto clunk_fid; |
1784 | } | 1974 | } |
@@ -1824,7 +2014,7 @@ EXPORT_SYMBOL_GPL(p9_client_xattrcreate); | |||
1824 | 2014 | ||
1825 | int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | 2015 | int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) |
1826 | { | 2016 | { |
1827 | int err, rsize; | 2017 | int err, rsize, non_zc = 0; |
1828 | struct p9_client *clnt; | 2018 | struct p9_client *clnt; |
1829 | struct p9_req_t *req; | 2019 | struct p9_req_t *req; |
1830 | char *dataptr; | 2020 | char *dataptr; |
@@ -1842,13 +2032,18 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
1842 | if (count < rsize) | 2032 | if (count < rsize) |
1843 | rsize = count; | 2033 | rsize = count; |
1844 | 2034 | ||
1845 | if ((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == | 2035 | /* Don't bother zerocopy for small IO (< 1024) */ |
1846 | P9_TRANS_PREF_PAYLOAD_SEP) { | 2036 | if (clnt->trans_mod->zc_request && rsize > 1024) { |
1847 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqF", fid->fid, | 2037 | /* |
1848 | offset, rsize, data); | 2038 | * response header len is 11 |
2039 | * PDU Header(7) + IO Size (4) | ||
2040 | */ | ||
2041 | req = p9_client_zc_rpc(clnt, P9_TREADDIR, data, NULL, rsize, 0, | ||
2042 | 11, 1, "dqd", fid->fid, offset, rsize); | ||
1849 | } else { | 2043 | } else { |
2044 | non_zc = 1; | ||
1850 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, | 2045 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, |
1851 | offset, rsize); | 2046 | offset, rsize); |
1852 | } | 2047 | } |
1853 | if (IS_ERR(req)) { | 2048 | if (IS_ERR(req)) { |
1854 | err = PTR_ERR(req); | 2049 | err = PTR_ERR(req); |
@@ -1857,13 +2052,13 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
1857 | 2052 | ||
1858 | err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); | 2053 | err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); |
1859 | if (err) { | 2054 | if (err) { |
1860 | P9_DUMP_PKT(1, req->rc); | 2055 | trace_9p_protocol_dump(clnt, req->rc); |
1861 | goto free_and_error; | 2056 | goto free_and_error; |
1862 | } | 2057 | } |
1863 | 2058 | ||
1864 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); | 2059 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); |
1865 | 2060 | ||
1866 | if (!req->tc->pbuf_size && data) | 2061 | if (non_zc) |
1867 | memmove(data, dataptr, count); | 2062 | memmove(data, dataptr, count); |
1868 | 2063 | ||
1869 | p9_free_req(clnt, req); | 2064 | p9_free_req(clnt, req); |
@@ -1894,7 +2089,7 @@ int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode, | |||
1894 | 2089 | ||
1895 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); | 2090 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); |
1896 | if (err) { | 2091 | if (err) { |
1897 | P9_DUMP_PKT(1, req->rc); | 2092 | trace_9p_protocol_dump(clnt, req->rc); |
1898 | goto error; | 2093 | goto error; |
1899 | } | 2094 | } |
1900 | P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type, | 2095 | P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type, |
@@ -1925,7 +2120,7 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, | |||
1925 | 2120 | ||
1926 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); | 2121 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); |
1927 | if (err) { | 2122 | if (err) { |
1928 | P9_DUMP_PKT(1, req->rc); | 2123 | trace_9p_protocol_dump(clnt, req->rc); |
1929 | goto error; | 2124 | goto error; |
1930 | } | 2125 | } |
1931 | P9_DPRINTK(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type, | 2126 | P9_DPRINTK(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type, |
@@ -1960,7 +2155,7 @@ int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status) | |||
1960 | 2155 | ||
1961 | err = p9pdu_readf(req->rc, clnt->proto_version, "b", status); | 2156 | err = p9pdu_readf(req->rc, clnt->proto_version, "b", status); |
1962 | if (err) { | 2157 | if (err) { |
1963 | P9_DUMP_PKT(1, req->rc); | 2158 | trace_9p_protocol_dump(clnt, req->rc); |
1964 | goto error; | 2159 | goto error; |
1965 | } | 2160 | } |
1966 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status); | 2161 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status); |
@@ -1993,7 +2188,7 @@ int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock) | |||
1993 | &glock->start, &glock->length, &glock->proc_id, | 2188 | &glock->start, &glock->length, &glock->proc_id, |
1994 | &glock->client_id); | 2189 | &glock->client_id); |
1995 | if (err) { | 2190 | if (err) { |
1996 | P9_DUMP_PKT(1, req->rc); | 2191 | trace_9p_protocol_dump(clnt, req->rc); |
1997 | goto error; | 2192 | goto error; |
1998 | } | 2193 | } |
1999 | P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld " | 2194 | P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld " |
@@ -2021,7 +2216,7 @@ int p9_client_readlink(struct p9_fid *fid, char **target) | |||
2021 | 2216 | ||
2022 | err = p9pdu_readf(req->rc, clnt->proto_version, "s", target); | 2217 | err = p9pdu_readf(req->rc, clnt->proto_version, "s", target); |
2023 | if (err) { | 2218 | if (err) { |
2024 | P9_DUMP_PKT(1, req->rc); | 2219 | trace_9p_protocol_dump(clnt, req->rc); |
2025 | goto error; | 2220 | goto error; |
2026 | } | 2221 | } |
2027 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target); | 2222 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target); |
diff --git a/net/9p/protocol.c b/net/9p/protocol.c index df58375ea6b3..55e10a96c902 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c | |||
@@ -37,40 +37,11 @@ | |||
37 | #include <net/9p/client.h> | 37 | #include <net/9p/client.h> |
38 | #include "protocol.h" | 38 | #include "protocol.h" |
39 | 39 | ||
40 | #include <trace/events/9p.h> | ||
41 | |||
40 | static int | 42 | static int |
41 | p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...); | 43 | p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...); |
42 | 44 | ||
43 | #ifdef CONFIG_NET_9P_DEBUG | ||
44 | void | ||
45 | p9pdu_dump(int way, struct p9_fcall *pdu) | ||
46 | { | ||
47 | int len = pdu->size; | ||
48 | |||
49 | if ((p9_debug_level & P9_DEBUG_VPKT) != P9_DEBUG_VPKT) { | ||
50 | if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) { | ||
51 | if (len > 32) | ||
52 | len = 32; | ||
53 | } else { | ||
54 | /* shouldn't happen */ | ||
55 | return; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | if (way) | ||
60 | print_hex_dump_bytes("[9P] ", DUMP_PREFIX_OFFSET, pdu->sdata, | ||
61 | len); | ||
62 | else | ||
63 | print_hex_dump_bytes("]9P[ ", DUMP_PREFIX_OFFSET, pdu->sdata, | ||
64 | len); | ||
65 | } | ||
66 | #else | ||
67 | void | ||
68 | p9pdu_dump(int way, struct p9_fcall *pdu) | ||
69 | { | ||
70 | } | ||
71 | #endif | ||
72 | EXPORT_SYMBOL(p9pdu_dump); | ||
73 | |||
74 | void p9stat_free(struct p9_wstat *stbuf) | 45 | void p9stat_free(struct p9_wstat *stbuf) |
75 | { | 46 | { |
76 | kfree(stbuf->name); | 47 | kfree(stbuf->name); |
@@ -81,7 +52,7 @@ void p9stat_free(struct p9_wstat *stbuf) | |||
81 | } | 52 | } |
82 | EXPORT_SYMBOL(p9stat_free); | 53 | EXPORT_SYMBOL(p9stat_free); |
83 | 54 | ||
84 | static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size) | 55 | size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size) |
85 | { | 56 | { |
86 | size_t len = min(pdu->size - pdu->offset, size); | 57 | size_t len = min(pdu->size - pdu->offset, size); |
87 | memcpy(data, &pdu->sdata[pdu->offset], len); | 58 | memcpy(data, &pdu->sdata[pdu->offset], len); |
@@ -108,26 +79,6 @@ pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) | |||
108 | return size - len; | 79 | return size - len; |
109 | } | 80 | } |
110 | 81 | ||
111 | static size_t | ||
112 | pdu_write_urw(struct p9_fcall *pdu, const char *kdata, const char __user *udata, | ||
113 | size_t size) | ||
114 | { | ||
115 | BUG_ON(pdu->size > P9_IOHDRSZ); | ||
116 | pdu->pubuf = (char __user *)udata; | ||
117 | pdu->pkbuf = (char *)kdata; | ||
118 | pdu->pbuf_size = size; | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static size_t | ||
123 | pdu_write_readdir(struct p9_fcall *pdu, const char *kdata, size_t size) | ||
124 | { | ||
125 | BUG_ON(pdu->size > P9_READDIRHDRSZ); | ||
126 | pdu->pkbuf = (char *)kdata; | ||
127 | pdu->pbuf_size = size; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | /* | 82 | /* |
132 | b - int8_t | 83 | b - int8_t |
133 | w - int16_t | 84 | w - int16_t |
@@ -459,26 +410,6 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt, | |||
459 | errcode = -EFAULT; | 410 | errcode = -EFAULT; |
460 | } | 411 | } |
461 | break; | 412 | break; |
462 | case 'E':{ | ||
463 | int32_t cnt = va_arg(ap, int32_t); | ||
464 | const char *k = va_arg(ap, const void *); | ||
465 | const char __user *u = va_arg(ap, | ||
466 | const void __user *); | ||
467 | errcode = p9pdu_writef(pdu, proto_version, "d", | ||
468 | cnt); | ||
469 | if (!errcode && pdu_write_urw(pdu, k, u, cnt)) | ||
470 | errcode = -EFAULT; | ||
471 | } | ||
472 | break; | ||
473 | case 'F':{ | ||
474 | int32_t cnt = va_arg(ap, int32_t); | ||
475 | const char *k = va_arg(ap, const void *); | ||
476 | errcode = p9pdu_writef(pdu, proto_version, "d", | ||
477 | cnt); | ||
478 | if (!errcode && pdu_write_readdir(pdu, k, cnt)) | ||
479 | errcode = -EFAULT; | ||
480 | } | ||
481 | break; | ||
482 | case 'U':{ | 413 | case 'U':{ |
483 | int32_t count = va_arg(ap, int32_t); | 414 | int32_t count = va_arg(ap, int32_t); |
484 | const char __user *udata = | 415 | const char __user *udata = |
@@ -591,7 +522,7 @@ p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...) | |||
591 | return ret; | 522 | return ret; |
592 | } | 523 | } |
593 | 524 | ||
594 | int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version) | 525 | int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st) |
595 | { | 526 | { |
596 | struct p9_fcall fake_pdu; | 527 | struct p9_fcall fake_pdu; |
597 | int ret; | 528 | int ret; |
@@ -601,10 +532,10 @@ int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version) | |||
601 | fake_pdu.sdata = buf; | 532 | fake_pdu.sdata = buf; |
602 | fake_pdu.offset = 0; | 533 | fake_pdu.offset = 0; |
603 | 534 | ||
604 | ret = p9pdu_readf(&fake_pdu, proto_version, "S", st); | 535 | ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "S", st); |
605 | if (ret) { | 536 | if (ret) { |
606 | P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); | 537 | P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); |
607 | P9_DUMP_PKT(0, &fake_pdu); | 538 | trace_9p_protocol_dump(clnt, &fake_pdu); |
608 | } | 539 | } |
609 | 540 | ||
610 | return ret; | 541 | return ret; |
@@ -617,7 +548,7 @@ int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type) | |||
617 | return p9pdu_writef(pdu, 0, "dbw", 0, type, tag); | 548 | return p9pdu_writef(pdu, 0, "dbw", 0, type, tag); |
618 | } | 549 | } |
619 | 550 | ||
620 | int p9pdu_finalize(struct p9_fcall *pdu) | 551 | int p9pdu_finalize(struct p9_client *clnt, struct p9_fcall *pdu) |
621 | { | 552 | { |
622 | int size = pdu->size; | 553 | int size = pdu->size; |
623 | int err; | 554 | int err; |
@@ -626,7 +557,7 @@ int p9pdu_finalize(struct p9_fcall *pdu) | |||
626 | err = p9pdu_writef(pdu, 0, "d", size); | 557 | err = p9pdu_writef(pdu, 0, "d", size); |
627 | pdu->size = size; | 558 | pdu->size = size; |
628 | 559 | ||
629 | P9_DUMP_PKT(0, pdu); | 560 | trace_9p_protocol_dump(clnt, pdu); |
630 | P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size, | 561 | P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size, |
631 | pdu->id, pdu->tag); | 562 | pdu->id, pdu->tag); |
632 | 563 | ||
@@ -637,14 +568,10 @@ void p9pdu_reset(struct p9_fcall *pdu) | |||
637 | { | 568 | { |
638 | pdu->offset = 0; | 569 | pdu->offset = 0; |
639 | pdu->size = 0; | 570 | pdu->size = 0; |
640 | pdu->private = NULL; | ||
641 | pdu->pubuf = NULL; | ||
642 | pdu->pkbuf = NULL; | ||
643 | pdu->pbuf_size = 0; | ||
644 | } | 571 | } |
645 | 572 | ||
646 | int p9dirent_read(char *buf, int len, struct p9_dirent *dirent, | 573 | int p9dirent_read(struct p9_client *clnt, char *buf, int len, |
647 | int proto_version) | 574 | struct p9_dirent *dirent) |
648 | { | 575 | { |
649 | struct p9_fcall fake_pdu; | 576 | struct p9_fcall fake_pdu; |
650 | int ret; | 577 | int ret; |
@@ -655,11 +582,11 @@ int p9dirent_read(char *buf, int len, struct p9_dirent *dirent, | |||
655 | fake_pdu.sdata = buf; | 582 | fake_pdu.sdata = buf; |
656 | fake_pdu.offset = 0; | 583 | fake_pdu.offset = 0; |
657 | 584 | ||
658 | ret = p9pdu_readf(&fake_pdu, proto_version, "Qqbs", &dirent->qid, | 585 | ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "Qqbs", &dirent->qid, |
659 | &dirent->d_off, &dirent->d_type, &nameptr); | 586 | &dirent->d_off, &dirent->d_type, &nameptr); |
660 | if (ret) { | 587 | if (ret) { |
661 | P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret); | 588 | P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret); |
662 | P9_DUMP_PKT(1, &fake_pdu); | 589 | trace_9p_protocol_dump(clnt, &fake_pdu); |
663 | goto out; | 590 | goto out; |
664 | } | 591 | } |
665 | 592 | ||
diff --git a/net/9p/protocol.h b/net/9p/protocol.h index 2431c0f38d56..2cc525fa49fa 100644 --- a/net/9p/protocol.h +++ b/net/9p/protocol.h | |||
@@ -29,6 +29,6 @@ int p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt, | |||
29 | va_list ap); | 29 | va_list ap); |
30 | int p9pdu_readf(struct p9_fcall *pdu, int proto_version, 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_client *clnt, struct p9_fcall *pdu); |
33 | void p9pdu_dump(int, struct p9_fcall *); | ||
34 | void p9pdu_reset(struct p9_fcall *pdu); | 33 | void p9pdu_reset(struct p9_fcall *pdu); |
34 | size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size); | ||
diff --git a/net/9p/trans_common.c b/net/9p/trans_common.c index 9a70ebdec56e..de8df957867d 100644 --- a/net/9p/trans_common.c +++ b/net/9p/trans_common.c | |||
@@ -21,30 +21,25 @@ | |||
21 | 21 | ||
22 | /** | 22 | /** |
23 | * p9_release_req_pages - Release pages after the transaction. | 23 | * p9_release_req_pages - Release pages after the transaction. |
24 | * @*private: PDU's private page of struct trans_rpage_info | ||
25 | */ | 24 | */ |
26 | void | 25 | void p9_release_pages(struct page **pages, int nr_pages) |
27 | p9_release_req_pages(struct trans_rpage_info *rpinfo) | ||
28 | { | 26 | { |
29 | int i = 0; | 27 | int i = 0; |
30 | 28 | while (pages[i] && nr_pages--) { | |
31 | while (rpinfo->rp_data[i] && rpinfo->rp_nr_pages--) { | 29 | put_page(pages[i]); |
32 | put_page(rpinfo->rp_data[i]); | ||
33 | i++; | 30 | i++; |
34 | } | 31 | } |
35 | } | 32 | } |
36 | EXPORT_SYMBOL(p9_release_req_pages); | 33 | EXPORT_SYMBOL(p9_release_pages); |
37 | 34 | ||
38 | /** | 35 | /** |
39 | * p9_nr_pages - Return number of pages needed to accommodate the payload. | 36 | * p9_nr_pages - Return number of pages needed to accommodate the payload. |
40 | */ | 37 | */ |
41 | int | 38 | int p9_nr_pages(char *data, int len) |
42 | p9_nr_pages(struct p9_req_t *req) | ||
43 | { | 39 | { |
44 | unsigned long start_page, end_page; | 40 | unsigned long start_page, end_page; |
45 | start_page = (unsigned long)req->tc->pubuf >> PAGE_SHIFT; | 41 | start_page = (unsigned long)data >> PAGE_SHIFT; |
46 | end_page = ((unsigned long)req->tc->pubuf + req->tc->pbuf_size + | 42 | end_page = ((unsigned long)data + len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
47 | PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
48 | return end_page - start_page; | 43 | return end_page - start_page; |
49 | } | 44 | } |
50 | EXPORT_SYMBOL(p9_nr_pages); | 45 | EXPORT_SYMBOL(p9_nr_pages); |
@@ -58,35 +53,17 @@ EXPORT_SYMBOL(p9_nr_pages); | |||
58 | * @nr_pages: number of pages to accommodate the payload | 53 | * @nr_pages: number of pages to accommodate the payload |
59 | * @rw: Indicates if the pages are for read or write. | 54 | * @rw: Indicates if the pages are for read or write. |
60 | */ | 55 | */ |
61 | int | ||
62 | p9_payload_gup(struct p9_req_t *req, size_t *pdata_off, int *pdata_len, | ||
63 | int nr_pages, u8 rw) | ||
64 | { | ||
65 | uint32_t first_page_bytes = 0; | ||
66 | int32_t pdata_mapped_pages; | ||
67 | struct trans_rpage_info *rpinfo; | ||
68 | |||
69 | *pdata_off = (__force size_t)req->tc->pubuf & (PAGE_SIZE-1); | ||
70 | 56 | ||
71 | if (*pdata_off) | 57 | int p9_payload_gup(char *data, int *nr_pages, struct page **pages, int write) |
72 | first_page_bytes = min(((size_t)PAGE_SIZE - *pdata_off), | 58 | { |
73 | req->tc->pbuf_size); | 59 | int nr_mapped_pages; |
74 | 60 | ||
75 | rpinfo = req->tc->private; | 61 | nr_mapped_pages = get_user_pages_fast((unsigned long)data, |
76 | pdata_mapped_pages = get_user_pages_fast((unsigned long)req->tc->pubuf, | 62 | *nr_pages, write, pages); |
77 | nr_pages, rw, &rpinfo->rp_data[0]); | 63 | if (nr_mapped_pages <= 0) |
78 | if (pdata_mapped_pages <= 0) | 64 | return nr_mapped_pages; |
79 | return pdata_mapped_pages; | ||
80 | 65 | ||
81 | rpinfo->rp_nr_pages = pdata_mapped_pages; | 66 | *nr_pages = nr_mapped_pages; |
82 | if (*pdata_off) { | ||
83 | *pdata_len = first_page_bytes; | ||
84 | *pdata_len += min((req->tc->pbuf_size - *pdata_len), | ||
85 | ((size_t)pdata_mapped_pages - 1) << PAGE_SHIFT); | ||
86 | } else { | ||
87 | *pdata_len = min(req->tc->pbuf_size, | ||
88 | (size_t)pdata_mapped_pages << PAGE_SHIFT); | ||
89 | } | ||
90 | return 0; | 67 | return 0; |
91 | } | 68 | } |
92 | EXPORT_SYMBOL(p9_payload_gup); | 69 | EXPORT_SYMBOL(p9_payload_gup); |
diff --git a/net/9p/trans_common.h b/net/9p/trans_common.h index 76309223bb02..173bb550a9eb 100644 --- a/net/9p/trans_common.h +++ b/net/9p/trans_common.h | |||
@@ -12,21 +12,6 @@ | |||
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | /* TRUE if it is user context */ | 15 | void p9_release_pages(struct page **, int); |
16 | #define P9_IS_USER_CONTEXT (!segment_eq(get_fs(), KERNEL_DS)) | 16 | int p9_payload_gup(char *, int *, struct page **, int); |
17 | 17 | int p9_nr_pages(char *, int); | |
18 | /** | ||
19 | * struct trans_rpage_info - To store mapped page information in PDU. | ||
20 | * @rp_alloc:Set if this structure is allocd, not a reuse unused space in pdu. | ||
21 | * @rp_nr_pages: Number of mapped pages | ||
22 | * @rp_data: Array of page pointers | ||
23 | */ | ||
24 | struct trans_rpage_info { | ||
25 | u8 rp_alloc; | ||
26 | int rp_nr_pages; | ||
27 | struct page *rp_data[0]; | ||
28 | }; | ||
29 | |||
30 | void p9_release_req_pages(struct trans_rpage_info *); | ||
31 | int p9_payload_gup(struct p9_req_t *, size_t *, int *, int, u8); | ||
32 | int p9_nr_pages(struct p9_req_t *); | ||
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index e317583fcc73..32aa9834229c 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c | |||
@@ -150,12 +150,10 @@ static void req_done(struct virtqueue *vq) | |||
150 | while (1) { | 150 | while (1) { |
151 | spin_lock_irqsave(&chan->lock, flags); | 151 | spin_lock_irqsave(&chan->lock, flags); |
152 | rc = virtqueue_get_buf(chan->vq, &len); | 152 | rc = virtqueue_get_buf(chan->vq, &len); |
153 | |||
154 | if (rc == NULL) { | 153 | if (rc == NULL) { |
155 | spin_unlock_irqrestore(&chan->lock, flags); | 154 | spin_unlock_irqrestore(&chan->lock, flags); |
156 | break; | 155 | break; |
157 | } | 156 | } |
158 | |||
159 | chan->ring_bufs_avail = 1; | 157 | chan->ring_bufs_avail = 1; |
160 | spin_unlock_irqrestore(&chan->lock, flags); | 158 | spin_unlock_irqrestore(&chan->lock, flags); |
161 | /* Wakeup if anyone waiting for VirtIO ring space. */ | 159 | /* Wakeup if anyone waiting for VirtIO ring space. */ |
@@ -163,17 +161,6 @@ static void req_done(struct virtqueue *vq) | |||
163 | P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc); | 161 | P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc); |
164 | P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag); | 162 | P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag); |
165 | req = p9_tag_lookup(chan->client, rc->tag); | 163 | req = p9_tag_lookup(chan->client, rc->tag); |
166 | if (req->tc->private) { | ||
167 | struct trans_rpage_info *rp = req->tc->private; | ||
168 | int p = rp->rp_nr_pages; | ||
169 | /*Release pages */ | ||
170 | p9_release_req_pages(rp); | ||
171 | atomic_sub(p, &vp_pinned); | ||
172 | wake_up(&vp_wq); | ||
173 | if (rp->rp_alloc) | ||
174 | kfree(rp); | ||
175 | req->tc->private = NULL; | ||
176 | } | ||
177 | req->status = REQ_STATUS_RCVD; | 164 | req->status = REQ_STATUS_RCVD; |
178 | p9_client_cb(chan->client, req); | 165 | p9_client_cb(chan->client, req); |
179 | } | 166 | } |
@@ -193,9 +180,8 @@ static void req_done(struct virtqueue *vq) | |||
193 | * | 180 | * |
194 | */ | 181 | */ |
195 | 182 | ||
196 | static int | 183 | static int pack_sg_list(struct scatterlist *sg, int start, |
197 | pack_sg_list(struct scatterlist *sg, int start, int limit, char *data, | 184 | int limit, char *data, int count) |
198 | int count) | ||
199 | { | 185 | { |
200 | int s; | 186 | int s; |
201 | int index = start; | 187 | int index = start; |
@@ -224,31 +210,36 @@ static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req) | |||
224 | * this takes a list of pages. | 210 | * this takes a list of pages. |
225 | * @sg: scatter/gather list to pack into | 211 | * @sg: scatter/gather list to pack into |
226 | * @start: which segment of the sg_list to start at | 212 | * @start: which segment of the sg_list to start at |
227 | * @pdata_off: Offset into the first page | ||
228 | * @**pdata: a list of pages to add into sg. | 213 | * @**pdata: a list of pages to add into sg. |
214 | * @nr_pages: number of pages to pack into the scatter/gather list | ||
215 | * @data: data to pack into scatter/gather list | ||
229 | * @count: amount of data to pack into the scatter/gather list | 216 | * @count: amount of data to pack into the scatter/gather list |
230 | */ | 217 | */ |
231 | static int | 218 | static int |
232 | pack_sg_list_p(struct scatterlist *sg, int start, int limit, size_t pdata_off, | 219 | pack_sg_list_p(struct scatterlist *sg, int start, int limit, |
233 | struct page **pdata, int count) | 220 | struct page **pdata, int nr_pages, char *data, int count) |
234 | { | 221 | { |
235 | int s; | 222 | int i = 0, s; |
236 | int i = 0; | 223 | int data_off; |
237 | int index = start; | 224 | int index = start; |
238 | 225 | ||
239 | if (pdata_off) { | 226 | BUG_ON(nr_pages > (limit - start)); |
240 | s = min((int)(PAGE_SIZE - pdata_off), count); | 227 | /* |
241 | sg_set_page(&sg[index++], pdata[i++], s, pdata_off); | 228 | * if the first page doesn't start at |
242 | count -= s; | 229 | * page boundary find the offset |
243 | } | 230 | */ |
244 | 231 | data_off = offset_in_page(data); | |
245 | while (count) { | 232 | while (nr_pages) { |
246 | BUG_ON(index > limit); | 233 | s = rest_of_page(data); |
247 | s = min((int)PAGE_SIZE, count); | 234 | if (s > count) |
248 | sg_set_page(&sg[index++], pdata[i++], s, 0); | 235 | s = count; |
236 | sg_set_page(&sg[index++], pdata[i++], s, data_off); | ||
237 | data_off = 0; | ||
238 | data += s; | ||
249 | count -= s; | 239 | count -= s; |
240 | nr_pages--; | ||
250 | } | 241 | } |
251 | return index-start; | 242 | return index - start; |
252 | } | 243 | } |
253 | 244 | ||
254 | /** | 245 | /** |
@@ -261,114 +252,166 @@ pack_sg_list_p(struct scatterlist *sg, int start, int limit, size_t pdata_off, | |||
261 | static int | 252 | static int |
262 | p9_virtio_request(struct p9_client *client, struct p9_req_t *req) | 253 | p9_virtio_request(struct p9_client *client, struct p9_req_t *req) |
263 | { | 254 | { |
264 | int in, out, inp, outp; | 255 | int err; |
265 | struct virtio_chan *chan = client->trans; | 256 | int in, out; |
266 | unsigned long flags; | 257 | unsigned long flags; |
267 | size_t pdata_off = 0; | 258 | struct virtio_chan *chan = client->trans; |
268 | struct trans_rpage_info *rpinfo = NULL; | ||
269 | int err, pdata_len = 0; | ||
270 | 259 | ||
271 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); | 260 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); |
272 | 261 | ||
273 | req->status = REQ_STATUS_SENT; | 262 | req->status = REQ_STATUS_SENT; |
263 | req_retry: | ||
264 | spin_lock_irqsave(&chan->lock, flags); | ||
265 | |||
266 | /* Handle out VirtIO ring buffers */ | ||
267 | out = pack_sg_list(chan->sg, 0, | ||
268 | VIRTQUEUE_NUM, req->tc->sdata, req->tc->size); | ||
274 | 269 | ||
275 | if (req->tc->pbuf_size && (req->tc->pubuf && P9_IS_USER_CONTEXT)) { | 270 | in = pack_sg_list(chan->sg, out, |
276 | int nr_pages = p9_nr_pages(req); | 271 | VIRTQUEUE_NUM, req->rc->sdata, req->rc->capacity); |
277 | int rpinfo_size = sizeof(struct trans_rpage_info) + | ||
278 | sizeof(struct page *) * nr_pages; | ||
279 | 272 | ||
280 | if (atomic_read(&vp_pinned) >= chan->p9_max_pages) { | 273 | err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); |
281 | err = wait_event_interruptible(vp_wq, | 274 | if (err < 0) { |
282 | atomic_read(&vp_pinned) < chan->p9_max_pages); | 275 | if (err == -ENOSPC) { |
276 | chan->ring_bufs_avail = 0; | ||
277 | spin_unlock_irqrestore(&chan->lock, flags); | ||
278 | err = wait_event_interruptible(*chan->vc_wq, | ||
279 | chan->ring_bufs_avail); | ||
283 | if (err == -ERESTARTSYS) | 280 | if (err == -ERESTARTSYS) |
284 | return err; | 281 | return err; |
285 | P9_DPRINTK(P9_DEBUG_TRANS, "9p: May gup pages now.\n"); | ||
286 | } | ||
287 | 282 | ||
288 | if (rpinfo_size <= (req->tc->capacity - req->tc->size)) { | 283 | P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n"); |
289 | /* We can use sdata */ | 284 | goto req_retry; |
290 | req->tc->private = req->tc->sdata + req->tc->size; | ||
291 | rpinfo = (struct trans_rpage_info *)req->tc->private; | ||
292 | rpinfo->rp_alloc = 0; | ||
293 | } else { | 285 | } else { |
294 | req->tc->private = kmalloc(rpinfo_size, GFP_NOFS); | 286 | spin_unlock_irqrestore(&chan->lock, flags); |
295 | if (!req->tc->private) { | 287 | P9_DPRINTK(P9_DEBUG_TRANS, |
296 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: " | 288 | "9p debug: " |
297 | "private kmalloc returned NULL"); | 289 | "virtio rpc add_buf returned failure"); |
298 | return -ENOMEM; | 290 | return -EIO; |
299 | } | ||
300 | rpinfo = (struct trans_rpage_info *)req->tc->private; | ||
301 | rpinfo->rp_alloc = 1; | ||
302 | } | 291 | } |
292 | } | ||
293 | virtqueue_kick(chan->vq); | ||
294 | spin_unlock_irqrestore(&chan->lock, flags); | ||
303 | 295 | ||
304 | err = p9_payload_gup(req, &pdata_off, &pdata_len, nr_pages, | 296 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n"); |
305 | req->tc->id == P9_TREAD ? 1 : 0); | 297 | return 0; |
306 | if (err < 0) { | 298 | } |
307 | if (rpinfo->rp_alloc) | 299 | |
308 | kfree(rpinfo); | 300 | static int p9_get_mapped_pages(struct virtio_chan *chan, |
301 | struct page **pages, char *data, | ||
302 | int nr_pages, int write, int kern_buf) | ||
303 | { | ||
304 | int err; | ||
305 | if (!kern_buf) { | ||
306 | /* | ||
307 | * We allow only p9_max_pages pinned. We wait for the | ||
308 | * Other zc request to finish here | ||
309 | */ | ||
310 | if (atomic_read(&vp_pinned) >= chan->p9_max_pages) { | ||
311 | err = wait_event_interruptible(vp_wq, | ||
312 | (atomic_read(&vp_pinned) < chan->p9_max_pages)); | ||
313 | if (err == -ERESTARTSYS) | ||
314 | return err; | ||
315 | } | ||
316 | err = p9_payload_gup(data, &nr_pages, pages, write); | ||
317 | if (err < 0) | ||
309 | return err; | 318 | return err; |
310 | } else { | 319 | atomic_add(nr_pages, &vp_pinned); |
311 | atomic_add(rpinfo->rp_nr_pages, &vp_pinned); | 320 | } else { |
321 | /* kernel buffer, no need to pin pages */ | ||
322 | int s, index = 0; | ||
323 | int count = nr_pages; | ||
324 | while (nr_pages) { | ||
325 | s = rest_of_page(data); | ||
326 | pages[index++] = virt_to_page(data); | ||
327 | data += s; | ||
328 | nr_pages--; | ||
312 | } | 329 | } |
330 | nr_pages = count; | ||
313 | } | 331 | } |
332 | return nr_pages; | ||
333 | } | ||
314 | 334 | ||
315 | req_retry_pinned: | 335 | /** |
316 | spin_lock_irqsave(&chan->lock, flags); | 336 | * p9_virtio_zc_request - issue a zero copy request |
337 | * @client: client instance issuing the request | ||
338 | * @req: request to be issued | ||
339 | * @uidata: user bffer that should be ued for zero copy read | ||
340 | * @uodata: user buffer that shoud be user for zero copy write | ||
341 | * @inlen: read buffer size | ||
342 | * @olen: write buffer size | ||
343 | * @hdrlen: reader header size, This is the size of response protocol data | ||
344 | * | ||
345 | */ | ||
346 | static int | ||
347 | p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, | ||
348 | char *uidata, char *uodata, int inlen, | ||
349 | int outlen, int in_hdr_len, int kern_buf) | ||
350 | { | ||
351 | int in, out, err; | ||
352 | unsigned long flags; | ||
353 | int in_nr_pages = 0, out_nr_pages = 0; | ||
354 | struct page **in_pages = NULL, **out_pages = NULL; | ||
355 | struct virtio_chan *chan = client->trans; | ||
317 | 356 | ||
318 | /* Handle out VirtIO ring buffers */ | 357 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); |
319 | out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata, | 358 | |
320 | req->tc->size); | 359 | if (uodata) { |
321 | 360 | out_nr_pages = p9_nr_pages(uodata, outlen); | |
322 | if (req->tc->pbuf_size && (req->tc->id == P9_TWRITE)) { | 361 | out_pages = kmalloc(sizeof(struct page *) * out_nr_pages, |
323 | /* We have additional write payload buffer to take care */ | 362 | GFP_NOFS); |
324 | if (req->tc->pubuf && P9_IS_USER_CONTEXT) { | 363 | if (!out_pages) { |
325 | outp = pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM, | 364 | err = -ENOMEM; |
326 | pdata_off, rpinfo->rp_data, pdata_len); | 365 | goto err_out; |
327 | } else { | 366 | } |
328 | char *pbuf; | 367 | out_nr_pages = p9_get_mapped_pages(chan, out_pages, uodata, |
329 | if (req->tc->pubuf) | 368 | out_nr_pages, 0, kern_buf); |
330 | pbuf = (__force char *) req->tc->pubuf; | 369 | if (out_nr_pages < 0) { |
331 | else | 370 | err = out_nr_pages; |
332 | pbuf = req->tc->pkbuf; | 371 | kfree(out_pages); |
333 | outp = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, pbuf, | 372 | out_pages = NULL; |
334 | req->tc->pbuf_size); | 373 | goto err_out; |
335 | } | 374 | } |
336 | out += outp; | ||
337 | } | 375 | } |
338 | 376 | if (uidata) { | |
339 | /* Handle in VirtIO ring buffers */ | 377 | in_nr_pages = p9_nr_pages(uidata, inlen); |
340 | if (req->tc->pbuf_size && | 378 | in_pages = kmalloc(sizeof(struct page *) * in_nr_pages, |
341 | ((req->tc->id == P9_TREAD) || (req->tc->id == P9_TREADDIR))) { | 379 | GFP_NOFS); |
342 | /* | 380 | if (!in_pages) { |
343 | * Take care of additional Read payload. | 381 | err = -ENOMEM; |
344 | * 11 is the read/write header = PDU Header(7) + IO Size (4). | 382 | goto err_out; |
345 | * Arrange in such a way that server places header in the | 383 | } |
346 | * alloced memory and payload onto the user buffer. | 384 | in_nr_pages = p9_get_mapped_pages(chan, in_pages, uidata, |
347 | */ | 385 | in_nr_pages, 1, kern_buf); |
348 | inp = pack_sg_list(chan->sg, out, | 386 | if (in_nr_pages < 0) { |
349 | VIRTQUEUE_NUM, req->rc->sdata, 11); | 387 | err = in_nr_pages; |
350 | /* | 388 | kfree(in_pages); |
351 | * Running executables in the filesystem may result in | 389 | in_pages = NULL; |
352 | * a read request with kernel buffer as opposed to user buffer. | 390 | goto err_out; |
353 | */ | ||
354 | if (req->tc->pubuf && P9_IS_USER_CONTEXT) { | ||
355 | in = pack_sg_list_p(chan->sg, out+inp, VIRTQUEUE_NUM, | ||
356 | pdata_off, rpinfo->rp_data, pdata_len); | ||
357 | } else { | ||
358 | char *pbuf; | ||
359 | if (req->tc->pubuf) | ||
360 | pbuf = (__force char *) req->tc->pubuf; | ||
361 | else | ||
362 | pbuf = req->tc->pkbuf; | ||
363 | |||
364 | in = pack_sg_list(chan->sg, out+inp, VIRTQUEUE_NUM, | ||
365 | pbuf, req->tc->pbuf_size); | ||
366 | } | 391 | } |
367 | in += inp; | ||
368 | } else { | ||
369 | in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, | ||
370 | req->rc->sdata, req->rc->capacity); | ||
371 | } | 392 | } |
393 | req->status = REQ_STATUS_SENT; | ||
394 | req_retry_pinned: | ||
395 | spin_lock_irqsave(&chan->lock, flags); | ||
396 | /* out data */ | ||
397 | out = pack_sg_list(chan->sg, 0, | ||
398 | VIRTQUEUE_NUM, req->tc->sdata, req->tc->size); | ||
399 | |||
400 | if (out_pages) | ||
401 | out += pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM, | ||
402 | out_pages, out_nr_pages, uodata, outlen); | ||
403 | /* | ||
404 | * Take care of in data | ||
405 | * For example TREAD have 11. | ||
406 | * 11 is the read/write header = PDU Header(7) + IO Size (4). | ||
407 | * Arrange in such a way that server places header in the | ||
408 | * alloced memory and payload onto the user buffer. | ||
409 | */ | ||
410 | in = pack_sg_list(chan->sg, out, | ||
411 | VIRTQUEUE_NUM, req->rc->sdata, in_hdr_len); | ||
412 | if (in_pages) | ||
413 | in += pack_sg_list_p(chan->sg, out + in, VIRTQUEUE_NUM, | ||
414 | in_pages, in_nr_pages, uidata, inlen); | ||
372 | 415 | ||
373 | err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); | 416 | err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); |
374 | if (err < 0) { | 417 | if (err < 0) { |
@@ -376,28 +419,45 @@ req_retry_pinned: | |||
376 | chan->ring_bufs_avail = 0; | 419 | chan->ring_bufs_avail = 0; |
377 | spin_unlock_irqrestore(&chan->lock, flags); | 420 | spin_unlock_irqrestore(&chan->lock, flags); |
378 | err = wait_event_interruptible(*chan->vc_wq, | 421 | err = wait_event_interruptible(*chan->vc_wq, |
379 | chan->ring_bufs_avail); | 422 | chan->ring_bufs_avail); |
380 | if (err == -ERESTARTSYS) | 423 | if (err == -ERESTARTSYS) |
381 | return err; | 424 | goto err_out; |
382 | 425 | ||
383 | P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n"); | 426 | P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n"); |
384 | goto req_retry_pinned; | 427 | goto req_retry_pinned; |
385 | } else { | 428 | } else { |
386 | spin_unlock_irqrestore(&chan->lock, flags); | 429 | spin_unlock_irqrestore(&chan->lock, flags); |
387 | P9_DPRINTK(P9_DEBUG_TRANS, | 430 | P9_DPRINTK(P9_DEBUG_TRANS, |
388 | "9p debug: " | 431 | "9p debug: " |
389 | "virtio rpc add_buf returned failure"); | 432 | "virtio rpc add_buf returned failure"); |
390 | if (rpinfo && rpinfo->rp_alloc) | 433 | err = -EIO; |
391 | kfree(rpinfo); | 434 | goto err_out; |
392 | return -EIO; | ||
393 | } | 435 | } |
394 | } | 436 | } |
395 | |||
396 | virtqueue_kick(chan->vq); | 437 | virtqueue_kick(chan->vq); |
397 | spin_unlock_irqrestore(&chan->lock, flags); | 438 | spin_unlock_irqrestore(&chan->lock, flags); |
398 | |||
399 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n"); | 439 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n"); |
400 | return 0; | 440 | err = wait_event_interruptible(*req->wq, |
441 | req->status >= REQ_STATUS_RCVD); | ||
442 | /* | ||
443 | * Non kernel buffers are pinned, unpin them | ||
444 | */ | ||
445 | err_out: | ||
446 | if (!kern_buf) { | ||
447 | if (in_pages) { | ||
448 | p9_release_pages(in_pages, in_nr_pages); | ||
449 | atomic_sub(in_nr_pages, &vp_pinned); | ||
450 | } | ||
451 | if (out_pages) { | ||
452 | p9_release_pages(out_pages, out_nr_pages); | ||
453 | atomic_sub(out_nr_pages, &vp_pinned); | ||
454 | } | ||
455 | /* wakeup anybody waiting for slots to pin pages */ | ||
456 | wake_up(&vp_wq); | ||
457 | } | ||
458 | kfree(in_pages); | ||
459 | kfree(out_pages); | ||
460 | return err; | ||
401 | } | 461 | } |
402 | 462 | ||
403 | static ssize_t p9_mount_tag_show(struct device *dev, | 463 | static ssize_t p9_mount_tag_show(struct device *dev, |
@@ -591,8 +651,8 @@ static struct p9_trans_module p9_virtio_trans = { | |||
591 | .create = p9_virtio_create, | 651 | .create = p9_virtio_create, |
592 | .close = p9_virtio_close, | 652 | .close = p9_virtio_close, |
593 | .request = p9_virtio_request, | 653 | .request = p9_virtio_request, |
654 | .zc_request = p9_virtio_zc_request, | ||
594 | .cancel = p9_virtio_cancel, | 655 | .cancel = p9_virtio_cancel, |
595 | |||
596 | /* | 656 | /* |
597 | * We leave one entry for input and one entry for response | 657 | * We leave one entry for input and one entry for response |
598 | * headers. We also skip one more entry to accomodate, address | 658 | * headers. We also skip one more entry to accomodate, address |
@@ -600,7 +660,6 @@ static struct p9_trans_module p9_virtio_trans = { | |||
600 | * page in zero copy. | 660 | * page in zero copy. |
601 | */ | 661 | */ |
602 | .maxsize = PAGE_SIZE * (VIRTQUEUE_NUM - 3), | 662 | .maxsize = PAGE_SIZE * (VIRTQUEUE_NUM - 3), |
603 | .pref = P9_TRANS_PREF_PAYLOAD_SEP, | ||
604 | .def = 0, | 663 | .def = 0, |
605 | .owner = THIS_MODULE, | 664 | .owner = THIS_MODULE, |
606 | }; | 665 | }; |