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