1 /* 2 * net/9p/clnt.c 3 * 4 * 9P Client 5 * 6 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 10 * as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to: 19 * Free Software Foundation 20 * 51 Franklin Street, Fifth Floor 21 * Boston, MA 02111-1301 USA 22 * 23 */ 24 25 #include <linux/module.h> 26 #include <linux/errno.h> 27 #include <linux/fs.h> 28 #include <linux/idr.h> 29 #include <linux/mutex.h> 30 #include <linux/sched.h> 31 #include <linux/uaccess.h> 32 #include <net/9p/9p.h> 33 #include <linux/parser.h> 34 #include <net/9p/transport.h> 35 #include <net/9p/conn.h> 36 #include <net/9p/client.h> 37 38 static struct p9_fid *p9_fid_create(struct p9_client *clnt); 39 static void p9_fid_destroy(struct p9_fid *fid); 40 static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu); 41 42 struct p9_client *p9_client_create(struct p9_trans *trans, int msize, 43 int dotu) 44 { 45 int err, n; 46 struct p9_client *clnt; 47 struct p9_fcall *tc, *rc; 48 struct p9_str *version; 49 50 err = 0; 51 tc = NULL; 52 rc = NULL; 53 clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL); 54 if (!clnt) 55 return ERR_PTR(-ENOMEM); 56 57 P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n", 58 clnt, trans, msize, dotu); 59 spin_lock_init(&clnt->lock); 60 clnt->trans = trans; 61 clnt->msize = msize; 62 clnt->dotu = dotu; 63 INIT_LIST_HEAD(&clnt->fidlist); 64 clnt->fidpool = p9_idpool_create(); 65 if (!clnt->fidpool) { 66 err = PTR_ERR(clnt->fidpool); 67 clnt->fidpool = NULL; 68 goto error; 69 } 70 71 clnt->conn = p9_conn_create(clnt->trans, clnt->msize, &clnt->dotu); 72 if (IS_ERR(clnt->conn)) { 73 err = PTR_ERR(clnt->conn); 74 clnt->conn = NULL; 75 goto error; 76 } 77 78 tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000"); 79 if (IS_ERR(tc)) { 80 err = PTR_ERR(tc); 81 tc = NULL; 82 goto error; 83 } 84 85 err = p9_conn_rpc(clnt->conn, tc, &rc); 86 if (err) 87 goto error; 88 89 version = &rc->params.rversion.version; 90 if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8)) 91 clnt->dotu = 1; 92 else if (version->len == 6 && !memcmp(version->str, "9P2000", 6)) 93 clnt->dotu = 0; 94 else { 95 err = -EREMOTEIO; 96 goto error; 97 } 98 99 n = rc->params.rversion.msize; 100 if (n < clnt->msize) 101 clnt->msize = n; 102 103 kfree(tc); 104 kfree(rc); 105 return clnt; 106 107 error: 108 kfree(tc); 109 kfree(rc); 110 p9_client_destroy(clnt); 111 return ERR_PTR(err); 112 } 113 EXPORT_SYMBOL(p9_client_create); 114 115 void p9_client_destroy(struct p9_client *clnt) 116 { 117 struct p9_fid *fid, *fidptr; 118 119 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); 120 if (clnt->conn) { 121 p9_conn_destroy(clnt->conn); 122 clnt->conn = NULL; 123 } 124 125 if (clnt->trans) { 126 clnt->trans->close(clnt->trans); 127 kfree(clnt->trans); 128 clnt->trans = NULL; 129 } 130 131 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) 132 p9_fid_destroy(fid); 133 134 if (clnt->fidpool) 135 p9_idpool_destroy(clnt->fidpool); 136 137 kfree(clnt); 138 } 139 EXPORT_SYMBOL(p9_client_destroy); 140 141 void p9_client_disconnect(struct p9_client *clnt) 142 { 143 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); 144 clnt->trans->status = Disconnected; 145 p9_conn_cancel(clnt->conn, -EIO); 146 } 147 EXPORT_SYMBOL(p9_client_disconnect); 148 149 struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, 150 char *uname, u32 n_uname, char *aname) 151 { 152 int err; 153 struct p9_fcall *tc, *rc; 154 struct p9_fid *fid; 155 156 P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n", 157 clnt, afid?afid->fid:-1, uname, aname); 158 err = 0; 159 tc = NULL; 160 rc = NULL; 161 162 fid = p9_fid_create(clnt); 163 if (IS_ERR(fid)) { 164 err = PTR_ERR(fid); 165 fid = NULL; 166 goto error; 167 } 168 169 tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname, 170 n_uname, clnt->dotu); 171 if (IS_ERR(tc)) { 172 err = PTR_ERR(tc); 173 tc = NULL; 174 goto error; 175 } 176 177 err = p9_conn_rpc(clnt->conn, tc, &rc); 178 if (err) 179 goto error; 180 181 memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid)); 182 kfree(tc); 183 kfree(rc); 184 return fid; 185 186 error: 187 kfree(tc); 188 kfree(rc); 189 if (fid) 190 p9_fid_destroy(fid); 191 return ERR_PTR(err); 192 } 193 EXPORT_SYMBOL(p9_client_attach); 194 195 struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, 196 u32 n_uname, char *aname) 197 { 198 int err; 199 struct p9_fcall *tc, *rc; 200 struct p9_fid *fid; 201 202 P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname, 203 aname); 204 err = 0; 205 tc = NULL; 206 rc = NULL; 207 208 fid = p9_fid_create(clnt); 209 if (IS_ERR(fid)) { 210 err = PTR_ERR(fid); 211 fid = NULL; 212 goto error; 213 } 214 215 tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu); 216 if (IS_ERR(tc)) { 217 err = PTR_ERR(tc); 218 tc = NULL; 219 goto error; 220 } 221 222 err = p9_conn_rpc(clnt->conn, tc, &rc); 223 if (err) 224 goto error; 225 226 memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid)); 227 kfree(tc); 228 kfree(rc); 229 return fid; 230 231 error: 232 kfree(tc); 233 kfree(rc); 234 if (fid) 235 p9_fid_destroy(fid); 236 return ERR_PTR(err); 237 } 238 EXPORT_SYMBOL(p9_client_auth); 239 240 struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, 241 int clone) 242 { 243 int err; 244 struct p9_fcall *tc, *rc; 245 struct p9_client *clnt; 246 struct p9_fid *fid; 247 248 P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n", 249 oldfid->fid, nwname, wnames?wnames[0]:NULL); 250 err = 0; 251 tc = NULL; 252 rc = NULL; 253 clnt = oldfid->clnt; 254 if (clone) { 255 fid = p9_fid_create(clnt); 256 if (IS_ERR(fid)) { 257 err = PTR_ERR(fid); 258 fid = NULL; 259 goto error; 260 } 261 262 fid->uid = oldfid->uid; 263 } else 264 fid = oldfid; 265 266 tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames); 267 if (IS_ERR(tc)) { 268 err = PTR_ERR(tc); 269 tc = NULL; 270 goto error; 271 } 272 273 err = p9_conn_rpc(clnt->conn, tc, &rc); 274 if (err) { 275 if (rc && rc->id == P9_RWALK) 276 goto clunk_fid; 277 else 278 goto error; 279 } 280 281 if (rc->params.rwalk.nwqid != nwname) { 282 err = -ENOENT; 283 goto clunk_fid; 284 } 285 286 if (nwname) 287 memmove(&fid->qid, 288 &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1], 289 sizeof(struct p9_qid)); 290 else 291 fid->qid = oldfid->qid; 292 293 kfree(tc); 294 kfree(rc); 295 return fid; 296 297 clunk_fid: 298 kfree(tc); 299 kfree(rc); 300 rc = NULL; 301 tc = p9_create_tclunk(fid->fid); 302 if (IS_ERR(tc)) { 303 err = PTR_ERR(tc); 304 tc = NULL; 305 goto error; 306 } 307 308 p9_conn_rpc(clnt->conn, tc, &rc); 309 310 error: 311 kfree(tc); 312 kfree(rc); 313 if (fid && (fid != oldfid)) 314 p9_fid_destroy(fid); 315 316 return ERR_PTR(err); 317 } 318 EXPORT_SYMBOL(p9_client_walk); 319 320 int p9_client_open(struct p9_fid *fid, int mode) 321 { 322 int err; 323 struct p9_fcall *tc, *rc; 324 struct p9_client *clnt; 325 326 P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode); 327 err = 0; 328 tc = NULL; 329 rc = NULL; 330 clnt = fid->clnt; 331 332 if (fid->mode != -1) 333 return -EINVAL; 334 335 tc = p9_create_topen(fid->fid, mode); 336 if (IS_ERR(tc)) { 337 err = PTR_ERR(tc); 338 tc = NULL; 339 goto done; 340 } 341 342 err = p9_conn_rpc(clnt->conn, tc, &rc); 343 if (err) 344 goto done; 345 346 fid->mode = mode; 347 fid->iounit = rc->params.ropen.iounit; 348 349 done: 350 kfree(tc); 351 kfree(rc); 352 return err; 353 } 354 EXPORT_SYMBOL(p9_client_open); 355 356 int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, 357 char *extension) 358 { 359 int err; 360 struct p9_fcall *tc, *rc; 361 struct p9_client *clnt; 362 363 P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid, 364 name, perm, mode); 365 err = 0; 366 tc = NULL; 367 rc = NULL; 368 clnt = fid->clnt; 369 370 if (fid->mode != -1) 371 return -EINVAL; 372 373 tc = p9_create_tcreate(fid->fid, name, perm, mode, extension, 374 clnt->dotu); 375 if (IS_ERR(tc)) { 376 err = PTR_ERR(tc); 377 tc = NULL; 378 goto done; 379 } 380 381 err = p9_conn_rpc(clnt->conn, tc, &rc); 382 if (err) 383 goto done; 384 385 fid->mode = mode; 386 fid->iounit = rc->params.ropen.iounit; 387 388 done: 389 kfree(tc); 390 kfree(rc); 391 return err; 392 } 393 EXPORT_SYMBOL(p9_client_fcreate); 394 395 int p9_client_clunk(struct p9_fid *fid) 396 { 397 int err; 398 struct p9_fcall *tc, *rc; 399 struct p9_client *clnt; 400 401 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 402 err = 0; 403 tc = NULL; 404 rc = NULL; 405 clnt = fid->clnt; 406 407 tc = p9_create_tclunk(fid->fid); 408 if (IS_ERR(tc)) { 409 err = PTR_ERR(tc); 410 tc = NULL; 411 goto done; 412 } 413 414 err = p9_conn_rpc(clnt->conn, tc, &rc); 415 if (err) 416 goto done; 417 418 p9_fid_destroy(fid); 419 420 done: 421 kfree(tc); 422 kfree(rc); 423 return err; 424 } 425 EXPORT_SYMBOL(p9_client_clunk); 426 427 int p9_client_remove(struct p9_fid *fid) 428 { 429 int err; 430 struct p9_fcall *tc, *rc; 431 struct p9_client *clnt; 432 433 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 434 err = 0; 435 tc = NULL; 436 rc = NULL; 437 clnt = fid->clnt; 438 439 tc = p9_create_tremove(fid->fid); 440 if (IS_ERR(tc)) { 441 err = PTR_ERR(tc); 442 tc = NULL; 443 goto done; 444 } 445 446 err = p9_conn_rpc(clnt->conn, tc, &rc); 447 if (err) 448 goto done; 449 450 p9_fid_destroy(fid); 451 452 done: 453 kfree(tc); 454 kfree(rc); 455 return err; 456 } 457 EXPORT_SYMBOL(p9_client_remove); 458 459 int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count) 460 { 461 int err, n, rsize, total; 462 struct p9_fcall *tc, *rc; 463 struct p9_client *clnt; 464 465 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid, 466 (long long unsigned) offset, count); 467 err = 0; 468 tc = NULL; 469 rc = NULL; 470 clnt = fid->clnt; 471 total = 0; 472 473 rsize = fid->iounit; 474 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 475 rsize = clnt->msize - P9_IOHDRSZ; 476 477 do { 478 if (count < rsize) 479 rsize = count; 480 481 tc = p9_create_tread(fid->fid, offset, rsize); 482 if (IS_ERR(tc)) { 483 err = PTR_ERR(tc); 484 tc = NULL; 485 goto error; 486 } 487 488 err = p9_conn_rpc(clnt->conn, tc, &rc); 489 if (err) 490 goto error; 491 492 n = rc->params.rread.count; 493 if (n > count) 494 n = count; 495 496 memmove(data, rc->params.rread.data, n); 497 count -= n; 498 data += n; 499 offset += n; 500 total += n; 501 kfree(tc); 502 tc = NULL; 503 kfree(rc); 504 rc = NULL; 505 } while (count > 0 && n == rsize); 506 507 return total; 508 509 error: 510 kfree(tc); 511 kfree(rc); 512 return err; 513 } 514 EXPORT_SYMBOL(p9_client_read); 515 516 int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count) 517 { 518 int err, n, rsize, total; 519 struct p9_fcall *tc, *rc; 520 struct p9_client *clnt; 521 522 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, 523 (long long unsigned) offset, count); 524 err = 0; 525 tc = NULL; 526 rc = NULL; 527 clnt = fid->clnt; 528 total = 0; 529 530 rsize = fid->iounit; 531 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 532 rsize = clnt->msize - P9_IOHDRSZ; 533 534 do { 535 if (count < rsize) 536 rsize = count; 537 538 tc = p9_create_twrite(fid->fid, offset, rsize, data); 539 if (IS_ERR(tc)) { 540 err = PTR_ERR(tc); 541 tc = NULL; 542 goto error; 543 } 544 545 err = p9_conn_rpc(clnt->conn, tc, &rc); 546 if (err) 547 goto error; 548 549 n = rc->params.rread.count; 550 count -= n; 551 data += n; 552 offset += n; 553 total += n; 554 kfree(tc); 555 tc = NULL; 556 kfree(rc); 557 rc = NULL; 558 } while (count > 0); 559 560 return total; 561 562 error: 563 kfree(tc); 564 kfree(rc); 565 return err; 566 } 567 EXPORT_SYMBOL(p9_client_write); 568 569 int 570 p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count) 571 { 572 int err, n, rsize, total; 573 struct p9_fcall *tc, *rc; 574 struct p9_client *clnt; 575 576 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, 577 (long long unsigned) offset, count); 578 err = 0; 579 tc = NULL; 580 rc = NULL; 581 clnt = fid->clnt; 582 total = 0; 583 584 rsize = fid->iounit; 585 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 586 rsize = clnt->msize - P9_IOHDRSZ; 587 588 do { 589 if (count < rsize) 590 rsize = count; 591 592 tc = p9_create_tread(fid->fid, offset, rsize); 593 if (IS_ERR(tc)) { 594 err = PTR_ERR(tc); 595 tc = NULL; 596 goto error; 597 } 598 599 err = p9_conn_rpc(clnt->conn, tc, &rc); 600 if (err) 601 goto error; 602 603 n = rc->params.rread.count; 604 if (n > count) 605 n = count; 606 607 err = copy_to_user(data, rc->params.rread.data, n); 608 if (err) { 609 err = -EFAULT; 610 goto error; 611 } 612 613 count -= n; 614 data += n; 615 offset += n; 616 total += n; 617 kfree(tc); 618 tc = NULL; 619 kfree(rc); 620 rc = NULL; 621 } while (count > 0 && n == rsize); 622 623 return total; 624 625 error: 626 kfree(tc); 627 kfree(rc); 628 return err; 629 } 630 EXPORT_SYMBOL(p9_client_uread); 631 632 int 633 p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset, 634 u32 count) 635 { 636 int err, n, rsize, total; 637 struct p9_fcall *tc, *rc; 638 struct p9_client *clnt; 639 640 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, 641 (long long unsigned) offset, count); 642 err = 0; 643 tc = NULL; 644 rc = NULL; 645 clnt = fid->clnt; 646 total = 0; 647 648 rsize = fid->iounit; 649 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 650 rsize = clnt->msize - P9_IOHDRSZ; 651 652 do { 653 if (count < rsize) 654 rsize = count; 655 656 tc = p9_create_twrite_u(fid->fid, offset, rsize, data); 657 if (IS_ERR(tc)) { 658 err = PTR_ERR(tc); 659 tc = NULL; 660 goto error; 661 } 662 663 err = p9_conn_rpc(clnt->conn, tc, &rc); 664 if (err) 665 goto error; 666 667 n = rc->params.rread.count; 668 count -= n; 669 data += n; 670 offset += n; 671 total += n; 672 kfree(tc); 673 tc = NULL; 674 kfree(rc); 675 rc = NULL; 676 } while (count > 0); 677 678 return total; 679 680 error: 681 kfree(tc); 682 kfree(rc); 683 return err; 684 } 685 EXPORT_SYMBOL(p9_client_uwrite); 686 687 int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count) 688 { 689 int n, total; 690 691 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, 692 (long long unsigned) offset, count); 693 n = 0; 694 total = 0; 695 while (count) { 696 n = p9_client_read(fid, data, offset, count); 697 if (n <= 0) 698 break; 699 700 data += n; 701 offset += n; 702 count -= n; 703 total += n; 704 } 705 706 if (n < 0) 707 total = n; 708 709 return total; 710 } 711 EXPORT_SYMBOL(p9_client_readn); 712 713 struct p9_stat *p9_client_stat(struct p9_fid *fid) 714 { 715 int err; 716 struct p9_fcall *tc, *rc; 717 struct p9_client *clnt; 718 struct p9_stat *ret; 719 720 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 721 err = 0; 722 tc = NULL; 723 rc = NULL; 724 ret = NULL; 725 clnt = fid->clnt; 726 727 tc = p9_create_tstat(fid->fid); 728 if (IS_ERR(tc)) { 729 err = PTR_ERR(tc); 730 tc = NULL; 731 goto error; 732 } 733 734 err = p9_conn_rpc(clnt->conn, tc, &rc); 735 if (err) 736 goto error; 737 738 ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu); 739 if (IS_ERR(ret)) { 740 err = PTR_ERR(ret); 741 ret = NULL; 742 goto error; 743 } 744 745 kfree(tc); 746 kfree(rc); 747 return ret; 748 749 error: 750 kfree(tc); 751 kfree(rc); 752 kfree(ret); 753 return ERR_PTR(err); 754 } 755 EXPORT_SYMBOL(p9_client_stat); 756 757 int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) 758 { 759 int err; 760 struct p9_fcall *tc, *rc; 761 struct p9_client *clnt; 762 763 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 764 err = 0; 765 tc = NULL; 766 rc = NULL; 767 clnt = fid->clnt; 768 769 tc = p9_create_twstat(fid->fid, wst, clnt->dotu); 770 if (IS_ERR(tc)) { 771 err = PTR_ERR(tc); 772 tc = NULL; 773 goto done; 774 } 775 776 err = p9_conn_rpc(clnt->conn, tc, &rc); 777 778 done: 779 kfree(tc); 780 kfree(rc); 781 return err; 782 } 783 EXPORT_SYMBOL(p9_client_wstat); 784 785 struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset) 786 { 787 int err, n, m; 788 struct p9_fcall *tc, *rc; 789 struct p9_client *clnt; 790 struct p9_stat st, *ret; 791 792 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu\n", fid->fid, 793 (long long unsigned) offset); 794 err = 0; 795 tc = NULL; 796 rc = NULL; 797 ret = NULL; 798 clnt = fid->clnt; 799 800 /* if the offset is below or above the current response, free it */ 801 if (offset < fid->rdir_fpos || (fid->rdir_fcall && 802 offset >= fid->rdir_fpos+fid->rdir_fcall->params.rread.count)) { 803 fid->rdir_pos = 0; 804 if (fid->rdir_fcall) 805 fid->rdir_fpos += fid->rdir_fcall->params.rread.count; 806 807 kfree(fid->rdir_fcall); 808 fid->rdir_fcall = NULL; 809 if (offset < fid->rdir_fpos) 810 fid->rdir_fpos = 0; 811 } 812 813 if (!fid->rdir_fcall) { 814 n = fid->iounit; 815 if (!n || n > clnt->msize-P9_IOHDRSZ) 816 n = clnt->msize - P9_IOHDRSZ; 817 818 while (1) { 819 if (fid->rdir_fcall) { 820 fid->rdir_fpos += 821 fid->rdir_fcall->params.rread.count; 822 kfree(fid->rdir_fcall); 823 fid->rdir_fcall = NULL; 824 } 825 826 tc = p9_create_tread(fid->fid, fid->rdir_fpos, n); 827 if (IS_ERR(tc)) { 828 err = PTR_ERR(tc); 829 tc = NULL; 830 goto error; 831 } 832 833 err = p9_conn_rpc(clnt->conn, tc, &rc); 834 if (err) 835 goto error; 836 837 n = rc->params.rread.count; 838 if (n == 0) 839 goto done; 840 841 fid->rdir_fcall = rc; 842 rc = NULL; 843 if (offset >= fid->rdir_fpos && 844 offset < fid->rdir_fpos+n) 845 break; 846 } 847 848 fid->rdir_pos = 0; 849 } 850 851 m = offset - fid->rdir_fpos; 852 if (m < 0) 853 goto done; 854 855 n = p9_deserialize_stat(fid->rdir_fcall->params.rread.data + m, 856 fid->rdir_fcall->params.rread.count - m, &st, clnt->dotu); 857 858 if (!n) { 859 err = -EIO; 860 goto error; 861 } 862 863 fid->rdir_pos += n; 864 st.size = n; 865 ret = p9_clone_stat(&st, clnt->dotu); 866 if (IS_ERR(ret)) { 867 err = PTR_ERR(ret); 868 ret = NULL; 869 goto error; 870 } 871 872 done: 873 kfree(tc); 874 kfree(rc); 875 return ret; 876 877 error: 878 kfree(tc); 879 kfree(rc); 880 kfree(ret); 881 return ERR_PTR(err); 882 } 883 EXPORT_SYMBOL(p9_client_dirread); 884 885 static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu) 886 { 887 int n; 888 char *p; 889 struct p9_stat *ret; 890 891 n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len + 892 st->muid.len; 893 894 if (dotu) 895 n += st->extension.len; 896 897 ret = kmalloc(n, GFP_KERNEL); 898 if (!ret) 899 return ERR_PTR(-ENOMEM); 900 901 memmove(ret, st, sizeof(struct p9_stat)); 902 p = ((char *) ret) + sizeof(struct p9_stat); 903 memmove(p, st->name.str, st->name.len); 904 p += st->name.len; 905 memmove(p, st->uid.str, st->uid.len); 906 p += st->uid.len; 907 memmove(p, st->gid.str, st->gid.len); 908 p += st->gid.len; 909 memmove(p, st->muid.str, st->muid.len); 910 p += st->muid.len; 911 912 if (dotu) { 913 memmove(p, st->extension.str, st->extension.len); 914 p += st->extension.len; 915 } 916 917 return ret; 918 } 919 920 static struct p9_fid *p9_fid_create(struct p9_client *clnt) 921 { 922 int err; 923 struct p9_fid *fid; 924 925 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); 926 fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL); 927 if (!fid) 928 return ERR_PTR(-ENOMEM); 929 930 fid->fid = p9_idpool_get(clnt->fidpool); 931 if (fid->fid < 0) { 932 err = -ENOSPC; 933 goto error; 934 } 935 936 memset(&fid->qid, 0, sizeof(struct p9_qid)); 937 fid->mode = -1; 938 fid->rdir_fpos = 0; 939 fid->rdir_pos = 0; 940 fid->rdir_fcall = NULL; 941 fid->uid = current->fsuid; 942 fid->clnt = clnt; 943 fid->aux = NULL; 944 945 spin_lock(&clnt->lock); 946 list_add(&fid->flist, &clnt->fidlist); 947 spin_unlock(&clnt->lock); 948 949 return fid; 950 951 error: 952 kfree(fid); 953 return ERR_PTR(err); 954 } 955 956 static void p9_fid_destroy(struct p9_fid *fid) 957 { 958 struct p9_client *clnt; 959 960 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); 961 clnt = fid->clnt; 962 p9_idpool_put(fid->fid, clnt->fidpool); 963 spin_lock(&clnt->lock); 964 list_del(&fid->flist); 965 spin_unlock(&clnt->lock); 966 kfree(fid->rdir_fcall); 967 kfree(fid); 968 } 969