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