diff options
author | Latchesar Ionkov <lucho@ionkov.net> | 2006-01-08 04:05:00 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-08 23:14:06 -0500 |
commit | 531b1094b74365dcc55fa464d28a9a2497ae825d (patch) | |
tree | a0384dabe3be1c844166d028b3ef7c21c3dfe5fc /fs/9p/mux.c | |
parent | d8da097afb765654c866062148fd98b11db9003e (diff) |
[PATCH] v9fs: zero copy implementation
Performance enhancement reducing the number of copies in the data and
stat paths.
Signed-off-by: Latchesar Ionkov <lucho@ionkov.net>
Cc: Eric Van Hensbergen <ericvh@ericvh.myip.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/9p/mux.c')
-rw-r--r-- | fs/9p/mux.c | 157 |
1 files changed, 86 insertions, 71 deletions
diff --git a/fs/9p/mux.c b/fs/9p/mux.c index 62b6ad0767e1..f21cf5083973 100644 --- a/fs/9p/mux.c +++ b/fs/9p/mux.c | |||
@@ -35,8 +35,8 @@ | |||
35 | #include "debug.h" | 35 | #include "debug.h" |
36 | #include "v9fs.h" | 36 | #include "v9fs.h" |
37 | #include "9p.h" | 37 | #include "9p.h" |
38 | #include "transport.h" | ||
39 | #include "conv.h" | 38 | #include "conv.h" |
39 | #include "transport.h" | ||
40 | #include "mux.h" | 40 | #include "mux.h" |
41 | 41 | ||
42 | #define ERREQFLUSH 1 | 42 | #define ERREQFLUSH 1 |
@@ -74,6 +74,7 @@ struct v9fs_mux_data { | |||
74 | wait_queue_head_t equeue; | 74 | wait_queue_head_t equeue; |
75 | struct list_head req_list; | 75 | struct list_head req_list; |
76 | struct list_head unsent_req_list; | 76 | struct list_head unsent_req_list; |
77 | struct v9fs_fcall *rcall; | ||
77 | int rpos; | 78 | int rpos; |
78 | char *rbuf; | 79 | char *rbuf; |
79 | int wpos; | 80 | int wpos; |
@@ -101,11 +102,15 @@ struct v9fs_mux_rpc { | |||
101 | wait_queue_head_t wqueue; | 102 | wait_queue_head_t wqueue; |
102 | }; | 103 | }; |
103 | 104 | ||
105 | extern int v9fs_errstr2errno(char *str, int len); | ||
106 | |||
104 | static int v9fs_poll_proc(void *); | 107 | static int v9fs_poll_proc(void *); |
105 | static void v9fs_read_work(void *); | 108 | static void v9fs_read_work(void *); |
106 | static void v9fs_write_work(void *); | 109 | static void v9fs_write_work(void *); |
107 | static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, | 110 | static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, |
108 | poll_table * p); | 111 | poll_table * p); |
112 | static u16 v9fs_mux_get_tag(struct v9fs_mux_data *); | ||
113 | static void v9fs_mux_put_tag(struct v9fs_mux_data *, u16); | ||
109 | 114 | ||
110 | static DECLARE_MUTEX(v9fs_mux_task_lock); | 115 | static DECLARE_MUTEX(v9fs_mux_task_lock); |
111 | static struct workqueue_struct *v9fs_mux_wq; | 116 | static struct workqueue_struct *v9fs_mux_wq; |
@@ -166,8 +171,9 @@ static void v9fs_mux_poll_start(struct v9fs_mux_data *m) | |||
166 | if (v9fs_mux_poll_tasks[i].task == NULL) { | 171 | if (v9fs_mux_poll_tasks[i].task == NULL) { |
167 | vpt = &v9fs_mux_poll_tasks[i]; | 172 | vpt = &v9fs_mux_poll_tasks[i]; |
168 | dprintk(DEBUG_MUX, "create proc %p\n", vpt); | 173 | dprintk(DEBUG_MUX, "create proc %p\n", vpt); |
169 | vpt->task = kthread_create(v9fs_poll_proc, | 174 | vpt->task = |
170 | vpt, "v9fs-poll"); | 175 | kthread_create(v9fs_poll_proc, vpt, |
176 | "v9fs-poll"); | ||
171 | INIT_LIST_HEAD(&vpt->mux_list); | 177 | INIT_LIST_HEAD(&vpt->mux_list); |
172 | vpt->muxnum = 0; | 178 | vpt->muxnum = 0; |
173 | v9fs_mux_poll_task_num++; | 179 | v9fs_mux_poll_task_num++; |
@@ -253,7 +259,7 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, | |||
253 | struct v9fs_mux_data *m, *mtmp; | 259 | struct v9fs_mux_data *m, *mtmp; |
254 | 260 | ||
255 | dprintk(DEBUG_MUX, "transport %p msize %d\n", trans, msize); | 261 | dprintk(DEBUG_MUX, "transport %p msize %d\n", trans, msize); |
256 | m = kmalloc(sizeof(struct v9fs_mux_data) + 2 * msize, GFP_KERNEL); | 262 | m = kmalloc(sizeof(struct v9fs_mux_data), GFP_KERNEL); |
257 | if (!m) | 263 | if (!m) |
258 | return ERR_PTR(-ENOMEM); | 264 | return ERR_PTR(-ENOMEM); |
259 | 265 | ||
@@ -268,10 +274,11 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, | |||
268 | init_waitqueue_head(&m->equeue); | 274 | init_waitqueue_head(&m->equeue); |
269 | INIT_LIST_HEAD(&m->req_list); | 275 | INIT_LIST_HEAD(&m->req_list); |
270 | INIT_LIST_HEAD(&m->unsent_req_list); | 276 | INIT_LIST_HEAD(&m->unsent_req_list); |
277 | m->rcall = NULL; | ||
271 | m->rpos = 0; | 278 | m->rpos = 0; |
272 | m->rbuf = (char *)m + sizeof(struct v9fs_mux_data); | 279 | m->rbuf = NULL; |
273 | m->wpos = m->wsize = 0; | 280 | m->wpos = m->wsize = 0; |
274 | m->wbuf = m->rbuf + msize; | 281 | m->wbuf = NULL; |
275 | INIT_WORK(&m->rq, v9fs_read_work, m); | 282 | INIT_WORK(&m->rq, v9fs_read_work, m); |
276 | INIT_WORK(&m->wq, v9fs_write_work, m); | 283 | INIT_WORK(&m->wq, v9fs_write_work, m); |
277 | m->wsched = 0; | 284 | m->wsched = 0; |
@@ -427,29 +434,6 @@ static int v9fs_poll_proc(void *a) | |||
427 | return 0; | 434 | return 0; |
428 | } | 435 | } |
429 | 436 | ||
430 | static inline int v9fs_write_req(struct v9fs_mux_data *m, struct v9fs_req *req) | ||
431 | { | ||
432 | int n; | ||
433 | |||
434 | list_move_tail(&req->req_list, &m->req_list); | ||
435 | n = v9fs_serialize_fcall(req->tcall, m->wbuf, m->msize, *m->extended); | ||
436 | if (n < 0) { | ||
437 | req->err = n; | ||
438 | list_del(&req->req_list); | ||
439 | if (req->cb) { | ||
440 | spin_unlock(&m->lock); | ||
441 | (*req->cb) (req->cba, req->tcall, req->rcall, req->err); | ||
442 | req->cb = NULL; | ||
443 | spin_lock(&m->lock); | ||
444 | } else | ||
445 | kfree(req->rcall); | ||
446 | |||
447 | kfree(req); | ||
448 | } | ||
449 | |||
450 | return n; | ||
451 | } | ||
452 | |||
453 | /** | 437 | /** |
454 | * v9fs_write_work - called when a transport can send some data | 438 | * v9fs_write_work - called when a transport can send some data |
455 | */ | 439 | */ |
@@ -457,7 +441,7 @@ static void v9fs_write_work(void *a) | |||
457 | { | 441 | { |
458 | int n, err; | 442 | int n, err; |
459 | struct v9fs_mux_data *m; | 443 | struct v9fs_mux_data *m; |
460 | struct v9fs_req *req, *rtmp; | 444 | struct v9fs_req *req; |
461 | 445 | ||
462 | m = a; | 446 | m = a; |
463 | 447 | ||
@@ -472,17 +456,15 @@ static void v9fs_write_work(void *a) | |||
472 | return; | 456 | return; |
473 | } | 457 | } |
474 | 458 | ||
475 | err = 0; | ||
476 | spin_lock(&m->lock); | 459 | spin_lock(&m->lock); |
477 | list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, | 460 | req = |
478 | req_list) { | 461 | list_entry(m->unsent_req_list.next, struct v9fs_req, |
479 | err = v9fs_write_req(m, req); | 462 | req_list); |
480 | if (err > 0) | 463 | list_move_tail(&req->req_list, &m->req_list); |
481 | break; | 464 | m->wbuf = req->tcall->sdata; |
482 | } | 465 | m->wsize = req->tcall->size; |
483 | |||
484 | m->wsize = err; | ||
485 | m->wpos = 0; | 466 | m->wpos = 0; |
467 | dump_data(m->wbuf, m->wsize); | ||
486 | spin_unlock(&m->lock); | 468 | spin_unlock(&m->lock); |
487 | } | 469 | } |
488 | 470 | ||
@@ -526,24 +508,23 @@ static void v9fs_write_work(void *a) | |||
526 | static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) | 508 | static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) |
527 | { | 509 | { |
528 | int ecode, tag; | 510 | int ecode, tag; |
529 | char *ename; | 511 | struct v9fs_str *ename; |
530 | 512 | ||
531 | tag = req->tag; | 513 | tag = req->tag; |
532 | if (req->rcall->id == RERROR && !req->err) { | 514 | if (req->rcall->id == RERROR && !req->err) { |
533 | ecode = req->rcall->params.rerror.errno; | 515 | ecode = req->rcall->params.rerror.errno; |
534 | ename = req->rcall->params.rerror.error; | 516 | ename = &req->rcall->params.rerror.error; |
535 | 517 | ||
536 | dprintk(DEBUG_MUX, "Rerror %s\n", ename); | 518 | dprintk(DEBUG_MUX, "Rerror %.*s\n", ename->len, ename->str); |
537 | 519 | ||
538 | if (*m->extended) | 520 | if (*m->extended) |
539 | req->err = -ecode; | 521 | req->err = -ecode; |
540 | 522 | ||
541 | if (!req->err) { | 523 | if (!req->err) { |
542 | req->err = v9fs_errstr2errno(ename); | 524 | req->err = v9fs_errstr2errno(ename->str, ename->len); |
543 | 525 | ||
544 | if (!req->err) { /* string match failed */ | 526 | if (!req->err) { /* string match failed */ |
545 | dprintk(DEBUG_ERROR, "unknown error: %s\n", | 527 | PRINT_FCALL_ERROR("unknown error", req->rcall); |
546 | ename); | ||
547 | } | 528 | } |
548 | 529 | ||
549 | if (!req->err) | 530 | if (!req->err) |
@@ -565,8 +546,7 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) | |||
565 | } else | 546 | } else |
566 | kfree(req->rcall); | 547 | kfree(req->rcall); |
567 | 548 | ||
568 | if (tag != V9FS_NOTAG) | 549 | v9fs_mux_put_tag(m, tag); |
569 | v9fs_put_idpool(tag, &m->tidpool); | ||
570 | 550 | ||
571 | wake_up(&m->equeue); | 551 | wake_up(&m->equeue); |
572 | kfree(req); | 552 | kfree(req); |
@@ -577,10 +557,11 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) | |||
577 | */ | 557 | */ |
578 | static void v9fs_read_work(void *a) | 558 | static void v9fs_read_work(void *a) |
579 | { | 559 | { |
580 | int n, err, rcallen; | 560 | int n, err; |
581 | struct v9fs_mux_data *m; | 561 | struct v9fs_mux_data *m; |
582 | struct v9fs_req *req, *rptr, *rreq; | 562 | struct v9fs_req *req, *rptr, *rreq; |
583 | struct v9fs_fcall *rcall; | 563 | struct v9fs_fcall *rcall; |
564 | char *rbuf; | ||
584 | 565 | ||
585 | m = a; | 566 | m = a; |
586 | 567 | ||
@@ -589,6 +570,19 @@ static void v9fs_read_work(void *a) | |||
589 | 570 | ||
590 | rcall = NULL; | 571 | rcall = NULL; |
591 | dprintk(DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); | 572 | dprintk(DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); |
573 | |||
574 | if (!m->rcall) { | ||
575 | m->rcall = | ||
576 | kmalloc(sizeof(struct v9fs_fcall) + m->msize, GFP_KERNEL); | ||
577 | if (!m->rcall) { | ||
578 | err = -ENOMEM; | ||
579 | goto error; | ||
580 | } | ||
581 | |||
582 | m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall); | ||
583 | m->rpos = 0; | ||
584 | } | ||
585 | |||
592 | clear_bit(Rpending, &m->wsched); | 586 | clear_bit(Rpending, &m->wsched); |
593 | err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos); | 587 | err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos); |
594 | dprintk(DEBUG_MUX, "mux %p got %d bytes\n", m, err); | 588 | dprintk(DEBUG_MUX, "mux %p got %d bytes\n", m, err); |
@@ -613,21 +607,32 @@ static void v9fs_read_work(void *a) | |||
613 | if (m->rpos < n) | 607 | if (m->rpos < n) |
614 | break; | 608 | break; |
615 | 609 | ||
616 | rcallen = n + V9FS_FCALLHDRSZ; | ||
617 | rcall = kmalloc(rcallen, GFP_KERNEL); | ||
618 | if (!rcall) { | ||
619 | err = -ENOMEM; | ||
620 | goto error; | ||
621 | } | ||
622 | |||
623 | dump_data(m->rbuf, n); | 610 | dump_data(m->rbuf, n); |
624 | err = v9fs_deserialize_fcall(m->rbuf, n, rcall, rcallen, | 611 | err = |
625 | *m->extended); | 612 | v9fs_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended); |
626 | if (err < 0) { | 613 | if (err < 0) { |
627 | kfree(rcall); | ||
628 | goto error; | 614 | goto error; |
629 | } | 615 | } |
630 | 616 | ||
617 | rcall = m->rcall; | ||
618 | rbuf = m->rbuf; | ||
619 | if (m->rpos > n) { | ||
620 | m->rcall = kmalloc(sizeof(struct v9fs_fcall) + m->msize, | ||
621 | GFP_KERNEL); | ||
622 | if (!m->rcall) { | ||
623 | err = -ENOMEM; | ||
624 | goto error; | ||
625 | } | ||
626 | |||
627 | m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall); | ||
628 | memmove(m->rbuf, rbuf + n, m->rpos - n); | ||
629 | m->rpos -= n; | ||
630 | } else { | ||
631 | m->rcall = NULL; | ||
632 | m->rbuf = NULL; | ||
633 | m->rpos = 0; | ||
634 | } | ||
635 | |||
631 | dprintk(DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, rcall->id, | 636 | dprintk(DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, rcall->id, |
632 | rcall->tag); | 637 | rcall->tag); |
633 | 638 | ||
@@ -642,6 +647,7 @@ static void v9fs_read_work(void *a) | |||
642 | process_request(m, req); | 647 | process_request(m, req); |
643 | break; | 648 | break; |
644 | } | 649 | } |
650 | |||
645 | } | 651 | } |
646 | 652 | ||
647 | if (!req) { | 653 | if (!req) { |
@@ -652,10 +658,6 @@ static void v9fs_read_work(void *a) | |||
652 | m, rcall->id, rcall->tag); | 658 | m, rcall->id, rcall->tag); |
653 | kfree(rcall); | 659 | kfree(rcall); |
654 | } | 660 | } |
655 | |||
656 | if (m->rpos > n) | ||
657 | memmove(m->rbuf, m->rbuf + n, m->rpos - n); | ||
658 | m->rpos -= n; | ||
659 | } | 661 | } |
660 | 662 | ||
661 | if (!list_empty(&m->req_list)) { | 663 | if (!list_empty(&m->req_list)) { |
@@ -710,12 +712,13 @@ static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m, | |||
710 | if (tc->id == TVERSION) | 712 | if (tc->id == TVERSION) |
711 | n = V9FS_NOTAG; | 713 | n = V9FS_NOTAG; |
712 | else | 714 | else |
713 | n = v9fs_get_idpool(&m->tidpool); | 715 | n = v9fs_mux_get_tag(m); |
714 | 716 | ||
715 | if (n < 0) | 717 | if (n < 0) |
716 | return ERR_PTR(-ENOMEM); | 718 | return ERR_PTR(-ENOMEM); |
717 | 719 | ||
718 | tc->tag = n; | 720 | v9fs_set_tag(tc, n); |
721 | |||
719 | req->tag = n; | 722 | req->tag = n; |
720 | req->tcall = tc; | 723 | req->tcall = tc; |
721 | req->rcall = NULL; | 724 | req->rcall = NULL; |
@@ -773,9 +776,7 @@ v9fs_mux_flush_cb(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc, | |||
773 | if (!cb) | 776 | if (!cb) |
774 | spin_unlock(&m->lock); | 777 | spin_unlock(&m->lock); |
775 | 778 | ||
776 | if (v9fs_check_idpool(tag, &m->tidpool)) | 779 | v9fs_mux_put_tag(m, tag); |
777 | v9fs_put_idpool(tag, &m->tidpool); | ||
778 | |||
779 | kfree(tc); | 780 | kfree(tc); |
780 | kfree(rc); | 781 | kfree(rc); |
781 | } | 782 | } |
@@ -787,10 +788,7 @@ v9fs_mux_flush_request(struct v9fs_mux_data *m, struct v9fs_req *req) | |||
787 | 788 | ||
788 | dprintk(DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag); | 789 | dprintk(DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag); |
789 | 790 | ||
790 | fc = kmalloc(sizeof(struct v9fs_fcall), GFP_KERNEL); | 791 | fc = v9fs_create_tflush(req->tag); |
791 | fc->id = TFLUSH; | ||
792 | fc->params.tflush.oldtag = req->tag; | ||
793 | |||
794 | v9fs_send_request(m, fc, v9fs_mux_flush_cb, m); | 792 | v9fs_send_request(m, fc, v9fs_mux_flush_cb, m); |
795 | } | 793 | } |
796 | 794 | ||
@@ -939,3 +937,20 @@ void v9fs_mux_cancel(struct v9fs_mux_data *m, int err) | |||
939 | 937 | ||
940 | wake_up(&m->equeue); | 938 | wake_up(&m->equeue); |
941 | } | 939 | } |
940 | |||
941 | static u16 v9fs_mux_get_tag(struct v9fs_mux_data *m) | ||
942 | { | ||
943 | int tag; | ||
944 | |||
945 | tag = v9fs_get_idpool(&m->tidpool); | ||
946 | if (tag < 0) | ||
947 | return V9FS_NOTAG; | ||
948 | else | ||
949 | return (u16) tag; | ||
950 | } | ||
951 | |||
952 | static void v9fs_mux_put_tag(struct v9fs_mux_data *m, u16 tag) | ||
953 | { | ||
954 | if (tag != V9FS_NOTAG && v9fs_check_idpool(tag, &m->tidpool)) | ||
955 | v9fs_put_idpool(tag, &m->tidpool); | ||
956 | } | ||