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/transport.h> 37 #include <net/9p/client.h> 38 39 static struct p9_fid *p9_fid_create(struct p9_client *clnt); 40 static void p9_fid_destroy(struct p9_fid *fid); 41 static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu); 42 43 /* 44 * Client Option Parsing (code inspired by NFS code) 45 * - a little lazy - parse all client options 46 */ 47 48 enum { 49 Opt_msize, 50 Opt_trans, 51 Opt_legacy, 52 Opt_err, 53 }; 54 55 static match_table_t tokens = { 56 {Opt_msize, "msize=%u"}, 57 {Opt_legacy, "noextend"}, 58 {Opt_trans, "trans=%s"}, 59 {Opt_err, NULL}, 60 }; 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 70 static 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->trans_mod = v9fs_default_trans(); 79 clnt->dotu = 1; 80 clnt->msize = 8192; 81 82 if (!opts) 83 return 0; 84 85 options = kstrdup(opts, GFP_KERNEL); 86 if (!options) { 87 P9_DPRINTK(P9_DEBUG_ERROR, 88 "failed to allocate copy of option string\n"); 89 return -ENOMEM; 90 } 91 92 while ((p = strsep(&options, ",")) != NULL) { 93 int token; 94 if (!*p) 95 continue; 96 token = match_token(p, tokens, args); 97 if (token < Opt_trans) { 98 int r = match_int(&args[0], &option); 99 if (r < 0) { 100 P9_DPRINTK(P9_DEBUG_ERROR, 101 "integer field, but no integer?\n"); 102 ret = r; 103 continue; 104 } 105 } 106 switch (token) { 107 case Opt_msize: 108 clnt->msize = option; 109 break; 110 case Opt_trans: 111 clnt->trans_mod = v9fs_match_trans(&args[0]); 112 break; 113 case Opt_legacy: 114 clnt->dotu = 0; 115 break; 116 default: 117 continue; 118 } 119 } 120 kfree(options); 121 return ret; 122 } 123 124 125 /** 126 * p9_client_rpc - sends 9P request and waits until a response is available. 127 * The function can be interrupted. 128 * @c: client data 129 * @tc: request to be sent 130 * @rc: pointer where a pointer to the response is stored 131 */ 132 int 133 p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, 134 struct p9_fcall **rc) 135 { 136 return c->trans->rpc(c->trans, tc, rc); 137 } 138 139 struct p9_client *p9_client_create(const char *dev_name, char *options) 140 { 141 int err, n; 142 struct p9_client *clnt; 143 struct p9_fcall *tc, *rc; 144 struct p9_str *version; 145 146 err = 0; 147 tc = NULL; 148 rc = NULL; 149 clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL); 150 if (!clnt) 151 return ERR_PTR(-ENOMEM); 152 153 clnt->trans = NULL; 154 spin_lock_init(&clnt->lock); 155 INIT_LIST_HEAD(&clnt->fidlist); 156 clnt->fidpool = p9_idpool_create(); 157 if (IS_ERR(clnt->fidpool)) { 158 err = PTR_ERR(clnt->fidpool); 159 clnt->fidpool = NULL; 160 goto error; 161 } 162 163 err = parse_opts(options, clnt); 164 if (err < 0) 165 goto error; 166 167 if (clnt->trans_mod == NULL) { 168 err = -EPROTONOSUPPORT; 169 P9_DPRINTK(P9_DEBUG_ERROR, 170 "No transport defined or default transport\n"); 171 goto error; 172 } 173 174 P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n", 175 clnt, clnt->trans_mod, clnt->msize, clnt->dotu); 176 177 178 clnt->trans = clnt->trans_mod->create(dev_name, options, clnt->msize, 179 clnt->dotu); 180 if (IS_ERR(clnt->trans)) { 181 err = PTR_ERR(clnt->trans); 182 clnt->trans = NULL; 183 goto error; 184 } 185 186 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) 187 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; 188 189 tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000"); 190 if (IS_ERR(tc)) { 191 err = PTR_ERR(tc); 192 tc = NULL; 193 goto error; 194 } 195 196 err = p9_client_rpc(clnt, tc, &rc); 197 if (err) 198 goto error; 199 200 version = &rc->params.rversion.version; 201 if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8)) 202 clnt->dotu = 1; 203 else if (version->len == 6 && !memcmp(version->str, "9P2000", 6)) 204 clnt->dotu = 0; 205 else { 206 err = -EREMOTEIO; 207 goto error; 208 } 209 210 n = rc->params.rversion.msize; 211 if (n < clnt->msize) 212 clnt->msize = n; 213 214 kfree(tc); 215 kfree(rc); 216 return clnt; 217 218 error: 219 kfree(tc); 220 kfree(rc); 221 p9_client_destroy(clnt); 222 return ERR_PTR(err); 223 } 224 EXPORT_SYMBOL(p9_client_create); 225 226 void p9_client_destroy(struct p9_client *clnt) 227 { 228 struct p9_fid *fid, *fidptr; 229 230 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); 231 232 if (clnt->trans) { 233 clnt->trans->close(clnt->trans); 234 kfree(clnt->trans); 235 clnt->trans = NULL; 236 } 237 238 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) 239 p9_fid_destroy(fid); 240 241 if (clnt->fidpool) 242 p9_idpool_destroy(clnt->fidpool); 243 244 kfree(clnt); 245 } 246 EXPORT_SYMBOL(p9_client_destroy); 247 248 void p9_client_disconnect(struct p9_client *clnt) 249 { 250 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); 251 clnt->trans->status = Disconnected; 252 } 253 EXPORT_SYMBOL(p9_client_disconnect); 254 255 struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, 256 char *uname, u32 n_uname, char *aname) 257 { 258 int err; 259 struct p9_fcall *tc, *rc; 260 struct p9_fid *fid; 261 262 P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n", 263 clnt, afid?afid->fid:-1, uname, aname); 264 err = 0; 265 tc = NULL; 266 rc = NULL; 267 268 fid = p9_fid_create(clnt); 269 if (IS_ERR(fid)) { 270 err = PTR_ERR(fid); 271 fid = NULL; 272 goto error; 273 } 274 275 tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname, 276 n_uname, clnt->dotu); 277 if (IS_ERR(tc)) { 278 err = PTR_ERR(tc); 279 tc = NULL; 280 goto error; 281 } 282 283 err = p9_client_rpc(clnt, tc, &rc); 284 if (err) 285 goto error; 286 287 memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid)); 288 kfree(tc); 289 kfree(rc); 290 return fid; 291 292 error: 293 kfree(tc); 294 kfree(rc); 295 if (fid) 296 p9_fid_destroy(fid); 297 return ERR_PTR(err); 298 } 299 EXPORT_SYMBOL(p9_client_attach); 300 301 struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, 302 u32 n_uname, char *aname) 303 { 304 int err; 305 struct p9_fcall *tc, *rc; 306 struct p9_fid *fid; 307 308 P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname, 309 aname); 310 err = 0; 311 tc = NULL; 312 rc = NULL; 313 314 fid = p9_fid_create(clnt); 315 if (IS_ERR(fid)) { 316 err = PTR_ERR(fid); 317 fid = NULL; 318 goto error; 319 } 320 321 tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu); 322 if (IS_ERR(tc)) { 323 err = PTR_ERR(tc); 324 tc = NULL; 325 goto error; 326 } 327 328 err = p9_client_rpc(clnt, tc, &rc); 329 if (err) 330 goto error; 331 332 memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid)); 333 kfree(tc); 334 kfree(rc); 335 return fid; 336 337 error: 338 kfree(tc); 339 kfree(rc); 340 if (fid) 341 p9_fid_destroy(fid); 342 return ERR_PTR(err); 343 } 344 EXPORT_SYMBOL(p9_client_auth); 345 346 struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, 347 int clone) 348 { 349 int err; 350 struct p9_fcall *tc, *rc; 351 struct p9_client *clnt; 352 struct p9_fid *fid; 353 354 P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n", 355 oldfid->fid, nwname, wnames?wnames[0]:NULL); 356 err = 0; 357 tc = NULL; 358 rc = NULL; 359 clnt = oldfid->clnt; 360 if (clone) { 361 fid = p9_fid_create(clnt); 362 if (IS_ERR(fid)) { 363 err = PTR_ERR(fid); 364 fid = NULL; 365 goto error; 366 } 367 368 fid->uid = oldfid->uid; 369 } else 370 fid = oldfid; 371 372 tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames); 373 if (IS_ERR(tc)) { 374 err = PTR_ERR(tc); 375 tc = NULL; 376 goto error; 377 } 378 379 err = p9_client_rpc(clnt, tc, &rc); 380 if (err) { 381 if (rc && rc->id == P9_RWALK) 382 goto clunk_fid; 383 else 384 goto error; 385 } 386 387 if (rc->params.rwalk.nwqid != nwname) { 388 err = -ENOENT; 389 goto clunk_fid; 390 } 391 392 if (nwname) 393 memmove(&fid->qid, 394 &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1], 395 sizeof(struct p9_qid)); 396 else 397 fid->qid = oldfid->qid; 398 399 kfree(tc); 400 kfree(rc); 401 return fid; 402 403 clunk_fid: 404 kfree(tc); 405 kfree(rc); 406 rc = NULL; 407 tc = p9_create_tclunk(fid->fid); 408 if (IS_ERR(tc)) { 409 err = PTR_ERR(tc); 410 tc = NULL; 411 goto error; 412 } 413 414 p9_client_rpc(clnt, tc, &rc); 415 416 error: 417 kfree(tc); 418 kfree(rc); 419 if (fid && (fid != oldfid)) 420 p9_fid_destroy(fid); 421 422 return ERR_PTR(err); 423 } 424 EXPORT_SYMBOL(p9_client_walk); 425 426 int p9_client_open(struct p9_fid *fid, int mode) 427 { 428 int err; 429 struct p9_fcall *tc, *rc; 430 struct p9_client *clnt; 431 432 P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode); 433 err = 0; 434 tc = NULL; 435 rc = NULL; 436 clnt = fid->clnt; 437 438 if (fid->mode != -1) 439 return -EINVAL; 440 441 tc = p9_create_topen(fid->fid, mode); 442 if (IS_ERR(tc)) { 443 err = PTR_ERR(tc); 444 tc = NULL; 445 goto done; 446 } 447 448 err = p9_client_rpc(clnt, tc, &rc); 449 if (err) 450 goto done; 451 452 fid->mode = mode; 453 fid->iounit = rc->params.ropen.iounit; 454 455 done: 456 kfree(tc); 457 kfree(rc); 458 return err; 459 } 460 EXPORT_SYMBOL(p9_client_open); 461 462 int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, 463 char *extension) 464 { 465 int err; 466 struct p9_fcall *tc, *rc; 467 struct p9_client *clnt; 468 469 P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid, 470 name, perm, mode); 471 err = 0; 472 tc = NULL; 473 rc = NULL; 474 clnt = fid->clnt; 475 476 if (fid->mode != -1) 477 return -EINVAL; 478 479 tc = p9_create_tcreate(fid->fid, name, perm, mode, extension, 480 clnt->dotu); 481 if (IS_ERR(tc)) { 482 err = PTR_ERR(tc); 483 tc = NULL; 484 goto done; 485 } 486 487 err = p9_client_rpc(clnt, tc, &rc); 488 if (err) 489 goto done; 490 491 fid->mode = mode; 492 fid->iounit = rc->params.ropen.iounit; 493 494 done: 495 kfree(tc); 496 kfree(rc); 497 return err; 498 } 499 EXPORT_SYMBOL(p9_client_fcreate); 500 501 int p9_client_clunk(struct p9_fid *fid) 502 { 503 int err; 504 struct p9_fcall *tc, *rc; 505 struct p9_client *clnt; 506 507 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 508 err = 0; 509 tc = NULL; 510 rc = NULL; 511 clnt = fid->clnt; 512 513 tc = p9_create_tclunk(fid->fid); 514 if (IS_ERR(tc)) { 515 err = PTR_ERR(tc); 516 tc = NULL; 517 goto done; 518 } 519 520 err = p9_client_rpc(clnt, tc, &rc); 521 if (err) 522 goto done; 523 524 p9_fid_destroy(fid); 525 526 done: 527 kfree(tc); 528 kfree(rc); 529 return err; 530 } 531 EXPORT_SYMBOL(p9_client_clunk); 532 533 int p9_client_remove(struct p9_fid *fid) 534 { 535 int err; 536 struct p9_fcall *tc, *rc; 537 struct p9_client *clnt; 538 539 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 540 err = 0; 541 tc = NULL; 542 rc = NULL; 543 clnt = fid->clnt; 544 545 tc = p9_create_tremove(fid->fid); 546 if (IS_ERR(tc)) { 547 err = PTR_ERR(tc); 548 tc = NULL; 549 goto done; 550 } 551 552 err = p9_client_rpc(clnt, tc, &rc); 553 if (err) 554 goto done; 555 556 p9_fid_destroy(fid); 557 558 done: 559 kfree(tc); 560 kfree(rc); 561 return err; 562 } 563 EXPORT_SYMBOL(p9_client_remove); 564 565 int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count) 566 { 567 int err, n, rsize, total; 568 struct p9_fcall *tc, *rc; 569 struct p9_client *clnt; 570 571 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid, 572 (long long unsigned) offset, count); 573 err = 0; 574 tc = NULL; 575 rc = NULL; 576 clnt = fid->clnt; 577 total = 0; 578 579 rsize = fid->iounit; 580 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 581 rsize = clnt->msize - P9_IOHDRSZ; 582 583 do { 584 if (count < rsize) 585 rsize = count; 586 587 tc = p9_create_tread(fid->fid, offset, rsize); 588 if (IS_ERR(tc)) { 589 err = PTR_ERR(tc); 590 tc = NULL; 591 goto error; 592 } 593 594 err = p9_client_rpc(clnt, tc, &rc); 595 if (err) 596 goto error; 597 598 n = rc->params.rread.count; 599 if (n > count) 600 n = count; 601 602 memmove(data, rc->params.rread.data, n); 603 count -= n; 604 data += n; 605 offset += n; 606 total += n; 607 kfree(tc); 608 tc = NULL; 609 kfree(rc); 610 rc = NULL; 611 } while (count > 0 && n == rsize); 612 613 return total; 614 615 error: 616 kfree(tc); 617 kfree(rc); 618 return err; 619 } 620 EXPORT_SYMBOL(p9_client_read); 621 622 int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count) 623 { 624 int err, n, rsize, total; 625 struct p9_fcall *tc, *rc; 626 struct p9_client *clnt; 627 628 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, 629 (long long unsigned) offset, count); 630 err = 0; 631 tc = NULL; 632 rc = NULL; 633 clnt = fid->clnt; 634 total = 0; 635 636 rsize = fid->iounit; 637 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 638 rsize = clnt->msize - P9_IOHDRSZ; 639 640 do { 641 if (count < rsize) 642 rsize = count; 643 644 tc = p9_create_twrite(fid->fid, offset, rsize, data); 645 if (IS_ERR(tc)) { 646 err = PTR_ERR(tc); 647 tc = NULL; 648 goto error; 649 } 650 651 err = p9_client_rpc(clnt, tc, &rc); 652 if (err) 653 goto error; 654 655 n = rc->params.rread.count; 656 count -= n; 657 data += n; 658 offset += n; 659 total += n; 660 kfree(tc); 661 tc = NULL; 662 kfree(rc); 663 rc = NULL; 664 } while (count > 0); 665 666 return total; 667 668 error: 669 kfree(tc); 670 kfree(rc); 671 return err; 672 } 673 EXPORT_SYMBOL(p9_client_write); 674 675 int 676 p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count) 677 { 678 int err, n, rsize, total; 679 struct p9_fcall *tc, *rc; 680 struct p9_client *clnt; 681 682 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, 683 (long long unsigned) offset, count); 684 err = 0; 685 tc = NULL; 686 rc = NULL; 687 clnt = fid->clnt; 688 total = 0; 689 690 rsize = fid->iounit; 691 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 692 rsize = clnt->msize - P9_IOHDRSZ; 693 694 do { 695 if (count < rsize) 696 rsize = count; 697 698 tc = p9_create_tread(fid->fid, offset, rsize); 699 if (IS_ERR(tc)) { 700 err = PTR_ERR(tc); 701 tc = NULL; 702 goto error; 703 } 704 705 err = p9_client_rpc(clnt, tc, &rc); 706 if (err) 707 goto error; 708 709 n = rc->params.rread.count; 710 if (n > count) 711 n = count; 712 713 err = copy_to_user(data, rc->params.rread.data, n); 714 if (err) { 715 err = -EFAULT; 716 goto error; 717 } 718 719 count -= n; 720 data += n; 721 offset += n; 722 total += n; 723 kfree(tc); 724 tc = NULL; 725 kfree(rc); 726 rc = NULL; 727 } while (count > 0 && n == rsize); 728 729 return total; 730 731 error: 732 kfree(tc); 733 kfree(rc); 734 return err; 735 } 736 EXPORT_SYMBOL(p9_client_uread); 737 738 int 739 p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset, 740 u32 count) 741 { 742 int err, n, rsize, total; 743 struct p9_fcall *tc, *rc; 744 struct p9_client *clnt; 745 746 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, 747 (long long unsigned) offset, count); 748 err = 0; 749 tc = NULL; 750 rc = NULL; 751 clnt = fid->clnt; 752 total = 0; 753 754 rsize = fid->iounit; 755 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 756 rsize = clnt->msize - P9_IOHDRSZ; 757 758 do { 759 if (count < rsize) 760 rsize = count; 761 762 tc = p9_create_twrite_u(fid->fid, offset, rsize, data); 763 if (IS_ERR(tc)) { 764 err = PTR_ERR(tc); 765 tc = NULL; 766 goto error; 767 } 768 769 err = p9_client_rpc(clnt, tc, &rc); 770 if (err) 771 goto error; 772 773 n = rc->params.rread.count; 774 count -= n; 775 data += n; 776 offset += n; 777 total += n; 778 kfree(tc); 779 tc = NULL; 780 kfree(rc); 781 rc = NULL; 782 } while (count > 0); 783 784 return total; 785 786 error: 787 kfree(tc); 788 kfree(rc); 789 return err; 790 } 791 EXPORT_SYMBOL(p9_client_uwrite); 792 793 int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count) 794 { 795 int n, total; 796 797 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, 798 (long long unsigned) offset, count); 799 n = 0; 800 total = 0; 801 while (count) { 802 n = p9_client_read(fid, data, offset, count); 803 if (n <= 0) 804 break; 805 806 data += n; 807 offset += n; 808 count -= n; 809 total += n; 810 } 811 812 if (n < 0) 813 total = n; 814 815 return total; 816 } 817 EXPORT_SYMBOL(p9_client_readn); 818 819 struct p9_stat *p9_client_stat(struct p9_fid *fid) 820 { 821 int err; 822 struct p9_fcall *tc, *rc; 823 struct p9_client *clnt; 824 struct p9_stat *ret; 825 826 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 827 err = 0; 828 tc = NULL; 829 rc = NULL; 830 ret = NULL; 831 clnt = fid->clnt; 832 833 tc = p9_create_tstat(fid->fid); 834 if (IS_ERR(tc)) { 835 err = PTR_ERR(tc); 836 tc = NULL; 837 goto error; 838 } 839 840 err = p9_client_rpc(clnt, tc, &rc); 841 if (err) 842 goto error; 843 844 ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu); 845 if (IS_ERR(ret)) { 846 err = PTR_ERR(ret); 847 ret = NULL; 848 goto error; 849 } 850 851 kfree(tc); 852 kfree(rc); 853 return ret; 854 855 error: 856 kfree(tc); 857 kfree(rc); 858 kfree(ret); 859 return ERR_PTR(err); 860 } 861 EXPORT_SYMBOL(p9_client_stat); 862 863 int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) 864 { 865 int err; 866 struct p9_fcall *tc, *rc; 867 struct p9_client *clnt; 868 869 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 870 err = 0; 871 tc = NULL; 872 rc = NULL; 873 clnt = fid->clnt; 874 875 tc = p9_create_twstat(fid->fid, wst, clnt->dotu); 876 if (IS_ERR(tc)) { 877 err = PTR_ERR(tc); 878 tc = NULL; 879 goto done; 880 } 881 882 err = p9_client_rpc(clnt, tc, &rc); 883 884 done: 885 kfree(tc); 886 kfree(rc); 887 return err; 888 } 889 EXPORT_SYMBOL(p9_client_wstat); 890 891 struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset) 892 { 893 int err, n, m; 894 struct p9_fcall *tc, *rc; 895 struct p9_client *clnt; 896 struct p9_stat st, *ret; 897 898 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu\n", fid->fid, 899 (long long unsigned) offset); 900 err = 0; 901 tc = NULL; 902 rc = NULL; 903 ret = NULL; 904 clnt = fid->clnt; 905 906 /* if the offset is below or above the current response, free it */ 907 if (offset < fid->rdir_fpos || (fid->rdir_fcall && 908 offset >= fid->rdir_fpos+fid->rdir_fcall->params.rread.count)) { 909 fid->rdir_pos = 0; 910 if (fid->rdir_fcall) 911 fid->rdir_fpos += fid->rdir_fcall->params.rread.count; 912 913 kfree(fid->rdir_fcall); 914 fid->rdir_fcall = NULL; 915 if (offset < fid->rdir_fpos) 916 fid->rdir_fpos = 0; 917 } 918 919 if (!fid->rdir_fcall) { 920 n = fid->iounit; 921 if (!n || n > clnt->msize-P9_IOHDRSZ) 922 n = clnt->msize - P9_IOHDRSZ; 923 924 while (1) { 925 if (fid->rdir_fcall) { 926 fid->rdir_fpos += 927 fid->rdir_fcall->params.rread.count; 928 kfree(fid->rdir_fcall); 929 fid->rdir_fcall = NULL; 930 } 931 932 tc = p9_create_tread(fid->fid, fid->rdir_fpos, n); 933 if (IS_ERR(tc)) { 934 err = PTR_ERR(tc); 935 tc = NULL; 936 goto error; 937 } 938 939 err = p9_client_rpc(clnt, tc, &rc); 940 if (err) 941 goto error; 942 943 n = rc->params.rread.count; 944 if (n == 0) 945 goto done; 946 947 fid->rdir_fcall = rc; 948 rc = NULL; 949 if (offset >= fid->rdir_fpos && 950 offset < fid->rdir_fpos+n) 951 break; 952 } 953 954 fid->rdir_pos = 0; 955 } 956 957 m = offset - fid->rdir_fpos; 958 if (m < 0) 959 goto done; 960 961 n = p9_deserialize_stat(fid->rdir_fcall->params.rread.data + m, 962 fid->rdir_fcall->params.rread.count - m, &st, clnt->dotu); 963 964 if (!n) { 965 err = -EIO; 966 goto error; 967 } 968 969 fid->rdir_pos += n; 970 st.size = n; 971 ret = p9_clone_stat(&st, clnt->dotu); 972 if (IS_ERR(ret)) { 973 err = PTR_ERR(ret); 974 ret = NULL; 975 goto error; 976 } 977 978 done: 979 kfree(tc); 980 kfree(rc); 981 return ret; 982 983 error: 984 kfree(tc); 985 kfree(rc); 986 kfree(ret); 987 return ERR_PTR(err); 988 } 989 EXPORT_SYMBOL(p9_client_dirread); 990 991 static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu) 992 { 993 int n; 994 char *p; 995 struct p9_stat *ret; 996 997 n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len + 998 st->muid.len; 999 1000 if (dotu) 1001 n += st->extension.len; 1002 1003 ret = kmalloc(n, GFP_KERNEL); 1004 if (!ret) 1005 return ERR_PTR(-ENOMEM); 1006 1007 memmove(ret, st, sizeof(struct p9_stat)); 1008 p = ((char *) ret) + sizeof(struct p9_stat); 1009 memmove(p, st->name.str, st->name.len); 1010 ret->name.str = p; 1011 p += st->name.len; 1012 memmove(p, st->uid.str, st->uid.len); 1013 ret->uid.str = p; 1014 p += st->uid.len; 1015 memmove(p, st->gid.str, st->gid.len); 1016 ret->gid.str = p; 1017 p += st->gid.len; 1018 memmove(p, st->muid.str, st->muid.len); 1019 ret->muid.str = p; 1020 p += st->muid.len; 1021 1022 if (dotu) { 1023 memmove(p, st->extension.str, st->extension.len); 1024 ret->extension.str = p; 1025 p += st->extension.len; 1026 } 1027 1028 return ret; 1029 } 1030 1031 static struct p9_fid *p9_fid_create(struct p9_client *clnt) 1032 { 1033 int err; 1034 struct p9_fid *fid; 1035 1036 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); 1037 fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL); 1038 if (!fid) 1039 return ERR_PTR(-ENOMEM); 1040 1041 fid->fid = p9_idpool_get(clnt->fidpool); 1042 if (fid->fid < 0) { 1043 err = -ENOSPC; 1044 goto error; 1045 } 1046 1047 memset(&fid->qid, 0, sizeof(struct p9_qid)); 1048 fid->mode = -1; 1049 fid->rdir_fpos = 0; 1050 fid->rdir_pos = 0; 1051 fid->rdir_fcall = NULL; 1052 fid->uid = current->fsuid; 1053 fid->clnt = clnt; 1054 fid->aux = NULL; 1055 1056 spin_lock(&clnt->lock); 1057 list_add(&fid->flist, &clnt->fidlist); 1058 spin_unlock(&clnt->lock); 1059 1060 return fid; 1061 1062 error: 1063 kfree(fid); 1064 return ERR_PTR(err); 1065 } 1066 1067 static void p9_fid_destroy(struct p9_fid *fid) 1068 { 1069 struct p9_client *clnt; 1070 1071 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 1072 clnt = fid->clnt; 1073 p9_idpool_put(fid->fid, clnt->fidpool); 1074 spin_lock(&clnt->lock); 1075 list_del(&fid->flist); 1076 spin_unlock(&clnt->lock); 1077 kfree(fid->rdir_fcall); 1078 kfree(fid); 1079 } 1080