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