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