client.c revision 1bab88b2310998de18b32529a27ea835d164254a
1/* 2 * net/9p/clnt.c 3 * 4 * 9P Client 5 * 6 * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com> 7 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 11 * as published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to: 20 * Free Software Foundation 21 * 51 Franklin Street, Fifth Floor 22 * Boston, MA 02111-1301 USA 23 * 24 */ 25 26#include <linux/module.h> 27#include <linux/errno.h> 28#include <linux/fs.h> 29#include <linux/poll.h> 30#include <linux/idr.h> 31#include <linux/mutex.h> 32#include <linux/sched.h> 33#include <linux/uaccess.h> 34#include <net/9p/9p.h> 35#include <linux/parser.h> 36#include <net/9p/client.h> 37#include <net/9p/transport.h> 38#include "protocol.h" 39 40/* 41 * Client Option Parsing (code inspired by NFS code) 42 * - a little lazy - parse all client options 43 */ 44 45enum { 46 Opt_msize, 47 Opt_trans, 48 Opt_legacy, 49 Opt_err, 50}; 51 52static const match_table_t tokens = { 53 {Opt_msize, "msize=%u"}, 54 {Opt_legacy, "noextend"}, 55 {Opt_trans, "trans=%s"}, 56 {Opt_err, NULL}, 57}; 58 59static struct p9_req_t * 60p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); 61 62/** 63 * v9fs_parse_options - parse mount options into session structure 64 * @options: options string passed from mount 65 * @v9ses: existing v9fs session information 66 * 67 * Return 0 upon success, -ERRNO upon failure 68 */ 69 70static int parse_opts(char *opts, struct p9_client *clnt) 71{ 72 char *options; 73 char *p; 74 substring_t args[MAX_OPT_ARGS]; 75 int option; 76 int ret = 0; 77 78 clnt->dotu = 1; 79 clnt->msize = 8192; 80 81 if (!opts) 82 return 0; 83 84 options = kstrdup(opts, GFP_KERNEL); 85 if (!options) { 86 P9_DPRINTK(P9_DEBUG_ERROR, 87 "failed to allocate copy of option string\n"); 88 return -ENOMEM; 89 } 90 91 while ((p = strsep(&options, ",")) != NULL) { 92 int token; 93 if (!*p) 94 continue; 95 token = match_token(p, tokens, args); 96 if (token < Opt_trans) { 97 int r = match_int(&args[0], &option); 98 if (r < 0) { 99 P9_DPRINTK(P9_DEBUG_ERROR, 100 "integer field, but no integer?\n"); 101 ret = r; 102 continue; 103 } 104 } 105 switch (token) { 106 case Opt_msize: 107 clnt->msize = option; 108 break; 109 case Opt_trans: 110 clnt->trans_mod = v9fs_get_trans_by_name(&args[0]); 111 break; 112 case Opt_legacy: 113 clnt->dotu = 0; 114 break; 115 default: 116 continue; 117 } 118 } 119 120 if (!clnt->trans_mod) 121 clnt->trans_mod = v9fs_get_default_trans(); 122 123 kfree(options); 124 return ret; 125} 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 kfree(req->wq); 193 req->tc = req->rc = NULL; 194 req->wq = NULL; 195 return ERR_PTR(-ENOMEM); 196 } 197 req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall); 198 req->tc->capacity = c->msize; 199 req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall); 200 req->rc->capacity = c->msize; 201 } 202 203 p9pdu_reset(req->tc); 204 p9pdu_reset(req->rc); 205 206 req->tc->tag = tag-1; 207 req->status = REQ_STATUS_ALLOC; 208 209 return &c->reqs[row][col]; 210} 211 212/** 213 * p9_tag_lookup - lookup a request by tag 214 * @c: client session to lookup tag within 215 * @tag: numeric id for transaction 216 * 217 */ 218 219struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag) 220{ 221 int row, col; 222 223 /* This looks up the original request by tag so we know which 224 * buffer to read the data into */ 225 tag++; 226 227 BUG_ON(tag >= c->max_tag); 228 229 row = tag / P9_ROW_MAXTAG; 230 col = tag % P9_ROW_MAXTAG; 231 232 return &c->reqs[row][col]; 233} 234EXPORT_SYMBOL(p9_tag_lookup); 235 236/** 237 * p9_tag_init - setup tags structure and contents 238 * @tags: tags structure from the client struct 239 * 240 * This initializes the tags structure for each client instance. 241 * 242 */ 243 244static int p9_tag_init(struct p9_client *c) 245{ 246 int err = 0; 247 248 c->tagpool = p9_idpool_create(); 249 if (IS_ERR(c->tagpool)) { 250 err = PTR_ERR(c->tagpool); 251 c->tagpool = NULL; 252 goto error; 253 } 254 255 p9_idpool_get(c->tagpool); /* reserve tag 0 */ 256 257 c->max_tag = 0; 258error: 259 return err; 260} 261 262/** 263 * p9_tag_cleanup - cleans up tags structure and reclaims resources 264 * @tags: tags structure from the client struct 265 * 266 * This frees resources associated with the tags structure 267 * 268 */ 269static void p9_tag_cleanup(struct p9_client *c) 270{ 271 int row, col; 272 273 /* check to insure all requests are idle */ 274 for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { 275 for (col = 0; col < P9_ROW_MAXTAG; col++) { 276 if (c->reqs[row][col].status != REQ_STATUS_IDLE) { 277 P9_DPRINTK(P9_DEBUG_MUX, 278 "Attempting to cleanup non-free tag %d,%d\n", 279 row, col); 280 /* TODO: delay execution of cleanup */ 281 return; 282 } 283 } 284 } 285 286 if (c->tagpool) 287 p9_idpool_destroy(c->tagpool); 288 289 /* free requests associated with tags */ 290 for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { 291 for (col = 0; col < P9_ROW_MAXTAG; col++) { 292 kfree(c->reqs[row][col].wq); 293 kfree(c->reqs[row][col].tc); 294 kfree(c->reqs[row][col].rc); 295 } 296 kfree(c->reqs[row]); 297 } 298 c->max_tag = 0; 299} 300 301/** 302 * p9_free_req - free a request and clean-up as necessary 303 * c: client state 304 * r: request to release 305 * 306 */ 307 308static void p9_free_req(struct p9_client *c, struct p9_req_t *r) 309{ 310 int tag = r->tc->tag; 311 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag); 312 313 r->status = REQ_STATUS_IDLE; 314 if (tag != P9_NOTAG && p9_idpool_check(tag, c->tagpool)) 315 p9_idpool_put(tag, c->tagpool); 316} 317 318/** 319 * p9_client_cb - call back from transport to client 320 * c: client state 321 * req: request received 322 * 323 */ 324void p9_client_cb(struct p9_client *c, struct p9_req_t *req) 325{ 326 P9_DPRINTK(P9_DEBUG_MUX, " tag %d\n", req->tc->tag); 327 wake_up(req->wq); 328 P9_DPRINTK(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag); 329} 330EXPORT_SYMBOL(p9_client_cb); 331 332/** 333 * p9_parse_header - parse header arguments out of a packet 334 * @pdu: packet to parse 335 * @size: size of packet 336 * @type: type of request 337 * @tag: tag of packet 338 * @rewind: set if we need to rewind offset afterwards 339 */ 340 341int 342p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, int16_t *tag, 343 int rewind) 344{ 345 int8_t r_type; 346 int16_t r_tag; 347 int32_t r_size; 348 int offset = pdu->offset; 349 int err; 350 351 pdu->offset = 0; 352 if (pdu->size == 0) 353 pdu->size = 7; 354 355 err = p9pdu_readf(pdu, 0, "dbw", &r_size, &r_type, &r_tag); 356 if (err) 357 goto rewind_and_exit; 358 359 pdu->size = r_size; 360 pdu->id = r_type; 361 pdu->tag = r_tag; 362 363 P9_DPRINTK(P9_DEBUG_9P, "<<< size=%d type: %d tag: %d\n", pdu->size, 364 pdu->id, pdu->tag); 365 366 if (type) 367 *type = r_type; 368 if (tag) 369 *tag = r_tag; 370 if (size) 371 *size = r_size; 372 373 374rewind_and_exit: 375 if (rewind) 376 pdu->offset = offset; 377 return err; 378} 379EXPORT_SYMBOL(p9_parse_header); 380 381/** 382 * p9_check_errors - check 9p packet for error return and process it 383 * @c: current client instance 384 * @req: request to parse and check for error conditions 385 * 386 * returns error code if one is discovered, otherwise returns 0 387 * 388 * this will have to be more complicated if we have multiple 389 * error packet types 390 */ 391 392static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) 393{ 394 int8_t type; 395 int err; 396 397 err = p9_parse_header(req->rc, NULL, &type, NULL, 0); 398 if (err) { 399 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err); 400 return err; 401 } 402 403 if (type == P9_RERROR) { 404 int ecode; 405 char *ename; 406 407 err = p9pdu_readf(req->rc, c->dotu, "s?d", &ename, &ecode); 408 if (err) { 409 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", 410 err); 411 return err; 412 } 413 414 if (c->dotu) 415 err = -ecode; 416 417 if (!err) { 418 err = p9_errstr2errno(ename, strlen(ename)); 419 420 /* string match failed */ 421 if (!err) 422 err = -ESERVERFAULT; 423 } 424 425 P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); 426 427 kfree(ename); 428 } else 429 err = 0; 430 431 return err; 432} 433 434/** 435 * p9_client_flush - flush (cancel) a request 436 * c: client state 437 * req: request to cancel 438 * 439 * This sents a flush for a particular requests and links 440 * the flush request to the original request. The current 441 * code only supports a single flush request although the protocol 442 * allows for multiple flush requests to be sent for a single request. 443 * 444 */ 445 446static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq) 447{ 448 struct p9_req_t *req; 449 int16_t oldtag; 450 int err; 451 452 err = p9_parse_header(oldreq->tc, NULL, NULL, &oldtag, 1); 453 if (err) 454 return err; 455 456 P9_DPRINTK(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag); 457 458 req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag); 459 if (IS_ERR(req)) 460 return PTR_ERR(req); 461 462 463 /* if we haven't received a response for oldreq, 464 remove it from the list. */ 465 spin_lock(&c->lock); 466 if (oldreq->status == REQ_STATUS_FLSH) 467 list_del(&oldreq->req_list); 468 spin_unlock(&c->lock); 469 470 p9_free_req(c, req); 471 return 0; 472} 473 474/** 475 * p9_client_rpc - issue a request and wait for a response 476 * @c: client session 477 * @type: type of request 478 * @fmt: protocol format string (see protocol.c) 479 * 480 * Returns request structure (which client must free using p9_free_req) 481 */ 482 483static struct p9_req_t * 484p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) 485{ 486 va_list ap; 487 int tag, err; 488 struct p9_req_t *req; 489 unsigned long flags; 490 int sigpending; 491 492 P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type); 493 494 if (c->status != Connected) 495 return ERR_PTR(-EIO); 496 497 if (signal_pending(current)) { 498 sigpending = 1; 499 clear_thread_flag(TIF_SIGPENDING); 500 } else 501 sigpending = 0; 502 503 tag = P9_NOTAG; 504 if (type != P9_TVERSION) { 505 tag = p9_idpool_get(c->tagpool); 506 if (tag < 0) 507 return ERR_PTR(-ENOMEM); 508 } 509 510 req = p9_tag_alloc(c, tag); 511 if (IS_ERR(req)) 512 return req; 513 514 /* marshall the data */ 515 p9pdu_prepare(req->tc, tag, type); 516 va_start(ap, fmt); 517 err = p9pdu_vwritef(req->tc, c->dotu, fmt, ap); 518 va_end(ap); 519 p9pdu_finalize(req->tc); 520 521 err = c->trans_mod->request(c, req); 522 if (err < 0) { 523 c->status = Disconnected; 524 goto reterr; 525 } 526 527 P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d\n", req->wq, tag); 528 err = wait_event_interruptible(*req->wq, 529 req->status >= REQ_STATUS_RCVD); 530 P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d returned %d\n", 531 req->wq, tag, err); 532 533 if (req->status == REQ_STATUS_ERROR) { 534 P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); 535 err = req->t_err; 536 } 537 538 if ((err == -ERESTARTSYS) && (c->status == Connected)) { 539 P9_DPRINTK(P9_DEBUG_MUX, "flushing\n"); 540 sigpending = 1; 541 clear_thread_flag(TIF_SIGPENDING); 542 543 if (c->trans_mod->cancel(c, req)) 544 p9_client_flush(c, req); 545 546 /* if we received the response anyway, don't signal error */ 547 if (req->status == REQ_STATUS_RCVD) 548 err = 0; 549 } 550 551 if (sigpending) { 552 spin_lock_irqsave(¤t->sighand->siglock, flags); 553 recalc_sigpending(); 554 spin_unlock_irqrestore(¤t->sighand->siglock, flags); 555 } 556 557 if (err < 0) 558 goto reterr; 559 560 err = p9_check_errors(c, req); 561 if (!err) { 562 P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d\n", c, type); 563 return req; 564 } 565 566reterr: 567 P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d error: %d\n", c, type, 568 err); 569 p9_free_req(c, req); 570 return ERR_PTR(err); 571} 572 573static struct p9_fid *p9_fid_create(struct p9_client *clnt) 574{ 575 int ret; 576 struct p9_fid *fid; 577 unsigned long flags; 578 579 P9_DPRINTK(P9_DEBUG_FID, "clnt %p\n", clnt); 580 fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL); 581 if (!fid) 582 return ERR_PTR(-ENOMEM); 583 584 ret = p9_idpool_get(clnt->fidpool); 585 if (ret < 0) { 586 ret = -ENOSPC; 587 goto error; 588 } 589 fid->fid = ret; 590 591 memset(&fid->qid, 0, sizeof(struct p9_qid)); 592 fid->mode = -1; 593 fid->rdir_fpos = 0; 594 fid->uid = current_fsuid(); 595 fid->clnt = clnt; 596 fid->aux = NULL; 597 598 spin_lock_irqsave(&clnt->lock, flags); 599 list_add(&fid->flist, &clnt->fidlist); 600 spin_unlock_irqrestore(&clnt->lock, flags); 601 602 return fid; 603 604error: 605 kfree(fid); 606 return ERR_PTR(ret); 607} 608 609static void p9_fid_destroy(struct p9_fid *fid) 610{ 611 struct p9_client *clnt; 612 unsigned long flags; 613 614 P9_DPRINTK(P9_DEBUG_FID, "fid %d\n", fid->fid); 615 clnt = fid->clnt; 616 p9_idpool_put(fid->fid, clnt->fidpool); 617 spin_lock_irqsave(&clnt->lock, flags); 618 list_del(&fid->flist); 619 spin_unlock_irqrestore(&clnt->lock, flags); 620 kfree(fid); 621} 622 623int p9_client_version(struct p9_client *c) 624{ 625 int err = 0; 626 struct p9_req_t *req; 627 char *version; 628 int msize; 629 630 P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n", 631 c->msize, c->dotu); 632 req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize, 633 c->dotu ? "9P2000.u" : "9P2000"); 634 if (IS_ERR(req)) 635 return PTR_ERR(req); 636 637 err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version); 638 if (err) { 639 P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); 640 p9pdu_dump(1, req->rc); 641 goto error; 642 } 643 644 P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version); 645 if (!memcmp(version, "9P2000.u", 8)) 646 c->dotu = 1; 647 else if (!memcmp(version, "9P2000", 6)) 648 c->dotu = 0; 649 else { 650 err = -EREMOTEIO; 651 goto error; 652 } 653 654 if (msize < c->msize) 655 c->msize = msize; 656 657error: 658 kfree(version); 659 p9_free_req(c, req); 660 661 return err; 662} 663EXPORT_SYMBOL(p9_client_version); 664 665struct p9_client *p9_client_create(const char *dev_name, char *options) 666{ 667 int err; 668 struct p9_client *clnt; 669 670 err = 0; 671 clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL); 672 if (!clnt) 673 return ERR_PTR(-ENOMEM); 674 675 clnt->trans_mod = NULL; 676 clnt->trans = NULL; 677 spin_lock_init(&clnt->lock); 678 INIT_LIST_HEAD(&clnt->fidlist); 679 clnt->fidpool = p9_idpool_create(); 680 if (IS_ERR(clnt->fidpool)) { 681 err = PTR_ERR(clnt->fidpool); 682 clnt->fidpool = NULL; 683 goto error; 684 } 685 686 p9_tag_init(clnt); 687 688 err = parse_opts(options, clnt); 689 if (err < 0) 690 goto error; 691 692 if (clnt->trans_mod == NULL) { 693 err = -EPROTONOSUPPORT; 694 P9_DPRINTK(P9_DEBUG_ERROR, 695 "No transport defined or default transport\n"); 696 goto error; 697 } 698 699 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d dotu %d\n", 700 clnt, clnt->trans_mod, clnt->msize, clnt->dotu); 701 702 err = clnt->trans_mod->create(clnt, dev_name, options); 703 if (err) 704 goto error; 705 706 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) 707 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; 708 709 err = p9_client_version(clnt); 710 if (err) 711 goto error; 712 713 return clnt; 714 715error: 716 p9_client_destroy(clnt); 717 return ERR_PTR(err); 718} 719EXPORT_SYMBOL(p9_client_create); 720 721void p9_client_destroy(struct p9_client *clnt) 722{ 723 struct p9_fid *fid, *fidptr; 724 725 P9_DPRINTK(P9_DEBUG_MUX, "clnt %p\n", clnt); 726 727 if (clnt->trans_mod) 728 clnt->trans_mod->close(clnt); 729 730 v9fs_put_trans(clnt->trans_mod); 731 732 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) 733 p9_fid_destroy(fid); 734 735 if (clnt->fidpool) 736 p9_idpool_destroy(clnt->fidpool); 737 738 p9_tag_cleanup(clnt); 739 740 kfree(clnt); 741} 742EXPORT_SYMBOL(p9_client_destroy); 743 744void p9_client_disconnect(struct p9_client *clnt) 745{ 746 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); 747 clnt->status = Disconnected; 748} 749EXPORT_SYMBOL(p9_client_disconnect); 750 751struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, 752 char *uname, u32 n_uname, char *aname) 753{ 754 int err; 755 struct p9_req_t *req; 756 struct p9_fid *fid; 757 struct p9_qid qid; 758 759 P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n", 760 afid ? afid->fid : -1, uname, aname); 761 err = 0; 762 763 fid = p9_fid_create(clnt); 764 if (IS_ERR(fid)) { 765 err = PTR_ERR(fid); 766 fid = NULL; 767 goto error; 768 } 769 770 req = p9_client_rpc(clnt, P9_TATTACH, "ddss?d", fid->fid, 771 afid ? afid->fid : P9_NOFID, uname, aname, n_uname); 772 if (IS_ERR(req)) { 773 err = PTR_ERR(req); 774 goto error; 775 } 776 777 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); 778 if (err) { 779 p9pdu_dump(1, req->rc); 780 p9_free_req(clnt, req); 781 goto error; 782 } 783 784 P9_DPRINTK(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n", 785 qid.type, 786 (unsigned long long)qid.path, 787 qid.version); 788 789 memmove(&fid->qid, &qid, sizeof(struct p9_qid)); 790 791 p9_free_req(clnt, req); 792 return fid; 793 794error: 795 if (fid) 796 p9_fid_destroy(fid); 797 return ERR_PTR(err); 798} 799EXPORT_SYMBOL(p9_client_attach); 800 801struct p9_fid * 802p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname) 803{ 804 int err; 805 struct p9_req_t *req; 806 struct p9_qid qid; 807 struct p9_fid *afid; 808 809 P9_DPRINTK(P9_DEBUG_9P, ">>> TAUTH uname %s aname %s\n", uname, aname); 810 err = 0; 811 812 afid = p9_fid_create(clnt); 813 if (IS_ERR(afid)) { 814 err = PTR_ERR(afid); 815 afid = NULL; 816 goto error; 817 } 818 819 req = p9_client_rpc(clnt, P9_TAUTH, "dss?d", 820 afid ? afid->fid : P9_NOFID, uname, aname, n_uname); 821 if (IS_ERR(req)) { 822 err = PTR_ERR(req); 823 goto error; 824 } 825 826 err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid); 827 if (err) { 828 p9pdu_dump(1, req->rc); 829 p9_free_req(clnt, req); 830 goto error; 831 } 832 833 P9_DPRINTK(P9_DEBUG_9P, "<<< RAUTH qid %x.%llx.%x\n", 834 qid.type, 835 (unsigned long long)qid.path, 836 qid.version); 837 838 memmove(&afid->qid, &qid, sizeof(struct p9_qid)); 839 p9_free_req(clnt, req); 840 return afid; 841 842error: 843 if (afid) 844 p9_fid_destroy(afid); 845 return ERR_PTR(err); 846} 847EXPORT_SYMBOL(p9_client_auth); 848 849struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, 850 int clone) 851{ 852 int err; 853 struct p9_client *clnt; 854 struct p9_fid *fid; 855 struct p9_qid *wqids; 856 struct p9_req_t *req; 857 int16_t nwqids, count; 858 859 err = 0; 860 clnt = oldfid->clnt; 861 if (clone) { 862 fid = p9_fid_create(clnt); 863 if (IS_ERR(fid)) { 864 err = PTR_ERR(fid); 865 fid = NULL; 866 goto error; 867 } 868 869 fid->uid = oldfid->uid; 870 } else 871 fid = oldfid; 872 873 874 P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n", 875 oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL); 876 877 req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid, 878 nwname, wnames); 879 if (IS_ERR(req)) { 880 err = PTR_ERR(req); 881 goto error; 882 } 883 884 err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids); 885 if (err) { 886 p9pdu_dump(1, req->rc); 887 p9_free_req(clnt, req); 888 goto clunk_fid; 889 } 890 p9_free_req(clnt, req); 891 892 P9_DPRINTK(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids); 893 894 if (nwqids != nwname) { 895 err = -ENOENT; 896 goto clunk_fid; 897 } 898 899 for (count = 0; count < nwqids; count++) 900 P9_DPRINTK(P9_DEBUG_9P, "<<< [%d] %x.%llx.%x\n", 901 count, wqids[count].type, 902 (unsigned long long)wqids[count].path, 903 wqids[count].version); 904 905 if (nwname) 906 memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid)); 907 else 908 fid->qid = oldfid->qid; 909 910 return fid; 911 912clunk_fid: 913 p9_client_clunk(fid); 914 fid = NULL; 915 916error: 917 if (fid && (fid != oldfid)) 918 p9_fid_destroy(fid); 919 920 return ERR_PTR(err); 921} 922EXPORT_SYMBOL(p9_client_walk); 923 924int p9_client_open(struct p9_fid *fid, int mode) 925{ 926 int err; 927 struct p9_client *clnt; 928 struct p9_req_t *req; 929 struct p9_qid qid; 930 int iounit; 931 932 P9_DPRINTK(P9_DEBUG_9P, ">>> TOPEN fid %d mode %d\n", fid->fid, mode); 933 err = 0; 934 clnt = fid->clnt; 935 936 if (fid->mode != -1) 937 return -EINVAL; 938 939 req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode); 940 if (IS_ERR(req)) { 941 err = PTR_ERR(req); 942 goto error; 943 } 944 945 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); 946 if (err) { 947 p9pdu_dump(1, req->rc); 948 goto free_and_error; 949 } 950 951 P9_DPRINTK(P9_DEBUG_9P, "<<< ROPEN qid %x.%llx.%x iounit %x\n", 952 qid.type, 953 (unsigned long long)qid.path, 954 qid.version, iounit); 955 956 fid->mode = mode; 957 fid->iounit = iounit; 958 959free_and_error: 960 p9_free_req(clnt, req); 961error: 962 return err; 963} 964EXPORT_SYMBOL(p9_client_open); 965 966int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, 967 char *extension) 968{ 969 int err; 970 struct p9_client *clnt; 971 struct p9_req_t *req; 972 struct p9_qid qid; 973 int iounit; 974 975 P9_DPRINTK(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n", 976 fid->fid, name, perm, mode); 977 err = 0; 978 clnt = fid->clnt; 979 980 if (fid->mode != -1) 981 return -EINVAL; 982 983 req = p9_client_rpc(clnt, P9_TCREATE, "dsdb?s", fid->fid, name, perm, 984 mode, extension); 985 if (IS_ERR(req)) { 986 err = PTR_ERR(req); 987 goto error; 988 } 989 990 err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); 991 if (err) { 992 p9pdu_dump(1, req->rc); 993 goto free_and_error; 994 } 995 996 P9_DPRINTK(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n", 997 qid.type, 998 (unsigned long long)qid.path, 999 qid.version, iounit); 1000 1001 fid->mode = mode; 1002 fid->iounit = iounit; 1003 1004free_and_error: 1005 p9_free_req(clnt, req); 1006error: 1007 return err; 1008} 1009EXPORT_SYMBOL(p9_client_fcreate); 1010 1011int p9_client_clunk(struct p9_fid *fid) 1012{ 1013 int err; 1014 struct p9_client *clnt; 1015 struct p9_req_t *req; 1016 1017 P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid); 1018 err = 0; 1019 clnt = fid->clnt; 1020 1021 req = p9_client_rpc(clnt, P9_TCLUNK, "d", fid->fid); 1022 if (IS_ERR(req)) { 1023 err = PTR_ERR(req); 1024 goto error; 1025 } 1026 1027 P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid); 1028 1029 p9_free_req(clnt, req); 1030 p9_fid_destroy(fid); 1031 1032error: 1033 return err; 1034} 1035EXPORT_SYMBOL(p9_client_clunk); 1036 1037int p9_client_remove(struct p9_fid *fid) 1038{ 1039 int err; 1040 struct p9_client *clnt; 1041 struct p9_req_t *req; 1042 1043 P9_DPRINTK(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid); 1044 err = 0; 1045 clnt = fid->clnt; 1046 1047 req = p9_client_rpc(clnt, P9_TREMOVE, "d", fid->fid); 1048 if (IS_ERR(req)) { 1049 err = PTR_ERR(req); 1050 goto error; 1051 } 1052 1053 P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid); 1054 1055 p9_free_req(clnt, req); 1056 p9_fid_destroy(fid); 1057 1058error: 1059 return err; 1060} 1061EXPORT_SYMBOL(p9_client_remove); 1062 1063int 1064p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, 1065 u32 count) 1066{ 1067 int err, rsize, total; 1068 struct p9_client *clnt; 1069 struct p9_req_t *req; 1070 char *dataptr; 1071 1072 P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", fid->fid, 1073 (long long unsigned) offset, count); 1074 err = 0; 1075 clnt = fid->clnt; 1076 total = 0; 1077 1078 rsize = fid->iounit; 1079 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 1080 rsize = clnt->msize - P9_IOHDRSZ; 1081 1082 if (count < rsize) 1083 rsize = count; 1084 1085 req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize); 1086 if (IS_ERR(req)) { 1087 err = PTR_ERR(req); 1088 goto error; 1089 } 1090 1091 err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr); 1092 if (err) { 1093 p9pdu_dump(1, req->rc); 1094 goto free_and_error; 1095 } 1096 1097 P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); 1098 1099 if (data) { 1100 memmove(data, dataptr, count); 1101 data += count; 1102 } 1103 1104 if (udata) { 1105 err = copy_to_user(udata, dataptr, count); 1106 if (err) { 1107 err = -EFAULT; 1108 goto free_and_error; 1109 } 1110 } 1111 1112 p9_free_req(clnt, req); 1113 return count; 1114 1115free_and_error: 1116 p9_free_req(clnt, req); 1117error: 1118 return err; 1119} 1120EXPORT_SYMBOL(p9_client_read); 1121 1122int 1123p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, 1124 u64 offset, u32 count) 1125{ 1126 int err, rsize, total; 1127 struct p9_client *clnt; 1128 struct p9_req_t *req; 1129 1130 P9_DPRINTK(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n", 1131 fid->fid, (long long unsigned) offset, count); 1132 err = 0; 1133 clnt = fid->clnt; 1134 total = 0; 1135 1136 rsize = fid->iounit; 1137 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 1138 rsize = clnt->msize - P9_IOHDRSZ; 1139 1140 if (count < rsize) 1141 rsize = count; 1142 if (data) 1143 req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset, 1144 rsize, data); 1145 else 1146 req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset, 1147 rsize, udata); 1148 if (IS_ERR(req)) { 1149 err = PTR_ERR(req); 1150 goto error; 1151 } 1152 1153 err = p9pdu_readf(req->rc, clnt->dotu, "d", &count); 1154 if (err) { 1155 p9pdu_dump(1, req->rc); 1156 goto free_and_error; 1157 } 1158 1159 P9_DPRINTK(P9_DEBUG_9P, "<<< RWRITE count %d\n", count); 1160 1161 p9_free_req(clnt, req); 1162 return count; 1163 1164free_and_error: 1165 p9_free_req(clnt, req); 1166error: 1167 return err; 1168} 1169EXPORT_SYMBOL(p9_client_write); 1170 1171struct p9_wstat *p9_client_stat(struct p9_fid *fid) 1172{ 1173 int err; 1174 struct p9_client *clnt; 1175 struct p9_wstat *ret = kmalloc(sizeof(struct p9_wstat), GFP_KERNEL); 1176 struct p9_req_t *req; 1177 u16 ignored; 1178 1179 P9_DPRINTK(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid); 1180 1181 if (!ret) 1182 return ERR_PTR(-ENOMEM); 1183 1184 err = 0; 1185 clnt = fid->clnt; 1186 1187 req = p9_client_rpc(clnt, P9_TSTAT, "d", fid->fid); 1188 if (IS_ERR(req)) { 1189 err = PTR_ERR(req); 1190 goto error; 1191 } 1192 1193 err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret); 1194 if (err) { 1195 ret = ERR_PTR(err); 1196 p9pdu_dump(1, req->rc); 1197 goto free_and_error; 1198 } 1199 1200 P9_DPRINTK(P9_DEBUG_9P, 1201 "<<< RSTAT sz=%x type=%x dev=%x qid=%x.%llx.%x\n" 1202 "<<< mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n" 1203 "<<< name=%s uid=%s gid=%s muid=%s extension=(%s)\n" 1204 "<<< uid=%d gid=%d n_muid=%d\n", 1205 ret->size, ret->type, ret->dev, ret->qid.type, 1206 (unsigned long long)ret->qid.path, ret->qid.version, ret->mode, 1207 ret->atime, ret->mtime, (unsigned long long)ret->length, 1208 ret->name, ret->uid, ret->gid, ret->muid, ret->extension, 1209 ret->n_uid, ret->n_gid, ret->n_muid); 1210 1211 p9_free_req(clnt, req); 1212 return ret; 1213 1214free_and_error: 1215 p9_free_req(clnt, req); 1216error: 1217 kfree(ret); 1218 return ERR_PTR(err); 1219} 1220EXPORT_SYMBOL(p9_client_stat); 1221 1222static int p9_client_statsize(struct p9_wstat *wst, int optional) 1223{ 1224 int ret; 1225 1226 /* size[2] type[2] dev[4] qid[13] */ 1227 /* mode[4] atime[4] mtime[4] length[8]*/ 1228 /* name[s] uid[s] gid[s] muid[s] */ 1229 ret = 2+2+4+13+4+4+4+8+2+2+2+2; 1230 1231 if (wst->name) 1232 ret += strlen(wst->name); 1233 if (wst->uid) 1234 ret += strlen(wst->uid); 1235 if (wst->gid) 1236 ret += strlen(wst->gid); 1237 if (wst->muid) 1238 ret += strlen(wst->muid); 1239 1240 if (optional) { 1241 ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */ 1242 if (wst->extension) 1243 ret += strlen(wst->extension); 1244 } 1245 1246 return ret; 1247} 1248 1249int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) 1250{ 1251 int err; 1252 struct p9_req_t *req; 1253 struct p9_client *clnt; 1254 1255 err = 0; 1256 clnt = fid->clnt; 1257 wst->size = p9_client_statsize(wst, clnt->dotu); 1258 P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid); 1259 P9_DPRINTK(P9_DEBUG_9P, 1260 " sz=%x type=%x dev=%x qid=%x.%llx.%x\n" 1261 " mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n" 1262 " name=%s uid=%s gid=%s muid=%s extension=(%s)\n" 1263 " uid=%d gid=%d n_muid=%d\n", 1264 wst->size, wst->type, wst->dev, wst->qid.type, 1265 (unsigned long long)wst->qid.path, wst->qid.version, wst->mode, 1266 wst->atime, wst->mtime, (unsigned long long)wst->length, 1267 wst->name, wst->uid, wst->gid, wst->muid, wst->extension, 1268 wst->n_uid, wst->n_gid, wst->n_muid); 1269 1270 req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, wst->size, wst); 1271 if (IS_ERR(req)) { 1272 err = PTR_ERR(req); 1273 goto error; 1274 } 1275 1276 P9_DPRINTK(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid); 1277 1278 p9_free_req(clnt, req); 1279error: 1280 return err; 1281} 1282EXPORT_SYMBOL(p9_client_wstat); 1283