diff options
-rw-r--r-- | net/9p/trans_fd.c | 129 |
1 files changed, 66 insertions, 63 deletions
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index cc9bc739e9d3..627e3f097fc5 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c | |||
@@ -111,7 +111,9 @@ struct p9_poll_wait { | |||
111 | * @err: error state | 111 | * @err: error state |
112 | * @req_list: accounting for requests which have been sent | 112 | * @req_list: accounting for requests which have been sent |
113 | * @unsent_req_list: accounting for requests that haven't been sent | 113 | * @unsent_req_list: accounting for requests that haven't been sent |
114 | * @rcall: current response &p9_fcall structure | 114 | * @req: current request being processed (if any) |
115 | * @tmp_buf: temporary buffer to read in header | ||
116 | * @rsize: amount to read for current frame | ||
115 | * @rpos: read position in current frame | 117 | * @rpos: read position in current frame |
116 | * @rbuf: current read buffer | 118 | * @rbuf: current read buffer |
117 | * @wpos: write position for current frame | 119 | * @wpos: write position for current frame |
@@ -132,7 +134,9 @@ struct p9_conn { | |||
132 | int err; | 134 | int err; |
133 | struct list_head req_list; | 135 | struct list_head req_list; |
134 | struct list_head unsent_req_list; | 136 | struct list_head unsent_req_list; |
135 | struct p9_fcall *rcall; | 137 | struct p9_req_t *req; |
138 | char tmp_buf[7]; | ||
139 | int rsize; | ||
136 | int rpos; | 140 | int rpos; |
137 | char *rbuf; | 141 | char *rbuf; |
138 | int wpos; | 142 | int wpos; |
@@ -346,34 +350,25 @@ static void p9_read_work(struct work_struct *work) | |||
346 | { | 350 | { |
347 | int n, err; | 351 | int n, err; |
348 | struct p9_conn *m; | 352 | struct p9_conn *m; |
349 | struct p9_req_t *req; | ||
350 | struct p9_fcall *rcall; | ||
351 | char *rbuf; | ||
352 | 353 | ||
353 | m = container_of(work, struct p9_conn, rq); | 354 | m = container_of(work, struct p9_conn, rq); |
354 | 355 | ||
355 | if (m->err < 0) | 356 | if (m->err < 0) |
356 | return; | 357 | return; |
357 | 358 | ||
358 | rcall = NULL; | ||
359 | P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); | 359 | P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); |
360 | 360 | ||
361 | if (!m->rcall) { | 361 | if (!m->rbuf) { |
362 | m->rcall = | 362 | m->rbuf = m->tmp_buf; |
363 | kmalloc(sizeof(struct p9_fcall) + m->client->msize, | ||
364 | GFP_KERNEL); | ||
365 | if (!m->rcall) { | ||
366 | err = -ENOMEM; | ||
367 | goto error; | ||
368 | } | ||
369 | |||
370 | m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall); | ||
371 | m->rpos = 0; | 363 | m->rpos = 0; |
364 | m->rsize = 7; /* start by reading header */ | ||
372 | } | 365 | } |
373 | 366 | ||
374 | clear_bit(Rpending, &m->wsched); | 367 | clear_bit(Rpending, &m->wsched); |
368 | P9_DPRINTK(P9_DEBUG_MUX, "read mux %p pos %d size: %d = %d\n", m, | ||
369 | m->rpos, m->rsize, m->rsize-m->rpos); | ||
375 | err = p9_fd_read(m->client, m->rbuf + m->rpos, | 370 | err = p9_fd_read(m->client, m->rbuf + m->rpos, |
376 | m->client->msize - m->rpos); | 371 | m->rsize - m->rpos); |
377 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err); | 372 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err); |
378 | if (err == -EAGAIN) { | 373 | if (err == -EAGAIN) { |
379 | clear_bit(Rworksched, &m->wsched); | 374 | clear_bit(Rworksched, &m->wsched); |
@@ -384,8 +379,12 @@ static void p9_read_work(struct work_struct *work) | |||
384 | goto error; | 379 | goto error; |
385 | 380 | ||
386 | m->rpos += err; | 381 | m->rpos += err; |
387 | while (m->rpos > 4) { | 382 | |
388 | n = le32_to_cpu(*(__le32 *) m->rbuf); | 383 | if ((!m->req) && (m->rpos == m->rsize)) { /* header read in */ |
384 | u16 tag; | ||
385 | P9_DPRINTK(P9_DEBUG_MUX, "got new header\n"); | ||
386 | |||
387 | n = le32_to_cpu(*(__le32 *) m->rbuf); /* read packet size */ | ||
389 | if (n >= m->client->msize) { | 388 | if (n >= m->client->msize) { |
390 | P9_DPRINTK(P9_DEBUG_ERROR, | 389 | P9_DPRINTK(P9_DEBUG_ERROR, |
391 | "requested packet size too big: %d\n", n); | 390 | "requested packet size too big: %d\n", n); |
@@ -393,66 +392,71 @@ static void p9_read_work(struct work_struct *work) | |||
393 | goto error; | 392 | goto error; |
394 | } | 393 | } |
395 | 394 | ||
396 | if (m->rpos < n) | 395 | tag = le16_to_cpu(*(__le16 *) (m->rbuf+5)); /* read tag */ |
397 | break; | 396 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p pkt: size: %d bytes tag: %d\n", |
397 | m, n, tag); | ||
398 | 398 | ||
399 | err = | 399 | m->req = p9_tag_lookup(m->client, tag); |
400 | p9_deserialize_fcall(m->rbuf, n, m->rcall, m->client->dotu); | 400 | if (!m->req) { |
401 | if (err < 0) | 401 | P9_DPRINTK(P9_DEBUG_ERROR, "Unexpected packet tag %d\n", |
402 | tag); | ||
403 | err = -EIO; | ||
402 | goto error; | 404 | goto error; |
405 | } | ||
406 | |||
407 | if (m->req->rc == NULL) { | ||
408 | m->req->rc = kmalloc(sizeof(struct p9_fcall) + | ||
409 | m->client->msize, GFP_KERNEL); | ||
410 | if (!m->req->rc) { | ||
411 | m->req = NULL; | ||
412 | err = -ENOMEM; | ||
413 | goto error; | ||
414 | } | ||
415 | } | ||
416 | m->rbuf = (char *)m->req->rc + sizeof(struct p9_fcall); | ||
417 | memcpy(m->rbuf, m->tmp_buf, m->rsize); | ||
418 | m->rsize = n; | ||
419 | } | ||
420 | |||
421 | /* not an else because some packets (like clunk) have no payload */ | ||
422 | if ((m->req) && (m->rpos == m->rsize)) { /* packet is read in */ | ||
423 | P9_DPRINTK(P9_DEBUG_MUX, "got new packet\n"); | ||
424 | m->rbuf = (char *)m->req->rc + sizeof(struct p9_fcall); | ||
425 | err = p9_deserialize_fcall(m->rbuf, m->rsize, m->req->rc, | ||
426 | m->client->dotu); | ||
427 | if (err < 0) { | ||
428 | m->req = NULL; | ||
429 | goto error; | ||
430 | } | ||
403 | 431 | ||
404 | #ifdef CONFIG_NET_9P_DEBUG | 432 | #ifdef CONFIG_NET_9P_DEBUG |
405 | if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { | 433 | if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { |
406 | char buf[150]; | 434 | char buf[150]; |
407 | 435 | ||
408 | p9_printfcall(buf, sizeof(buf), m->rcall, | 436 | p9_printfcall(buf, sizeof(buf), m->req->rc, |
409 | m->client->dotu); | 437 | m->client->dotu); |
410 | printk(KERN_NOTICE ">>> %p %s\n", m, buf); | 438 | printk(KERN_NOTICE ">>> %p %s\n", m, buf); |
411 | } | 439 | } |
412 | #endif | 440 | #endif |
413 | 441 | ||
414 | rcall = m->rcall; | 442 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, |
415 | rbuf = m->rbuf; | 443 | m->req->rc->id, m->req->rc->tag); |
416 | if (m->rpos > n) { | ||
417 | m->rcall = kmalloc(sizeof(struct p9_fcall) + | ||
418 | m->client->msize, GFP_KERNEL); | ||
419 | if (!m->rcall) { | ||
420 | err = -ENOMEM; | ||
421 | goto error; | ||
422 | } | ||
423 | 444 | ||
424 | m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall); | 445 | m->rbuf = NULL; |
425 | memmove(m->rbuf, rbuf + n, m->rpos - n); | 446 | m->rpos = 0; |
426 | m->rpos -= n; | 447 | m->rsize = 0; |
427 | } else { | ||
428 | m->rcall = NULL; | ||
429 | m->rbuf = NULL; | ||
430 | m->rpos = 0; | ||
431 | } | ||
432 | 448 | ||
433 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, | 449 | if (m->req->status != REQ_STATUS_FLSH) { |
434 | rcall->id, rcall->tag); | 450 | list_del(&m->req->req_list); |
451 | m->req->status = REQ_STATUS_RCVD; | ||
452 | } | ||
435 | 453 | ||
436 | req = p9_tag_lookup(m->client, rcall->tag); | 454 | process_request(m, m->req); |
437 | 455 | ||
438 | if (req) { | 456 | if (m->req->status != REQ_STATUS_FLSH) |
439 | if (req->status != REQ_STATUS_FLSH) { | 457 | p9_conn_rpc_cb(m->client, m->req); |
440 | list_del(&req->req_list); | ||
441 | req->status = REQ_STATUS_RCVD; | ||
442 | } | ||
443 | 458 | ||
444 | req->rc = rcall; | 459 | m->req = NULL; |
445 | process_request(m, req); | ||
446 | |||
447 | if (req->status != REQ_STATUS_FLSH) | ||
448 | p9_conn_rpc_cb(m->client, req); | ||
449 | } else { | ||
450 | if (err >= 0 && rcall->id != P9_RFLUSH) | ||
451 | P9_DPRINTK(P9_DEBUG_ERROR, | ||
452 | "unexpected response mux %p id %d tag %d\n", | ||
453 | m, rcall->id, rcall->tag); | ||
454 | kfree(rcall); | ||
455 | } | ||
456 | } | 460 | } |
457 | 461 | ||
458 | if (!list_empty(&m->req_list)) { | 462 | if (!list_empty(&m->req_list)) { |
@@ -470,7 +474,6 @@ static void p9_read_work(struct work_struct *work) | |||
470 | clear_bit(Rworksched, &m->wsched); | 474 | clear_bit(Rworksched, &m->wsched); |
471 | 475 | ||
472 | return; | 476 | return; |
473 | |||
474 | error: | 477 | error: |
475 | p9_conn_cancel(m, err); | 478 | p9_conn_cancel(m, err); |
476 | clear_bit(Rworksched, &m->wsched); | 479 | clear_bit(Rworksched, &m->wsched); |