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->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 /** 129 * p9_client_rpc - sends 9P request and waits until a response is available. 130 * The function can be interrupted. 131 * @c: client data 132 * @tc: request to be sent 133 * @rc: pointer where a pointer to the response is stored 134 */ 135 int 136 p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, 137 struct p9_fcall **rc) 138 { 139 return c->trans->rpc(c->trans, tc, rc); 140 } 141 142 struct p9_client *p9_client_create(const char *dev_name, char *options) 143 { 144 int err, n; 145 struct p9_client *clnt; 146 struct p9_fcall *tc, *rc; 147 struct p9_str *version; 148 149 err = 0; 150 tc = NULL; 151 rc = NULL; 152 clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL); 153 if (!clnt) 154 return ERR_PTR(-ENOMEM); 155 156 clnt->trans_mod = NULL; 157 clnt->trans = NULL; 158 spin_lock_init(&clnt->lock); 159 INIT_LIST_HEAD(&clnt->fidlist); 160 clnt->fidpool = p9_idpool_create(); 161 if (IS_ERR(clnt->fidpool)) { 162 err = PTR_ERR(clnt->fidpool); 163 clnt->fidpool = NULL; 164 goto error; 165 } 166 167 err = parse_opts(options, clnt); 168 if (err < 0) 169 goto error; 170 171 if (clnt->trans_mod == NULL) { 172 err = -EPROTONOSUPPORT; 173 P9_DPRINTK(P9_DEBUG_ERROR, 174 "No transport defined or default transport\n"); 175 goto error; 176 } 177 178 P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n", 179 clnt, clnt->trans_mod, clnt->msize, clnt->dotu); 180 181 182 clnt->trans = clnt->trans_mod->create(dev_name, options, clnt->msize, 183 clnt->dotu); 184 if (IS_ERR(clnt->trans)) { 185 err = PTR_ERR(clnt->trans); 186 clnt->trans = NULL; 187 goto error; 188 } 189 190 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) 191 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; 192 193 tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000"); 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) 202 goto error; 203 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; 221 222 error: 223 kfree(tc); 224 kfree(rc); 225 p9_client_destroy(clnt); 226 return ERR_PTR(err); 227 } 228 EXPORT_SYMBOL(p9_client_create); 229 230 void p9_client_destroy(struct p9_client *clnt) 231 { 232 struct p9_fid *fid, *fidptr; 233 234 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); 235 236 if (clnt->trans) { 237 clnt->trans->close(clnt->trans); 238 kfree(clnt->trans); 239 clnt->trans = NULL; 240 } 241 242 v9fs_put_trans(clnt->trans_mod); 243 244 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) 245 p9_fid_destroy(fid); 246 247 if (clnt->fidpool) 248 p9_idpool_destroy(clnt->fidpool); 249 250 kfree(clnt); 251 } 252 EXPORT_SYMBOL(p9_client_destroy); 253 254 void p9_client_disconnect(struct p9_client *clnt) 255 { 256 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); 257 clnt->trans->status = Disconnected; 258 } 259 EXPORT_SYMBOL(p9_client_disconnect); 260 261 struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, 262 char *uname, u32 n_uname, char *aname) 263 { 264 int err; 265 struct p9_fcall *tc, *rc; 266 struct p9_fid *fid; 267 268 P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n", 269 clnt, afid?afid->fid:-1, uname, aname); 270 err = 0; 271 tc = NULL; 272 rc = NULL; 273 274 fid = p9_fid_create(clnt); 275 if (IS_ERR(fid)) { 276 err = PTR_ERR(fid); 277 fid = NULL; 278 goto error; 279 } 280 281 tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname, 282 n_uname, clnt->dotu); 283 if (IS_ERR(tc)) { 284 err = PTR_ERR(tc); 285 tc = NULL; 286 goto error; 287 } 288 289 err = p9_client_rpc(clnt, tc, &rc); 290 if (err) 291 goto error; 292 293 memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid)); 294 kfree(tc); 295 kfree(rc); 296 return fid; 297 298 error: 299 kfree(tc); 300 kfree(rc); 301 if (fid) 302 p9_fid_destroy(fid); 303 return ERR_PTR(err); 304 } 305 EXPORT_SYMBOL(p9_client_attach); 306 307 struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, 308 u32 n_uname, char *aname) 309 { 310 int err; 311 struct p9_fcall *tc, *rc; 312 struct p9_fid *fid; 313 314 P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname, 315 aname); 316 err = 0; 317 tc = NULL; 318 rc = NULL; 319 320 fid = p9_fid_create(clnt); 321 if (IS_ERR(fid)) { 322 err = PTR_ERR(fid); 323 fid = NULL; 324 goto error; 325 } 326 327 tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu); 328 if (IS_ERR(tc)) { 329 err = PTR_ERR(tc); 330 tc = NULL; 331 goto error; 332 } 333 334 err = p9_client_rpc(clnt, tc, &rc); 335 if (err) 336 goto error; 337 338 memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid)); 339 kfree(tc); 340 kfree(rc); 341 return fid; 342 343 error: 344 kfree(tc); 345 kfree(rc); 346 if (fid) 347 p9_fid_destroy(fid); 348 return ERR_PTR(err); 349 } 350 EXPORT_SYMBOL(p9_client_auth); 351 352 struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, 353 int clone) 354 { 355 int err; 356 struct p9_fcall *tc, *rc; 357 struct p9_client *clnt; 358 struct p9_fid *fid; 359 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; 363 tc = NULL; 364 rc = NULL; 365 clnt = oldfid->clnt; 366 if (clone) { 367 fid = p9_fid_create(clnt); 368 if (IS_ERR(fid)) { 369 err = PTR_ERR(fid); 370 fid = NULL; 371 goto error; 372 } 373 374 fid->uid = oldfid->uid; 375 } else 376 fid = oldfid; 377 378 tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames); 379 if (IS_ERR(tc)) { 380 err = PTR_ERR(tc); 381 tc = NULL; 382 goto error; 383 } 384 385 err = p9_client_rpc(clnt, tc, &rc); 386 if (err) { 387 if (rc && rc->id == P9_RWALK) 388 goto clunk_fid; 389 else 390 goto error; 391 } 392 393 if (rc->params.rwalk.nwqid != nwname) { 394 err = -ENOENT; 395 goto clunk_fid; 396 } 397 398 if (nwname) 399 memmove(&fid->qid, 400 &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1], 401 sizeof(struct p9_qid)); 402 else 403 fid->qid = oldfid->qid; 404 405 kfree(tc); 406 kfree(rc); 407 return fid; 408 409 clunk_fid: 410 kfree(tc); 411 kfree(rc); 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 422 error: 423 kfree(tc); 424 kfree(rc); 425 if (fid && (fid != oldfid)) 426 p9_fid_destroy(fid); 427 428 return ERR_PTR(err); 429 } 430 EXPORT_SYMBOL(p9_client_walk); 431 432 int p9_client_open(struct p9_fid *fid, int mode) 433 { 434 int err; 435 struct p9_fcall *tc, *rc; 436 struct p9_client *clnt; 437 438 P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode); 439 err = 0; 440 tc = NULL; 441 rc = NULL; 442 clnt = fid->clnt; 443 444 if (fid->mode != -1) 445 return -EINVAL; 446 447 tc = p9_create_topen(fid->fid, mode); 448 if (IS_ERR(tc)) { 449 err = PTR_ERR(tc); 450 tc = NULL; 451 goto done; 452 } 453 454 err = p9_client_rpc(clnt, tc, &rc); 455 if (err) 456 goto done; 457 458 fid->mode = mode; 459 fid->iounit = rc->params.ropen.iounit; 460 461 done: 462 kfree(tc); 463 kfree(rc); 464 return err; 465 } 466 EXPORT_SYMBOL(p9_client_open); 467 468 int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, 469 char *extension) 470 { 471 int err; 472 struct p9_fcall *tc, *rc; 473 struct p9_client *clnt; 474 475 P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid, 476 name, perm, mode); 477 err = 0; 478 tc = NULL; 479 rc = NULL; 480 clnt = fid->clnt; 481 482 if (fid->mode != -1) 483 return -EINVAL; 484 485 tc = p9_create_tcreate(fid->fid, name, perm, mode, extension, 486 clnt->dotu); 487 if (IS_ERR(tc)) { 488 err = PTR_ERR(tc); 489 tc = NULL; 490 goto done; 491 } 492 493 err = p9_client_rpc(clnt, tc, &rc); 494 if (err) 495 goto done; 496 497 fid->mode = mode; 498 fid->iounit = rc->params.ropen.iounit; 499 500 done: 501 kfree(tc); 502 kfree(rc); 503 return err; 504 } 505 EXPORT_SYMBOL(p9_client_fcreate); 506 507 int p9_client_clunk(struct p9_fid *fid) 508 { 509 int err; 510 struct p9_fcall *tc, *rc; 511 struct p9_client *clnt; 512 513 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 514 err = 0; 515 tc = NULL; 516 rc = NULL; 517 clnt = fid->clnt; 518 519 tc = p9_create_tclunk(fid->fid); 520 if (IS_ERR(tc)) { 521 err = PTR_ERR(tc); 522 tc = NULL; 523 goto done; 524 } 525 526 err = p9_client_rpc(clnt, tc, &rc); 527 if (err) 528 goto done; 529 530 p9_fid_destroy(fid); 531 532 done: 533 kfree(tc); 534 kfree(rc); 535 return err; 536 } 537 EXPORT_SYMBOL(p9_client_clunk); 538 539 int p9_client_remove(struct p9_fid *fid) 540 { 541 int err; 542 struct p9_fcall *tc, *rc; 543 struct p9_client *clnt; 544 545 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 546 err = 0; 547 tc = NULL; 548 rc = NULL; 549 clnt = fid->clnt; 550 551 tc = p9_create_tremove(fid->fid); 552 if (IS_ERR(tc)) { 553 err = PTR_ERR(tc); 554 tc = NULL; 555 goto done; 556 } 557 558 err = p9_client_rpc(clnt, tc, &rc); 559 if (err) 560 goto done; 561 562 p9_fid_destroy(fid); 563 564 done: 565 kfree(tc); 566 kfree(rc); 567 return err; 568 } 569 EXPORT_SYMBOL(p9_client_remove); 570 571 int 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 621 error: 622 kfree(tc); 623 kfree(rc); 624 return err; 625 } 626 EXPORT_SYMBOL(p9_client_read); 627 628 int 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 674 error: 675 kfree(tc); 676 kfree(rc); 677 return err; 678 } 679 EXPORT_SYMBOL(p9_client_write); 680 681 int 682 p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count) 683 { 684 int err, n, rsize, total; 685 struct p9_fcall *tc, *rc; 686 struct p9_client *clnt; 687 688 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, 689 (long long unsigned) offset, count); 690 err = 0; 691 tc = NULL; 692 rc = NULL; 693 clnt = fid->clnt; 694 total = 0; 695 696 rsize = fid->iounit; 697 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 698 rsize = clnt->msize - P9_IOHDRSZ; 699 700 do { 701 if (count < rsize) 702 rsize = count; 703 704 tc = p9_create_tread(fid->fid, offset, rsize); 705 if (IS_ERR(tc)) { 706 err = PTR_ERR(tc); 707 tc = NULL; 708 goto error; 709 } 710 711 err = p9_client_rpc(clnt, tc, &rc); 712 if (err) 713 goto error; 714 715 n = rc->params.rread.count; 716 if (n > count) 717 n = count; 718 719 err = copy_to_user(data, rc->params.rread.data, n); 720 if (err) { 721 err = -EFAULT; 722 goto error; 723 } 724 725 count -= n; 726 data += n; 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 737 error: 738 kfree(tc); 739 kfree(rc); 740 return err; 741 } 742 EXPORT_SYMBOL(p9_client_uread); 743 744 int 745 p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset, 746 u32 count) 747 { 748 int err, n, rsize, total; 749 struct p9_fcall *tc, *rc; 750 struct p9_client *clnt; 751 752 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, 753 (long long unsigned) offset, count); 754 err = 0; 755 tc = NULL; 756 rc = NULL; 757 clnt = fid->clnt; 758 total = 0; 759 760 rsize = fid->iounit; 761 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 762 rsize = clnt->msize - P9_IOHDRSZ; 763 764 do { 765 if (count < rsize) 766 rsize = count; 767 768 tc = p9_create_twrite_u(fid->fid, offset, rsize, data); 769 if (IS_ERR(tc)) { 770 err = PTR_ERR(tc); 771 tc = NULL; 772 goto error; 773 } 774 775 err = p9_client_rpc(clnt, tc, &rc); 776 if (err) 777 goto error; 778 779 n = rc->params.rread.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 790 return total; 791 792 error: 793 kfree(tc); 794 kfree(rc); 795 return err; 796 } 797 EXPORT_SYMBOL(p9_client_uwrite); 798 799 int 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 } 823 EXPORT_SYMBOL(p9_client_readn); 824 825 struct p9_stat *p9_client_stat(struct p9_fid *fid) 826 { 827 int err; 828 struct p9_fcall *tc, *rc; 829 struct p9_client *clnt; 830 struct p9_stat *ret; 831 832 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 833 err = 0; 834 tc = NULL; 835 rc = NULL; 836 ret = NULL; 837 clnt = fid->clnt; 838 839 tc = p9_create_tstat(fid->fid); 840 if (IS_ERR(tc)) { 841 err = PTR_ERR(tc); 842 tc = NULL; 843 goto error; 844 } 845 846 err = p9_client_rpc(clnt, tc, &rc); 847 if (err) 848 goto error; 849 850 ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu); 851 if (IS_ERR(ret)) { 852 err = PTR_ERR(ret); 853 ret = NULL; 854 goto error; 855 } 856 857 kfree(tc); 858 kfree(rc); 859 return ret; 860 861 error: 862 kfree(tc); 863 kfree(rc); 864 kfree(ret); 865 return ERR_PTR(err); 866 } 867 EXPORT_SYMBOL(p9_client_stat); 868 869 int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) 870 { 871 int err; 872 struct p9_fcall *tc, *rc; 873 struct p9_client *clnt; 874 875 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 876 err = 0; 877 tc = NULL; 878 rc = NULL; 879 clnt = fid->clnt; 880 881 tc = p9_create_twstat(fid->fid, wst, clnt->dotu); 882 if (IS_ERR(tc)) { 883 err = PTR_ERR(tc); 884 tc = NULL; 885 goto done; 886 } 887 888 err = p9_client_rpc(clnt, tc, &rc); 889 890 done: 891 kfree(tc); 892 kfree(rc); 893 return err; 894 } 895 EXPORT_SYMBOL(p9_client_wstat); 896 897 struct 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 984 done: 985 kfree(tc); 986 kfree(rc); 987 return ret; 988 989 error: 990 kfree(tc); 991 kfree(rc); 992 kfree(ret); 993 return ERR_PTR(err); 994 } 995 EXPORT_SYMBOL(p9_client_dirread); 996 997 static 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 1037 static 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; 1051 } 1052 1053 memset(&fid->qid, 0, sizeof(struct p9_qid)); 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 1068 error: 1069 kfree(fid); 1070 return ERR_PTR(err); 1071 } 1072 1073 static 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 } 1086