linux/net/9p/client.c
<<
>>
Prefs
   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
  39static struct p9_fid *p9_fid_create(struct p9_client *clnt);
  40static void p9_fid_destroy(struct p9_fid *fid);
  41static 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
  48enum {
  49        Opt_msize,
  50        Opt_trans,
  51        Opt_legacy,
  52        Opt_err,
  53};
  54
  55static 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
  70static 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 */
 135int
 136p9_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
 142struct 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
 222error:
 223        kfree(tc);
 224        kfree(rc);
 225        p9_client_destroy(clnt);
 226        return ERR_PTR(err);
 227}
 228EXPORT_SYMBOL(p9_client_create);
 229
 230void 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}
 252EXPORT_SYMBOL(p9_client_destroy);
 253
 254void p9_client_disconnect(struct p9_client *clnt)
 255{
 256        P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
 257        clnt->trans->status = Disconnected;
 258}
 259EXPORT_SYMBOL(p9_client_disconnect);
 260
 261struct 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
 298error:
 299        kfree(tc);
 300        kfree(rc);
 301        if (fid)
 302                p9_fid_destroy(fid);
 303        return ERR_PTR(err);
 304}
 305EXPORT_SYMBOL(p9_client_attach);
 306
 307struct 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
 343error:
 344        kfree(tc);
 345        kfree(rc);
 346        if (fid)
 347                p9_fid_destroy(fid);
 348        return ERR_PTR(err);
 349}
 350EXPORT_SYMBOL(p9_client_auth);
 351
 352struct 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
 409clunk_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
 422error:
 423        kfree(tc);
 424        kfree(rc);
 425        if (fid && (fid != oldfid))
 426                p9_fid_destroy(fid);
 427
 428        return ERR_PTR(err);
 429}
 430EXPORT_SYMBOL(p9_client_walk);
 431
 432int 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
 461done:
 462        kfree(tc);
 463        kfree(rc);
 464        return err;
 465}
 466EXPORT_SYMBOL(p9_client_open);
 467
 468int 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
 500done:
 501        kfree(tc);
 502        kfree(rc);
 503        return err;
 504}
 505EXPORT_SYMBOL(p9_client_fcreate);
 506
 507int 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
 532done:
 533        kfree(tc);
 534        kfree(rc);
 535        return err;
 536}
 537EXPORT_SYMBOL(p9_client_clunk);
 538
 539int 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
 564done:
 565        kfree(tc);
 566        kfree(rc);
 567        return err;
 568}
 569EXPORT_SYMBOL(p9_client_remove);
 570
 571int 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
 621error:
 622        kfree(tc);
 623        kfree(rc);
 624        return err;
 625}
 626EXPORT_SYMBOL(p9_client_read);
 627
 628int 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
 674error:
 675        kfree(tc);
 676        kfree(rc);
 677        return err;
 678}
 679EXPORT_SYMBOL(p9_client_write);
 680
 681int
 682p9_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
 737error:
 738        kfree(tc);
 739        kfree(rc);
 740        return err;
 741}
 742EXPORT_SYMBOL(p9_client_uread);
 743
 744int
 745p9_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
 792error:
 793        kfree(tc);
 794        kfree(rc);
 795        return err;
 796}
 797EXPORT_SYMBOL(p9_client_uwrite);
 798
 799int 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}
 823EXPORT_SYMBOL(p9_client_readn);
 824
 825struct 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
 861error:
 862        kfree(tc);
 863        kfree(rc);
 864        kfree(ret);
 865        return ERR_PTR(err);
 866}
 867EXPORT_SYMBOL(p9_client_stat);
 868
 869int 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
 890done:
 891        kfree(tc);
 892        kfree(rc);
 893        return err;
 894}
 895EXPORT_SYMBOL(p9_client_wstat);
 896
 897struct 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
 984done:
 985        kfree(tc);
 986        kfree(rc);
 987        return ret;
 988
 989error:
 990        kfree(tc);
 991        kfree(rc);
 992        kfree(ret);
 993        return ERR_PTR(err);
 994}
 995EXPORT_SYMBOL(p9_client_dirread);
 996
 997static 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
1037static 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
1068error:
1069        kfree(fid);
1070        return ERR_PTR(err);
1071}
1072
1073static 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