aboutsummaryrefslogtreecommitdiffstats
path: root/fs/9p/mux.c
diff options
context:
space:
mode:
authorLatchesar Ionkov <lucho@ionkov.net>2006-01-08 04:05:00 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-08 23:14:06 -0500
commit531b1094b74365dcc55fa464d28a9a2497ae825d (patch)
treea0384dabe3be1c844166d028b3ef7c21c3dfe5fc /fs/9p/mux.c
parentd8da097afb765654c866062148fd98b11db9003e (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.c157
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
105extern int v9fs_errstr2errno(char *str, int len);
106
104static int v9fs_poll_proc(void *); 107static int v9fs_poll_proc(void *);
105static void v9fs_read_work(void *); 108static void v9fs_read_work(void *);
106static void v9fs_write_work(void *); 109static void v9fs_write_work(void *);
107static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, 110static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address,
108 poll_table * p); 111 poll_table * p);
112static u16 v9fs_mux_get_tag(struct v9fs_mux_data *);
113static void v9fs_mux_put_tag(struct v9fs_mux_data *, u16);
109 114
110static DECLARE_MUTEX(v9fs_mux_task_lock); 115static DECLARE_MUTEX(v9fs_mux_task_lock);
111static struct workqueue_struct *v9fs_mux_wq; 116static 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
430static 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)
526static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) 508static 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 */
578static void v9fs_read_work(void *a) 558static 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
941static 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
952static 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}