aboutsummaryrefslogtreecommitdiffstats
path: root/net/9p/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/9p/client.c')
-rw-r--r--net/9p/client.c1468
1 files changed, 830 insertions, 638 deletions
diff --git a/net/9p/client.c b/net/9p/client.c
index e053e06028a5..67717f69412e 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -33,12 +33,9 @@
33#include <linux/uaccess.h> 33#include <linux/uaccess.h>
34#include <net/9p/9p.h> 34#include <net/9p/9p.h>
35#include <linux/parser.h> 35#include <linux/parser.h>
36#include <net/9p/transport.h>
37#include <net/9p/client.h> 36#include <net/9p/client.h>
38 37#include <net/9p/transport.h>
39static struct p9_fid *p9_fid_create(struct p9_client *clnt); 38#include "protocol.h"
40static void p9_fid_destroy(struct p9_fid *fid);
41static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu);
42 39
43/* 40/*
44 * Client Option Parsing (code inspired by NFS code) 41 * Client Option Parsing (code inspired by NFS code)
@@ -59,6 +56,9 @@ static const match_table_t tokens = {
59 {Opt_err, NULL}, 56 {Opt_err, NULL},
60}; 57};
61 58
59static struct p9_req_t *
60p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
61
62/** 62/**
63 * v9fs_parse_options - parse mount options into session structure 63 * v9fs_parse_options - parse mount options into session structure
64 * @options: options string passed from mount 64 * @options: options string passed from mount
@@ -124,31 +124,586 @@ static int parse_opts(char *opts, struct p9_client *clnt)
124 return ret; 124 return ret;
125} 125}
126 126
127/**
128 * p9_tag_alloc - lookup/allocate a request by tag
129 * @c: client session to lookup tag within
130 * @tag: numeric id for transaction
131 *
132 * this is a simple array lookup, but will grow the
133 * request_slots as necessary to accomodate transaction
134 * ids which did not previously have a slot.
135 *
136 * this code relies on the client spinlock to manage locks, its
137 * possible we should switch to something else, but I'd rather
138 * stick with something low-overhead for the common case.
139 *
140 */
141
142static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
143{
144 unsigned long flags;
145 int row, col;
146 struct p9_req_t *req;
147
148 /* This looks up the original request by tag so we know which
149 * buffer to read the data into */
150 tag++;
151
152 if (tag >= c->max_tag) {
153 spin_lock_irqsave(&c->lock, flags);
154 /* check again since original check was outside of lock */
155 while (tag >= c->max_tag) {
156 row = (tag / P9_ROW_MAXTAG);
157 c->reqs[row] = kcalloc(P9_ROW_MAXTAG,
158 sizeof(struct p9_req_t), GFP_ATOMIC);
159
160 if (!c->reqs[row]) {
161 printk(KERN_ERR "Couldn't grow tag array\n");
162 spin_unlock_irqrestore(&c->lock, flags);
163 return ERR_PTR(-ENOMEM);
164 }
165 for (col = 0; col < P9_ROW_MAXTAG; col++) {
166 c->reqs[row][col].status = REQ_STATUS_IDLE;
167 c->reqs[row][col].tc = NULL;
168 }
169 c->max_tag += P9_ROW_MAXTAG;
170 }
171 spin_unlock_irqrestore(&c->lock, flags);
172 }
173 row = tag / P9_ROW_MAXTAG;
174 col = tag % P9_ROW_MAXTAG;
175
176 req = &c->reqs[row][col];
177 if (!req->tc) {
178 req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
179 if (!req->wq) {
180 printk(KERN_ERR "Couldn't grow tag array\n");
181 return ERR_PTR(-ENOMEM);
182 }
183 init_waitqueue_head(req->wq);
184 req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize,
185 GFP_KERNEL);
186 req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize,
187 GFP_KERNEL);
188 if ((!req->tc) || (!req->rc)) {
189 printk(KERN_ERR "Couldn't grow tag array\n");
190 kfree(req->tc);
191 kfree(req->rc);
192 return ERR_PTR(-ENOMEM);
193 }
194 req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall);
195 req->tc->capacity = c->msize;
196 req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall);
197 req->rc->capacity = c->msize;
198 }
199
200 p9pdu_reset(req->tc);
201 p9pdu_reset(req->rc);
202
203 req->flush_tag = 0;
204 req->tc->tag = tag-1;
205 req->status = REQ_STATUS_ALLOC;
206
207 return &c->reqs[row][col];
208}
209
210/**
211 * p9_tag_lookup - lookup a request by tag
212 * @c: client session to lookup tag within
213 * @tag: numeric id for transaction
214 *
215 */
216
217struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag)
218{
219 int row, col;
220
221 /* This looks up the original request by tag so we know which
222 * buffer to read the data into */
223 tag++;
224
225 BUG_ON(tag >= c->max_tag);
226
227 row = tag / P9_ROW_MAXTAG;
228 col = tag % P9_ROW_MAXTAG;
229
230 return &c->reqs[row][col];
231}
232EXPORT_SYMBOL(p9_tag_lookup);
233
234/**
235 * p9_tag_init - setup tags structure and contents
236 * @tags: tags structure from the client struct
237 *
238 * This initializes the tags structure for each client instance.
239 *
240 */
241
242static int p9_tag_init(struct p9_client *c)
243{
244 int err = 0;
245
246 c->tagpool = p9_idpool_create();
247 if (IS_ERR(c->tagpool)) {
248 err = PTR_ERR(c->tagpool);
249 c->tagpool = NULL;
250 goto error;
251 }
252
253 p9_idpool_get(c->tagpool); /* reserve tag 0 */
254
255 c->max_tag = 0;
256error:
257 return err;
258}
127 259
128/** 260/**
129 * p9_client_rpc - sends 9P request and waits until a response is available. 261 * p9_tag_cleanup - cleans up tags structure and reclaims resources
130 * The function can be interrupted. 262 * @tags: tags structure from the client struct
131 * @c: client data 263 *
132 * @tc: request to be sent 264 * This frees resources associated with the tags structure
133 * @rc: pointer where a pointer to the response is stored 265 *
134 */ 266 */
267static void p9_tag_cleanup(struct p9_client *c)
268{
269 int row, col;
270
271 /* check to insure all requests are idle */
272 for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
273 for (col = 0; col < P9_ROW_MAXTAG; col++) {
274 if (c->reqs[row][col].status != REQ_STATUS_IDLE) {
275 P9_DPRINTK(P9_DEBUG_MUX,
276 "Attempting to cleanup non-free tag %d,%d\n",
277 row, col);
278 /* TODO: delay execution of cleanup */
279 return;
280 }
281 }
282 }
283
284 if (c->tagpool)
285 p9_idpool_destroy(c->tagpool);
286
287 /* free requests associated with tags */
288 for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
289 for (col = 0; col < P9_ROW_MAXTAG; col++) {
290 kfree(c->reqs[row][col].wq);
291 kfree(c->reqs[row][col].tc);
292 kfree(c->reqs[row][col].rc);
293 }
294 kfree(c->reqs[row]);
295 }
296 c->max_tag = 0;
297}
298
299/**
300 * p9_free_req - free a request and clean-up as necessary
301 * c: client state
302 * r: request to release
303 *
304 */
305
306static void p9_free_req(struct p9_client *c, struct p9_req_t *r)
307{
308 int tag = r->tc->tag;
309 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag);
310
311 r->status = REQ_STATUS_IDLE;
312 if (tag != P9_NOTAG && p9_idpool_check(tag, c->tagpool))
313 p9_idpool_put(tag, c->tagpool);
314
315 /* if this was a flush request we have to free response fcall */
316 if (r->rc->id == P9_RFLUSH) {
317 kfree(r->tc);
318 kfree(r->rc);
319 }
320}
321
322/**
323 * p9_client_cb - call back from transport to client
324 * c: client state
325 * req: request received
326 *
327 */
328void p9_client_cb(struct p9_client *c, struct p9_req_t *req)
329{
330 struct p9_req_t *other_req;
331 unsigned long flags;
332
333 P9_DPRINTK(P9_DEBUG_MUX, " tag %d\n", req->tc->tag);
334
335 if (req->status == REQ_STATUS_ERROR)
336 wake_up(req->wq);
337
338 if (req->flush_tag) { /* flush receive path */
339 P9_DPRINTK(P9_DEBUG_9P, "<<< RFLUSH %d\n", req->tc->tag);
340 spin_lock_irqsave(&c->lock, flags);
341 other_req = p9_tag_lookup(c, req->flush_tag);
342 if (other_req->status != REQ_STATUS_FLSH) /* stale flush */
343 spin_unlock_irqrestore(&c->lock, flags);
344 else {
345 other_req->status = REQ_STATUS_FLSHD;
346 spin_unlock_irqrestore(&c->lock, flags);
347 wake_up(other_req->wq);
348 }
349 p9_free_req(c, req);
350 } else { /* normal receive path */
351 P9_DPRINTK(P9_DEBUG_MUX, "normal: tag %d\n", req->tc->tag);
352 spin_lock_irqsave(&c->lock, flags);
353 if (req->status != REQ_STATUS_FLSHD)
354 req->status = REQ_STATUS_RCVD;
355 spin_unlock_irqrestore(&c->lock, flags);
356 wake_up(req->wq);
357 P9_DPRINTK(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag);
358 }
359}
360EXPORT_SYMBOL(p9_client_cb);
361
362/**
363 * p9_parse_header - parse header arguments out of a packet
364 * @pdu: packet to parse
365 * @size: size of packet
366 * @type: type of request
367 * @tag: tag of packet
368 * @rewind: set if we need to rewind offset afterwards
369 */
370
135int 371int
136p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, 372p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, int16_t *tag,
137 struct p9_fcall **rc) 373 int rewind)
138{ 374{
139 return c->trans->rpc(c->trans, tc, rc); 375 int8_t r_type;
376 int16_t r_tag;
377 int32_t r_size;
378 int offset = pdu->offset;
379 int err;
380
381 pdu->offset = 0;
382 if (pdu->size == 0)
383 pdu->size = 7;
384
385 err = p9pdu_readf(pdu, 0, "dbw", &r_size, &r_type, &r_tag);
386 if (err)
387 goto rewind_and_exit;
388
389 pdu->size = r_size;
390 pdu->id = r_type;
391 pdu->tag = r_tag;
392
393 P9_DPRINTK(P9_DEBUG_9P, "<<< size=%d type: %d tag: %d\n", pdu->size,
394 pdu->id, pdu->tag);
395
396 if (type)
397 *type = r_type;
398 if (tag)
399 *tag = r_tag;
400 if (size)
401 *size = r_size;
402
403
404rewind_and_exit:
405 if (rewind)
406 pdu->offset = offset;
407 return err;
140} 408}
409EXPORT_SYMBOL(p9_parse_header);
410
411/**
412 * p9_check_errors - check 9p packet for error return and process it
413 * @c: current client instance
414 * @req: request to parse and check for error conditions
415 *
416 * returns error code if one is discovered, otherwise returns 0
417 *
418 * this will have to be more complicated if we have multiple
419 * error packet types
420 */
421
422static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
423{
424 int8_t type;
425 int err;
426
427 err = p9_parse_header(req->rc, NULL, &type, NULL, 0);
428 if (err) {
429 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err);
430 return err;
431 }
432
433 if (type == P9_RERROR) {
434 int ecode;
435 char *ename;
436
437 err = p9pdu_readf(req->rc, c->dotu, "s?d", &ename, &ecode);
438 if (err) {
439 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
440 err);
441 return err;
442 }
443
444 if (c->dotu)
445 err = -ecode;
446
447 if (!err) {
448 err = p9_errstr2errno(ename, strlen(ename));
449
450 /* string match failed */
451 if (!err)
452 err = -ESERVERFAULT;
453 }
454
455 P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename);
456
457 kfree(ename);
458 } else
459 err = 0;
460
461 return err;
462}
463
464/**
465 * p9_client_flush - flush (cancel) a request
466 * c: client state
467 * req: request to cancel
468 *
469 * This sents a flush for a particular requests and links
470 * the flush request to the original request. The current
471 * code only supports a single flush request although the protocol
472 * allows for multiple flush requests to be sent for a single request.
473 *
474 */
475
476static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
477{
478 struct p9_req_t *req;
479 int16_t oldtag;
480 int err;
481
482 err = p9_parse_header(oldreq->tc, NULL, NULL, &oldtag, 1);
483 if (err)
484 return err;
485
486 P9_DPRINTK(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag);
487
488 req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag);
489 if (IS_ERR(req))
490 return PTR_ERR(req);
491
492 req->flush_tag = oldtag;
493
494 /* we don't free anything here because RPC isn't complete */
495 return 0;
496}
497
498/**
499 * p9_client_rpc - issue a request and wait for a response
500 * @c: client session
501 * @type: type of request
502 * @fmt: protocol format string (see protocol.c)
503 *
504 * Returns request structure (which client must free using p9_free_req)
505 */
506
507static struct p9_req_t *
508p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
509{
510 va_list ap;
511 int tag, err;
512 struct p9_req_t *req;
513 unsigned long flags;
514 int sigpending;
515 int flushed = 0;
516
517 P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type);
518
519 if (c->status != Connected)
520 return ERR_PTR(-EIO);
521
522 if (signal_pending(current)) {
523 sigpending = 1;
524 clear_thread_flag(TIF_SIGPENDING);
525 } else
526 sigpending = 0;
527
528 tag = P9_NOTAG;
529 if (type != P9_TVERSION) {
530 tag = p9_idpool_get(c->tagpool);
531 if (tag < 0)
532 return ERR_PTR(-ENOMEM);
533 }
534
535 req = p9_tag_alloc(c, tag);
536 if (IS_ERR(req))
537 return req;
538
539 /* marshall the data */
540 p9pdu_prepare(req->tc, tag, type);
541 va_start(ap, fmt);
542 err = p9pdu_vwritef(req->tc, c->dotu, fmt, ap);
543 va_end(ap);
544 p9pdu_finalize(req->tc);
545
546 err = c->trans_mod->request(c, req);
547 if (err < 0) {
548 c->status = Disconnected;
549 goto reterr;
550 }
551
552 /* if it was a flush we just transmitted, return our tag */
553 if (type == P9_TFLUSH)
554 return req;
555again:
556 P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d\n", req->wq, tag);
557 err = wait_event_interruptible(*req->wq,
558 req->status >= REQ_STATUS_RCVD);
559 P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d returned %d (flushed=%d)\n",
560 req->wq, tag, err, flushed);
561
562 if (req->status == REQ_STATUS_ERROR) {
563 P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
564 err = req->t_err;
565 } else if (err == -ERESTARTSYS && flushed) {
566 P9_DPRINTK(P9_DEBUG_MUX, "flushed - going again\n");
567 goto again;
568 } else if (req->status == REQ_STATUS_FLSHD) {
569 P9_DPRINTK(P9_DEBUG_MUX, "flushed - erestartsys\n");
570 err = -ERESTARTSYS;
571 }
572
573 if ((err == -ERESTARTSYS) && (c->status == Connected) && (!flushed)) {
574 P9_DPRINTK(P9_DEBUG_MUX, "flushing\n");
575 spin_lock_irqsave(&c->lock, flags);
576 if (req->status == REQ_STATUS_SENT)
577 req->status = REQ_STATUS_FLSH;
578 spin_unlock_irqrestore(&c->lock, flags);
579 sigpending = 1;
580 flushed = 1;
581 clear_thread_flag(TIF_SIGPENDING);
582
583 if (c->trans_mod->cancel(c, req)) {
584 err = p9_client_flush(c, req);
585 if (err == 0)
586 goto again;
587 }
588 }
589
590 if (sigpending) {
591 spin_lock_irqsave(&current->sighand->siglock, flags);
592 recalc_sigpending();
593 spin_unlock_irqrestore(&current->sighand->siglock, flags);
594 }
595
596 if (err < 0)
597 goto reterr;
598
599 err = p9_check_errors(c, req);
600 if (!err) {
601 P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d\n", c, type);
602 return req;
603 }
604
605reterr:
606 P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d error: %d\n", c, type,
607 err);
608 p9_free_req(c, req);
609 return ERR_PTR(err);
610}
611
612static struct p9_fid *p9_fid_create(struct p9_client *clnt)
613{
614 int err;
615 struct p9_fid *fid;
616
617 P9_DPRINTK(P9_DEBUG_FID, "clnt %p\n", clnt);
618 fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
619 if (!fid)
620 return ERR_PTR(-ENOMEM);
621
622 fid->fid = p9_idpool_get(clnt->fidpool);
623 if (fid->fid < 0) {
624 err = -ENOSPC;
625 goto error;
626 }
627
628 memset(&fid->qid, 0, sizeof(struct p9_qid));
629 fid->mode = -1;
630 fid->rdir_fpos = 0;
631 fid->uid = current->fsuid;
632 fid->clnt = clnt;
633 fid->aux = NULL;
634
635 spin_lock(&clnt->lock);
636 list_add(&fid->flist, &clnt->fidlist);
637 spin_unlock(&clnt->lock);
638
639 return fid;
640
641error:
642 kfree(fid);
643 return ERR_PTR(err);
644}
645
646static void p9_fid_destroy(struct p9_fid *fid)
647{
648 struct p9_client *clnt;
649
650 P9_DPRINTK(P9_DEBUG_FID, "fid %d\n", fid->fid);
651 clnt = fid->clnt;
652 p9_idpool_put(fid->fid, clnt->fidpool);
653 spin_lock(&clnt->lock);
654 list_del(&fid->flist);
655 spin_unlock(&clnt->lock);
656 kfree(fid);
657}
658
659int p9_client_version(struct p9_client *c)
660{
661 int err = 0;
662 struct p9_req_t *req;
663 char *version;
664 int msize;
665
666 P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n",
667 c->msize, c->dotu);
668 req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize,
669 c->dotu ? "9P2000.u" : "9P2000");
670 if (IS_ERR(req))
671 return PTR_ERR(req);
672
673 err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version);
674 if (err) {
675 P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
676 p9pdu_dump(1, req->rc);
677 goto error;
678 }
679
680 P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
681 if (!memcmp(version, "9P2000.u", 8))
682 c->dotu = 1;
683 else if (!memcmp(version, "9P2000", 6))
684 c->dotu = 0;
685 else {
686 err = -EREMOTEIO;
687 goto error;
688 }
689
690 if (msize < c->msize)
691 c->msize = msize;
692
693error:
694 kfree(version);
695 p9_free_req(c, req);
696
697 return err;
698}
699EXPORT_SYMBOL(p9_client_version);
141 700
142struct p9_client *p9_client_create(const char *dev_name, char *options) 701struct p9_client *p9_client_create(const char *dev_name, char *options)
143{ 702{
144 int err, n; 703 int err;
145 struct p9_client *clnt; 704 struct p9_client *clnt;
146 struct p9_fcall *tc, *rc;
147 struct p9_str *version;
148 705
149 err = 0; 706 err = 0;
150 tc = NULL;
151 rc = NULL;
152 clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL); 707 clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL);
153 if (!clnt) 708 if (!clnt)
154 return ERR_PTR(-ENOMEM); 709 return ERR_PTR(-ENOMEM);
@@ -164,6 +719,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
164 goto error; 719 goto error;
165 } 720 }
166 721
722 p9_tag_init(clnt);
723
167 err = parse_opts(options, clnt); 724 err = parse_opts(options, clnt);
168 if (err < 0) 725 if (err < 0)
169 goto error; 726 goto error;
@@ -175,53 +732,23 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
175 goto error; 732 goto error;
176 } 733 }
177 734
178 P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n", 735 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d dotu %d\n",
179 clnt, clnt->trans_mod, clnt->msize, clnt->dotu); 736 clnt, clnt->trans_mod, clnt->msize, clnt->dotu);
180 737
181 738 err = clnt->trans_mod->create(clnt, dev_name, options);
182 clnt->trans = clnt->trans_mod->create(dev_name, options, clnt->msize, 739 if (err)
183 clnt->dotu);
184 if (IS_ERR(clnt->trans)) {
185 err = PTR_ERR(clnt->trans);
186 clnt->trans = NULL;
187 goto error; 740 goto error;
188 }
189 741
190 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) 742 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize)
191 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; 743 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ;
192 744
193 tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000"); 745 err = p9_client_version(clnt);
194 if (IS_ERR(tc)) {
195 err = PTR_ERR(tc);
196 tc = NULL;
197 goto error;
198 }
199
200 err = p9_client_rpc(clnt, tc, &rc);
201 if (err) 746 if (err)
202 goto error; 747 goto error;
203 748
204 version = &rc->params.rversion.version;
205 if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8))
206 clnt->dotu = 1;
207 else if (version->len == 6 && !memcmp(version->str, "9P2000", 6))
208 clnt->dotu = 0;
209 else {
210 err = -EREMOTEIO;
211 goto error;
212 }
213
214 n = rc->params.rversion.msize;
215 if (n < clnt->msize)
216 clnt->msize = n;
217
218 kfree(tc);
219 kfree(rc);
220 return clnt; 749 return clnt;
221 750
222error: 751error:
223 kfree(tc);
224 kfree(rc);
225 p9_client_destroy(clnt); 752 p9_client_destroy(clnt);
226 return ERR_PTR(err); 753 return ERR_PTR(err);
227} 754}
@@ -231,13 +758,10 @@ void p9_client_destroy(struct p9_client *clnt)
231{ 758{
232 struct p9_fid *fid, *fidptr; 759 struct p9_fid *fid, *fidptr;
233 760
234 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); 761 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p\n", clnt);
235 762
236 if (clnt->trans) { 763 if (clnt->trans_mod)
237 clnt->trans->close(clnt->trans); 764 clnt->trans_mod->close(clnt);
238 kfree(clnt->trans);
239 clnt->trans = NULL;
240 }
241 765
242 v9fs_put_trans(clnt->trans_mod); 766 v9fs_put_trans(clnt->trans_mod);
243 767
@@ -247,6 +771,8 @@ void p9_client_destroy(struct p9_client *clnt)
247 if (clnt->fidpool) 771 if (clnt->fidpool)
248 p9_idpool_destroy(clnt->fidpool); 772 p9_idpool_destroy(clnt->fidpool);
249 773
774 p9_tag_cleanup(clnt);
775
250 kfree(clnt); 776 kfree(clnt);
251} 777}
252EXPORT_SYMBOL(p9_client_destroy); 778EXPORT_SYMBOL(p9_client_destroy);
@@ -254,7 +780,7 @@ EXPORT_SYMBOL(p9_client_destroy);
254void p9_client_disconnect(struct p9_client *clnt) 780void p9_client_disconnect(struct p9_client *clnt)
255{ 781{
256 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); 782 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
257 clnt->trans->status = Disconnected; 783 clnt->status = Disconnected;
258} 784}
259EXPORT_SYMBOL(p9_client_disconnect); 785EXPORT_SYMBOL(p9_client_disconnect);
260 786
@@ -262,14 +788,13 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
262 char *uname, u32 n_uname, char *aname) 788 char *uname, u32 n_uname, char *aname)
263{ 789{
264 int err; 790 int err;
265 struct p9_fcall *tc, *rc; 791 struct p9_req_t *req;
266 struct p9_fid *fid; 792 struct p9_fid *fid;
793 struct p9_qid qid;
267 794
268 P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n", 795 P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n",
269 clnt, afid?afid->fid:-1, uname, aname); 796 afid ? afid->fid : -1, uname, aname);
270 err = 0; 797 err = 0;
271 tc = NULL;
272 rc = NULL;
273 798
274 fid = p9_fid_create(clnt); 799 fid = p9_fid_create(clnt);
275 if (IS_ERR(fid)) { 800 if (IS_ERR(fid)) {
@@ -278,73 +803,77 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
278 goto error; 803 goto error;
279 } 804 }
280 805
281 tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname, 806 req = p9_client_rpc(clnt, P9_TATTACH, "ddss?d", fid->fid,
282 n_uname, clnt->dotu); 807 afid ? afid->fid : P9_NOFID, uname, aname, n_uname);
283 if (IS_ERR(tc)) { 808 if (IS_ERR(req)) {
284 err = PTR_ERR(tc); 809 err = PTR_ERR(req);
285 tc = NULL;
286 goto error; 810 goto error;
287 } 811 }
288 812
289 err = p9_client_rpc(clnt, tc, &rc); 813 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid);
290 if (err) 814 if (err) {
815 p9pdu_dump(1, req->rc);
816 p9_free_req(clnt, req);
291 goto error; 817 goto error;
818 }
819
820 P9_DPRINTK(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n",
821 qid.type, qid.path, qid.version);
292 822
293 memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid)); 823 memmove(&fid->qid, &qid, sizeof(struct p9_qid));
294 kfree(tc); 824
295 kfree(rc); 825 p9_free_req(clnt, req);
296 return fid; 826 return fid;
297 827
298error: 828error:
299 kfree(tc);
300 kfree(rc);
301 if (fid) 829 if (fid)
302 p9_fid_destroy(fid); 830 p9_fid_destroy(fid);
303 return ERR_PTR(err); 831 return ERR_PTR(err);
304} 832}
305EXPORT_SYMBOL(p9_client_attach); 833EXPORT_SYMBOL(p9_client_attach);
306 834
307struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, 835struct p9_fid *
308 u32 n_uname, char *aname) 836p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname)
309{ 837{
310 int err; 838 int err;
311 struct p9_fcall *tc, *rc; 839 struct p9_req_t *req;
312 struct p9_fid *fid; 840 struct p9_qid qid;
841 struct p9_fid *afid;
313 842
314 P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname, 843 P9_DPRINTK(P9_DEBUG_9P, ">>> TAUTH uname %s aname %s\n", uname, aname);
315 aname);
316 err = 0; 844 err = 0;
317 tc = NULL;
318 rc = NULL;
319 845
320 fid = p9_fid_create(clnt); 846 afid = p9_fid_create(clnt);
321 if (IS_ERR(fid)) { 847 if (IS_ERR(afid)) {
322 err = PTR_ERR(fid); 848 err = PTR_ERR(afid);
323 fid = NULL; 849 afid = NULL;
324 goto error; 850 goto error;
325 } 851 }
326 852
327 tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu); 853 req = p9_client_rpc(clnt, P9_TAUTH, "dss?d",
328 if (IS_ERR(tc)) { 854 afid ? afid->fid : P9_NOFID, uname, aname, n_uname);
329 err = PTR_ERR(tc); 855 if (IS_ERR(req)) {
330 tc = NULL; 856 err = PTR_ERR(req);
331 goto error; 857 goto error;
332 } 858 }
333 859
334 err = p9_client_rpc(clnt, tc, &rc); 860 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid);
335 if (err) 861 if (err) {
862 p9pdu_dump(1, req->rc);
863 p9_free_req(clnt, req);
336 goto error; 864 goto error;
865 }
337 866
338 memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid)); 867 P9_DPRINTK(P9_DEBUG_9P, "<<< RAUTH qid %x.%llx.%x\n",
339 kfree(tc); 868 qid.type, qid.path, qid.version);
340 kfree(rc); 869
341 return fid; 870 memmove(&afid->qid, &qid, sizeof(struct p9_qid));
871 p9_free_req(clnt, req);
872 return afid;
342 873
343error: 874error:
344 kfree(tc); 875 if (afid)
345 kfree(rc); 876 p9_fid_destroy(afid);
346 if (fid)
347 p9_fid_destroy(fid);
348 return ERR_PTR(err); 877 return ERR_PTR(err);
349} 878}
350EXPORT_SYMBOL(p9_client_auth); 879EXPORT_SYMBOL(p9_client_auth);
@@ -353,15 +882,13 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
353 int clone) 882 int clone)
354{ 883{
355 int err; 884 int err;
356 struct p9_fcall *tc, *rc;
357 struct p9_client *clnt; 885 struct p9_client *clnt;
358 struct p9_fid *fid; 886 struct p9_fid *fid;
887 struct p9_qid *wqids;
888 struct p9_req_t *req;
889 int16_t nwqids, count;
359 890
360 P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n",
361 oldfid->fid, nwname, wnames?wnames[0]:NULL);
362 err = 0; 891 err = 0;
363 tc = NULL;
364 rc = NULL;
365 clnt = oldfid->clnt; 892 clnt = oldfid->clnt;
366 if (clone) { 893 if (clone) {
367 fid = p9_fid_create(clnt); 894 fid = p9_fid_create(clnt);
@@ -375,53 +902,49 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
375 } else 902 } else
376 fid = oldfid; 903 fid = oldfid;
377 904
378 tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames); 905
379 if (IS_ERR(tc)) { 906 P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n",
380 err = PTR_ERR(tc); 907 oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL);
381 tc = NULL; 908
909 req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid,
910 nwname, wnames);
911 if (IS_ERR(req)) {
912 err = PTR_ERR(req);
382 goto error; 913 goto error;
383 } 914 }
384 915
385 err = p9_client_rpc(clnt, tc, &rc); 916 err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids);
386 if (err) { 917 if (err) {
387 if (rc && rc->id == P9_RWALK) 918 p9pdu_dump(1, req->rc);
388 goto clunk_fid; 919 p9_free_req(clnt, req);
389 else 920 goto clunk_fid;
390 goto error;
391 } 921 }
922 p9_free_req(clnt, req);
392 923
393 if (rc->params.rwalk.nwqid != nwname) { 924 P9_DPRINTK(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids);
925
926 if (nwqids != nwname) {
394 err = -ENOENT; 927 err = -ENOENT;
395 goto clunk_fid; 928 goto clunk_fid;
396 } 929 }
397 930
931 for (count = 0; count < nwqids; count++)
932 P9_DPRINTK(P9_DEBUG_9P, "<<< [%d] %x.%llx.%x\n",
933 count, wqids[count].type, wqids[count].path,
934 wqids[count].version);
935
398 if (nwname) 936 if (nwname)
399 memmove(&fid->qid, 937 memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid));
400 &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1],
401 sizeof(struct p9_qid));
402 else 938 else
403 fid->qid = oldfid->qid; 939 fid->qid = oldfid->qid;
404 940
405 kfree(tc);
406 kfree(rc);
407 return fid; 941 return fid;
408 942
409clunk_fid: 943clunk_fid:
410 kfree(tc); 944 p9_client_clunk(fid);
411 kfree(rc); 945 fid = NULL;
412 rc = NULL;
413 tc = p9_create_tclunk(fid->fid);
414 if (IS_ERR(tc)) {
415 err = PTR_ERR(tc);
416 tc = NULL;
417 goto error;
418 }
419
420 p9_client_rpc(clnt, tc, &rc);
421 946
422error: 947error:
423 kfree(tc);
424 kfree(rc);
425 if (fid && (fid != oldfid)) 948 if (fid && (fid != oldfid))
426 p9_fid_destroy(fid); 949 p9_fid_destroy(fid);
427 950
@@ -432,35 +955,39 @@ EXPORT_SYMBOL(p9_client_walk);
432int p9_client_open(struct p9_fid *fid, int mode) 955int p9_client_open(struct p9_fid *fid, int mode)
433{ 956{
434 int err; 957 int err;
435 struct p9_fcall *tc, *rc;
436 struct p9_client *clnt; 958 struct p9_client *clnt;
959 struct p9_req_t *req;
960 struct p9_qid qid;
961 int iounit;
437 962
438 P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode); 963 P9_DPRINTK(P9_DEBUG_9P, ">>> TOPEN fid %d mode %d\n", fid->fid, mode);
439 err = 0; 964 err = 0;
440 tc = NULL;
441 rc = NULL;
442 clnt = fid->clnt; 965 clnt = fid->clnt;
443 966
444 if (fid->mode != -1) 967 if (fid->mode != -1)
445 return -EINVAL; 968 return -EINVAL;
446 969
447 tc = p9_create_topen(fid->fid, mode); 970 req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode);
448 if (IS_ERR(tc)) { 971 if (IS_ERR(req)) {
449 err = PTR_ERR(tc); 972 err = PTR_ERR(req);
450 tc = NULL; 973 goto error;
451 goto done;
452 } 974 }
453 975
454 err = p9_client_rpc(clnt, tc, &rc); 976 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit);
455 if (err) 977 if (err) {
456 goto done; 978 p9pdu_dump(1, req->rc);
979 goto free_and_error;
980 }
981
982 P9_DPRINTK(P9_DEBUG_9P, "<<< ROPEN qid %x.%llx.%x iounit %x\n",
983 qid.type, qid.path, qid.version, iounit);
457 984
458 fid->mode = mode; 985 fid->mode = mode;
459 fid->iounit = rc->params.ropen.iounit; 986 fid->iounit = iounit;
460 987
461done: 988free_and_error:
462 kfree(tc); 989 p9_free_req(clnt, req);
463 kfree(rc); 990error:
464 return err; 991 return err;
465} 992}
466EXPORT_SYMBOL(p9_client_open); 993EXPORT_SYMBOL(p9_client_open);
@@ -469,37 +996,41 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
469 char *extension) 996 char *extension)
470{ 997{
471 int err; 998 int err;
472 struct p9_fcall *tc, *rc;
473 struct p9_client *clnt; 999 struct p9_client *clnt;
1000 struct p9_req_t *req;
1001 struct p9_qid qid;
1002 int iounit;
474 1003
475 P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid, 1004 P9_DPRINTK(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n",
476 name, perm, mode); 1005 fid->fid, name, perm, mode);
477 err = 0; 1006 err = 0;
478 tc = NULL;
479 rc = NULL;
480 clnt = fid->clnt; 1007 clnt = fid->clnt;
481 1008
482 if (fid->mode != -1) 1009 if (fid->mode != -1)
483 return -EINVAL; 1010 return -EINVAL;
484 1011
485 tc = p9_create_tcreate(fid->fid, name, perm, mode, extension, 1012 req = p9_client_rpc(clnt, P9_TCREATE, "dsdb?s", fid->fid, name, perm,
486 clnt->dotu); 1013 mode, extension);
487 if (IS_ERR(tc)) { 1014 if (IS_ERR(req)) {
488 err = PTR_ERR(tc); 1015 err = PTR_ERR(req);
489 tc = NULL; 1016 goto error;
490 goto done;
491 } 1017 }
492 1018
493 err = p9_client_rpc(clnt, tc, &rc); 1019 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit);
494 if (err) 1020 if (err) {
495 goto done; 1021 p9pdu_dump(1, req->rc);
1022 goto free_and_error;
1023 }
1024
1025 P9_DPRINTK(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n",
1026 qid.type, qid.path, qid.version, iounit);
496 1027
497 fid->mode = mode; 1028 fid->mode = mode;
498 fid->iounit = rc->params.ropen.iounit; 1029 fid->iounit = iounit;
499 1030
500done: 1031free_and_error:
501 kfree(tc); 1032 p9_free_req(clnt, req);
502 kfree(rc); 1033error:
503 return err; 1034 return err;
504} 1035}
505EXPORT_SYMBOL(p9_client_fcreate); 1036EXPORT_SYMBOL(p9_client_fcreate);
@@ -507,31 +1038,25 @@ EXPORT_SYMBOL(p9_client_fcreate);
507int p9_client_clunk(struct p9_fid *fid) 1038int p9_client_clunk(struct p9_fid *fid)
508{ 1039{
509 int err; 1040 int err;
510 struct p9_fcall *tc, *rc;
511 struct p9_client *clnt; 1041 struct p9_client *clnt;
1042 struct p9_req_t *req;
512 1043
513 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 1044 P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid);
514 err = 0; 1045 err = 0;
515 tc = NULL;
516 rc = NULL;
517 clnt = fid->clnt; 1046 clnt = fid->clnt;
518 1047
519 tc = p9_create_tclunk(fid->fid); 1048 req = p9_client_rpc(clnt, P9_TCLUNK, "d", fid->fid);
520 if (IS_ERR(tc)) { 1049 if (IS_ERR(req)) {
521 err = PTR_ERR(tc); 1050 err = PTR_ERR(req);
522 tc = NULL; 1051 goto error;
523 goto done;
524 } 1052 }
525 1053
526 err = p9_client_rpc(clnt, tc, &rc); 1054 P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid);
527 if (err)
528 goto done;
529 1055
1056 p9_free_req(clnt, req);
530 p9_fid_destroy(fid); 1057 p9_fid_destroy(fid);
531 1058
532done: 1059error:
533 kfree(tc);
534 kfree(rc);
535 return err; 1060 return err;
536} 1061}
537EXPORT_SYMBOL(p9_client_clunk); 1062EXPORT_SYMBOL(p9_client_clunk);
@@ -539,157 +1064,41 @@ EXPORT_SYMBOL(p9_client_clunk);
539int p9_client_remove(struct p9_fid *fid) 1064int p9_client_remove(struct p9_fid *fid)
540{ 1065{
541 int err; 1066 int err;
542 struct p9_fcall *tc, *rc;
543 struct p9_client *clnt; 1067 struct p9_client *clnt;
1068 struct p9_req_t *req;
544 1069
545 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 1070 P9_DPRINTK(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid);
546 err = 0; 1071 err = 0;
547 tc = NULL;
548 rc = NULL;
549 clnt = fid->clnt; 1072 clnt = fid->clnt;
550 1073
551 tc = p9_create_tremove(fid->fid); 1074 req = p9_client_rpc(clnt, P9_TREMOVE, "d", fid->fid);
552 if (IS_ERR(tc)) { 1075 if (IS_ERR(req)) {
553 err = PTR_ERR(tc); 1076 err = PTR_ERR(req);
554 tc = NULL; 1077 goto error;
555 goto done;
556 } 1078 }
557 1079
558 err = p9_client_rpc(clnt, tc, &rc); 1080 P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid);
559 if (err)
560 goto done;
561 1081
1082 p9_free_req(clnt, req);
562 p9_fid_destroy(fid); 1083 p9_fid_destroy(fid);
563 1084
564done:
565 kfree(tc);
566 kfree(rc);
567 return err;
568}
569EXPORT_SYMBOL(p9_client_remove);
570
571int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count)
572{
573 int err, n, rsize, total;
574 struct p9_fcall *tc, *rc;
575 struct p9_client *clnt;
576
577 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid,
578 (long long unsigned) offset, count);
579 err = 0;
580 tc = NULL;
581 rc = NULL;
582 clnt = fid->clnt;
583 total = 0;
584
585 rsize = fid->iounit;
586 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
587 rsize = clnt->msize - P9_IOHDRSZ;
588
589 do {
590 if (count < rsize)
591 rsize = count;
592
593 tc = p9_create_tread(fid->fid, offset, rsize);
594 if (IS_ERR(tc)) {
595 err = PTR_ERR(tc);
596 tc = NULL;
597 goto error;
598 }
599
600 err = p9_client_rpc(clnt, tc, &rc);
601 if (err)
602 goto error;
603
604 n = rc->params.rread.count;
605 if (n > count)
606 n = count;
607
608 memmove(data, rc->params.rread.data, n);
609 count -= n;
610 data += n;
611 offset += n;
612 total += n;
613 kfree(tc);
614 tc = NULL;
615 kfree(rc);
616 rc = NULL;
617 } while (count > 0 && n == rsize);
618
619 return total;
620
621error: 1085error:
622 kfree(tc);
623 kfree(rc);
624 return err; 1086 return err;
625} 1087}
626EXPORT_SYMBOL(p9_client_read); 1088EXPORT_SYMBOL(p9_client_remove);
627
628int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count)
629{
630 int err, n, rsize, total;
631 struct p9_fcall *tc, *rc;
632 struct p9_client *clnt;
633
634 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
635 (long long unsigned) offset, count);
636 err = 0;
637 tc = NULL;
638 rc = NULL;
639 clnt = fid->clnt;
640 total = 0;
641
642 rsize = fid->iounit;
643 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
644 rsize = clnt->msize - P9_IOHDRSZ;
645
646 do {
647 if (count < rsize)
648 rsize = count;
649
650 tc = p9_create_twrite(fid->fid, offset, rsize, data);
651 if (IS_ERR(tc)) {
652 err = PTR_ERR(tc);
653 tc = NULL;
654 goto error;
655 }
656
657 err = p9_client_rpc(clnt, tc, &rc);
658 if (err)
659 goto error;
660
661 n = rc->params.rread.count;
662 count -= n;
663 data += n;
664 offset += n;
665 total += n;
666 kfree(tc);
667 tc = NULL;
668 kfree(rc);
669 rc = NULL;
670 } while (count > 0);
671
672 return total;
673
674error:
675 kfree(tc);
676 kfree(rc);
677 return err;
678}
679EXPORT_SYMBOL(p9_client_write);
680 1089
681int 1090int
682p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count) 1091p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
1092 u32 count)
683{ 1093{
684 int err, n, rsize, total; 1094 int err, rsize, total;
685 struct p9_fcall *tc, *rc;
686 struct p9_client *clnt; 1095 struct p9_client *clnt;
1096 struct p9_req_t *req;
1097 char *dataptr;
687 1098
688 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, 1099 P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", fid->fid,
689 (long long unsigned) offset, count); 1100 (long long unsigned) offset, count);
690 err = 0; 1101 err = 0;
691 tc = NULL;
692 rc = NULL;
693 clnt = fid->clnt; 1102 clnt = fid->clnt;
694 total = 0; 1103 total = 0;
695 1104
@@ -697,63 +1106,57 @@ p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count)
697 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 1106 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
698 rsize = clnt->msize - P9_IOHDRSZ; 1107 rsize = clnt->msize - P9_IOHDRSZ;
699 1108
700 do { 1109 if (count < rsize)
701 if (count < rsize) 1110 rsize = count;
702 rsize = count;
703 1111
704 tc = p9_create_tread(fid->fid, offset, rsize); 1112 req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize);
705 if (IS_ERR(tc)) { 1113 if (IS_ERR(req)) {
706 err = PTR_ERR(tc); 1114 err = PTR_ERR(req);
707 tc = NULL; 1115 goto error;
708 goto error; 1116 }
709 }
710 1117
711 err = p9_client_rpc(clnt, tc, &rc); 1118 err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr);
712 if (err) 1119 if (err) {
713 goto error; 1120 p9pdu_dump(1, req->rc);
1121 goto free_and_error;
1122 }
1123
1124 P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
714 1125
715 n = rc->params.rread.count; 1126 if (data) {
716 if (n > count) 1127 memmove(data, dataptr, count);
717 n = count; 1128 data += count;
1129 }
718 1130
719 err = copy_to_user(data, rc->params.rread.data, n); 1131 if (udata) {
1132 err = copy_to_user(udata, dataptr, count);
720 if (err) { 1133 if (err) {
721 err = -EFAULT; 1134 err = -EFAULT;
722 goto error; 1135 goto free_and_error;
723 } 1136 }
1137 }
724 1138
725 count -= n; 1139 p9_free_req(clnt, req);
726 data += n; 1140 return count;
727 offset += n;
728 total += n;
729 kfree(tc);
730 tc = NULL;
731 kfree(rc);
732 rc = NULL;
733 } while (count > 0 && n == rsize);
734
735 return total;
736 1141
1142free_and_error:
1143 p9_free_req(clnt, req);
737error: 1144error:
738 kfree(tc);
739 kfree(rc);
740 return err; 1145 return err;
741} 1146}
742EXPORT_SYMBOL(p9_client_uread); 1147EXPORT_SYMBOL(p9_client_read);
743 1148
744int 1149int
745p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset, 1150p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
746 u32 count) 1151 u64 offset, u32 count)
747{ 1152{
748 int err, n, rsize, total; 1153 int err, rsize, total;
749 struct p9_fcall *tc, *rc;
750 struct p9_client *clnt; 1154 struct p9_client *clnt;
1155 struct p9_req_t *req;
751 1156
752 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, 1157 P9_DPRINTK(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n",
753 (long long unsigned) offset, count); 1158 fid->fid, (long long unsigned) offset, count);
754 err = 0; 1159 err = 0;
755 tc = NULL;
756 rc = NULL;
757 clnt = fid->clnt; 1160 clnt = fid->clnt;
758 total = 0; 1161 total = 0;
759 1162
@@ -761,325 +1164,114 @@ p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
761 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 1164 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
762 rsize = clnt->msize - P9_IOHDRSZ; 1165 rsize = clnt->msize - P9_IOHDRSZ;
763 1166
764 do { 1167 if (count < rsize)
765 if (count < rsize) 1168 rsize = count;
766 rsize = count; 1169 if (data)
767 1170 req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset,
768 tc = p9_create_twrite_u(fid->fid, offset, rsize, data); 1171 rsize, data);
769 if (IS_ERR(tc)) { 1172 else
770 err = PTR_ERR(tc); 1173 req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset,
771 tc = NULL; 1174 rsize, udata);
772 goto error; 1175 if (IS_ERR(req)) {
773 } 1176 err = PTR_ERR(req);
1177 goto error;
1178 }
774 1179
775 err = p9_client_rpc(clnt, tc, &rc); 1180 err = p9pdu_readf(req->rc, clnt->dotu, "d", &count);
776 if (err) 1181 if (err) {
777 goto error; 1182 p9pdu_dump(1, req->rc);
1183 goto free_and_error;
1184 }
778 1185
779 n = rc->params.rread.count; 1186 P9_DPRINTK(P9_DEBUG_9P, "<<< RWRITE count %d\n", count);
780 count -= n;
781 data += n;
782 offset += n;
783 total += n;
784 kfree(tc);
785 tc = NULL;
786 kfree(rc);
787 rc = NULL;
788 } while (count > 0);
789 1187
790 return total; 1188 p9_free_req(clnt, req);
1189 return count;
791 1190
1191free_and_error:
1192 p9_free_req(clnt, req);
792error: 1193error:
793 kfree(tc);
794 kfree(rc);
795 return err; 1194 return err;
796} 1195}
797EXPORT_SYMBOL(p9_client_uwrite); 1196EXPORT_SYMBOL(p9_client_write);
798
799int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count)
800{
801 int n, total;
802
803 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
804 (long long unsigned) offset, count);
805 n = 0;
806 total = 0;
807 while (count) {
808 n = p9_client_read(fid, data, offset, count);
809 if (n <= 0)
810 break;
811
812 data += n;
813 offset += n;
814 count -= n;
815 total += n;
816 }
817
818 if (n < 0)
819 total = n;
820
821 return total;
822}
823EXPORT_SYMBOL(p9_client_readn);
824 1197
825struct p9_stat *p9_client_stat(struct p9_fid *fid) 1198struct p9_wstat *p9_client_stat(struct p9_fid *fid)
826{ 1199{
827 int err; 1200 int err;
828 struct p9_fcall *tc, *rc;
829 struct p9_client *clnt; 1201 struct p9_client *clnt;
830 struct p9_stat *ret; 1202 struct p9_wstat *ret = kmalloc(sizeof(struct p9_wstat), GFP_KERNEL);
1203 struct p9_req_t *req;
1204 u16 ignored;
1205
1206 P9_DPRINTK(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid);
1207
1208 if (!ret)
1209 return ERR_PTR(-ENOMEM);
831 1210
832 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
833 err = 0; 1211 err = 0;
834 tc = NULL;
835 rc = NULL;
836 ret = NULL;
837 clnt = fid->clnt; 1212 clnt = fid->clnt;
838 1213
839 tc = p9_create_tstat(fid->fid); 1214 req = p9_client_rpc(clnt, P9_TSTAT, "d", fid->fid);
840 if (IS_ERR(tc)) { 1215 if (IS_ERR(req)) {
841 err = PTR_ERR(tc); 1216 err = PTR_ERR(req);
842 tc = NULL;
843 goto error; 1217 goto error;
844 } 1218 }
845 1219
846 err = p9_client_rpc(clnt, tc, &rc); 1220 err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret);
847 if (err) 1221 if (err) {
848 goto error; 1222 ret = ERR_PTR(err);
849 1223 p9pdu_dump(1, req->rc);
850 ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu); 1224 goto free_and_error;
851 if (IS_ERR(ret)) {
852 err = PTR_ERR(ret);
853 ret = NULL;
854 goto error;
855 } 1225 }
856 1226
857 kfree(tc); 1227 P9_DPRINTK(P9_DEBUG_9P,
858 kfree(rc); 1228 "<<< RSTAT sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
859 return ret; 1229 "<<< mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n"
860 1230 "<<< name=%s uid=%s gid=%s muid=%s extension=(%s)\n"
1231 "<<< uid=%d gid=%d n_muid=%d\n",
1232 ret->size, ret->type, ret->dev, ret->qid.type,
1233 ret->qid.path, ret->qid.version, ret->mode,
1234 ret->atime, ret->mtime, ret->length, ret->name,
1235 ret->uid, ret->gid, ret->muid, ret->extension,
1236 ret->n_uid, ret->n_gid, ret->n_muid);
1237
1238free_and_error:
1239 p9_free_req(clnt, req);
861error: 1240error:
862 kfree(tc); 1241 return ret;
863 kfree(rc);
864 kfree(ret);
865 return ERR_PTR(err);
866} 1242}
867EXPORT_SYMBOL(p9_client_stat); 1243EXPORT_SYMBOL(p9_client_stat);
868 1244
869int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) 1245int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
870{ 1246{
871 int err; 1247 int err;
872 struct p9_fcall *tc, *rc; 1248 struct p9_req_t *req;
873 struct p9_client *clnt; 1249 struct p9_client *clnt;
874 1250
875 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 1251 P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid);
1252 P9_DPRINTK(P9_DEBUG_9P,
1253 " sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
1254 " mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n"
1255 " name=%s uid=%s gid=%s muid=%s extension=(%s)\n"
1256 " uid=%d gid=%d n_muid=%d\n",
1257 wst->size, wst->type, wst->dev, wst->qid.type,
1258 wst->qid.path, wst->qid.version, wst->mode,
1259 wst->atime, wst->mtime, wst->length, wst->name,
1260 wst->uid, wst->gid, wst->muid, wst->extension,
1261 wst->n_uid, wst->n_gid, wst->n_muid);
876 err = 0; 1262 err = 0;
877 tc = NULL;
878 rc = NULL;
879 clnt = fid->clnt; 1263 clnt = fid->clnt;
880 1264
881 tc = p9_create_twstat(fid->fid, wst, clnt->dotu); 1265 req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, 0, wst);
882 if (IS_ERR(tc)) { 1266 if (IS_ERR(req)) {
883 err = PTR_ERR(tc); 1267 err = PTR_ERR(req);
884 tc = NULL;
885 goto done;
886 }
887
888 err = p9_client_rpc(clnt, tc, &rc);
889
890done:
891 kfree(tc);
892 kfree(rc);
893 return err;
894}
895EXPORT_SYMBOL(p9_client_wstat);
896
897struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset)
898{
899 int err, n, m;
900 struct p9_fcall *tc, *rc;
901 struct p9_client *clnt;
902 struct p9_stat st, *ret;
903
904 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu\n", fid->fid,
905 (long long unsigned) offset);
906 err = 0;
907 tc = NULL;
908 rc = NULL;
909 ret = NULL;
910 clnt = fid->clnt;
911
912 /* if the offset is below or above the current response, free it */
913 if (offset < fid->rdir_fpos || (fid->rdir_fcall &&
914 offset >= fid->rdir_fpos+fid->rdir_fcall->params.rread.count)) {
915 fid->rdir_pos = 0;
916 if (fid->rdir_fcall)
917 fid->rdir_fpos += fid->rdir_fcall->params.rread.count;
918
919 kfree(fid->rdir_fcall);
920 fid->rdir_fcall = NULL;
921 if (offset < fid->rdir_fpos)
922 fid->rdir_fpos = 0;
923 }
924
925 if (!fid->rdir_fcall) {
926 n = fid->iounit;
927 if (!n || n > clnt->msize-P9_IOHDRSZ)
928 n = clnt->msize - P9_IOHDRSZ;
929
930 while (1) {
931 if (fid->rdir_fcall) {
932 fid->rdir_fpos +=
933 fid->rdir_fcall->params.rread.count;
934 kfree(fid->rdir_fcall);
935 fid->rdir_fcall = NULL;
936 }
937
938 tc = p9_create_tread(fid->fid, fid->rdir_fpos, n);
939 if (IS_ERR(tc)) {
940 err = PTR_ERR(tc);
941 tc = NULL;
942 goto error;
943 }
944
945 err = p9_client_rpc(clnt, tc, &rc);
946 if (err)
947 goto error;
948
949 n = rc->params.rread.count;
950 if (n == 0)
951 goto done;
952
953 fid->rdir_fcall = rc;
954 rc = NULL;
955 if (offset >= fid->rdir_fpos &&
956 offset < fid->rdir_fpos+n)
957 break;
958 }
959
960 fid->rdir_pos = 0;
961 }
962
963 m = offset - fid->rdir_fpos;
964 if (m < 0)
965 goto done;
966
967 n = p9_deserialize_stat(fid->rdir_fcall->params.rread.data + m,
968 fid->rdir_fcall->params.rread.count - m, &st, clnt->dotu);
969
970 if (!n) {
971 err = -EIO;
972 goto error;
973 }
974
975 fid->rdir_pos += n;
976 st.size = n;
977 ret = p9_clone_stat(&st, clnt->dotu);
978 if (IS_ERR(ret)) {
979 err = PTR_ERR(ret);
980 ret = NULL;
981 goto error;
982 }
983
984done:
985 kfree(tc);
986 kfree(rc);
987 return ret;
988
989error:
990 kfree(tc);
991 kfree(rc);
992 kfree(ret);
993 return ERR_PTR(err);
994}
995EXPORT_SYMBOL(p9_client_dirread);
996
997static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu)
998{
999 int n;
1000 char *p;
1001 struct p9_stat *ret;
1002
1003 n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len +
1004 st->muid.len;
1005
1006 if (dotu)
1007 n += st->extension.len;
1008
1009 ret = kmalloc(n, GFP_KERNEL);
1010 if (!ret)
1011 return ERR_PTR(-ENOMEM);
1012
1013 memmove(ret, st, sizeof(struct p9_stat));
1014 p = ((char *) ret) + sizeof(struct p9_stat);
1015 memmove(p, st->name.str, st->name.len);
1016 ret->name.str = p;
1017 p += st->name.len;
1018 memmove(p, st->uid.str, st->uid.len);
1019 ret->uid.str = p;
1020 p += st->uid.len;
1021 memmove(p, st->gid.str, st->gid.len);
1022 ret->gid.str = p;
1023 p += st->gid.len;
1024 memmove(p, st->muid.str, st->muid.len);
1025 ret->muid.str = p;
1026 p += st->muid.len;
1027
1028 if (dotu) {
1029 memmove(p, st->extension.str, st->extension.len);
1030 ret->extension.str = p;
1031 p += st->extension.len;
1032 }
1033
1034 return ret;
1035}
1036
1037static struct p9_fid *p9_fid_create(struct p9_client *clnt)
1038{
1039 int err;
1040 struct p9_fid *fid;
1041
1042 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
1043 fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
1044 if (!fid)
1045 return ERR_PTR(-ENOMEM);
1046
1047 fid->fid = p9_idpool_get(clnt->fidpool);
1048 if (fid->fid < 0) {
1049 err = -ENOSPC;
1050 goto error; 1268 goto error;
1051 } 1269 }
1052 1270
1053 memset(&fid->qid, 0, sizeof(struct p9_qid)); 1271 P9_DPRINTK(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid);
1054 fid->mode = -1;
1055 fid->rdir_fpos = 0;
1056 fid->rdir_pos = 0;
1057 fid->rdir_fcall = NULL;
1058 fid->uid = current->fsuid;
1059 fid->clnt = clnt;
1060 fid->aux = NULL;
1061
1062 spin_lock(&clnt->lock);
1063 list_add(&fid->flist, &clnt->fidlist);
1064 spin_unlock(&clnt->lock);
1065
1066 return fid;
1067 1272
1273 p9_free_req(clnt, req);
1068error: 1274error:
1069 kfree(fid); 1275 return err;
1070 return ERR_PTR(err);
1071}
1072
1073static void p9_fid_destroy(struct p9_fid *fid)
1074{
1075 struct p9_client *clnt;
1076
1077 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
1078 clnt = fid->clnt;
1079 p9_idpool_put(fid->fid, clnt->fidpool);
1080 spin_lock(&clnt->lock);
1081 list_del(&fid->flist);
1082 spin_unlock(&clnt->lock);
1083 kfree(fid->rdir_fcall);
1084 kfree(fid);
1085} 1276}
1277EXPORT_SYMBOL(p9_client_wstat);