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