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/slab.h>
  33#include <linux/sched.h>
  34#include <linux/uaccess.h>
  35#include <net/9p/9p.h>
  36#include <linux/parser.h>
  37#include <net/9p/client.h>
  38#include <net/9p/transport.h>
  39#include "protocol.h"
  40
  41/*
  42  * Client Option Parsing (code inspired by NFS code)
  43  *  - a little lazy - parse all client options
  44  */
  45
  46enum {
  47        Opt_msize,
  48        Opt_trans,
  49        Opt_legacy,
  50        Opt_version,
  51        Opt_err,
  52};
  53
  54static const match_table_t tokens = {
  55        {Opt_msize, "msize=%u"},
  56        {Opt_legacy, "noextend"},
  57        {Opt_trans, "trans=%s"},
  58        {Opt_version, "version=%s"},
  59        {Opt_err, NULL},
  60};
  61
  62inline int p9_is_proto_dotl(struct p9_client *clnt)
  63{
  64        return (clnt->proto_version == p9_proto_2000L);
  65}
  66EXPORT_SYMBOL(p9_is_proto_dotl);
  67
  68inline int p9_is_proto_dotu(struct p9_client *clnt)
  69{
  70        return (clnt->proto_version == p9_proto_2000u);
  71}
  72EXPORT_SYMBOL(p9_is_proto_dotu);
  73
  74/* Interpret mount option for protocol version */
  75static int get_protocol_version(const substring_t *name)
  76{
  77        int version = -EINVAL;
  78
  79        if (!strncmp("9p2000", name->from, name->to-name->from)) {
  80                version = p9_proto_legacy;
  81                P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n");
  82        } else if (!strncmp("9p2000.u", name->from, name->to-name->from)) {
  83                version = p9_proto_2000u;
  84                P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.u\n");
  85        } else if (!strncmp("9p2000.L", name->from, name->to-name->from)) {
  86                version = p9_proto_2000L;
  87                P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.L\n");
  88        } else {
  89                P9_DPRINTK(P9_DEBUG_ERROR, "Unknown protocol version %s. ",
  90                                                        name->from);
  91        }
  92        return version;
  93}
  94
  95static struct p9_req_t *
  96p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
  97
  98/**
  99 * parse_options - parse mount options into client structure
 100 * @opts: options string passed from mount
 101 * @clnt: existing v9fs client information
 102 *
 103 * Return 0 upon success, -ERRNO upon failure
 104 */
 105
 106static int parse_opts(char *opts, struct p9_client *clnt)
 107{
 108        char *options, *tmp_options;
 109        char *p;
 110        substring_t args[MAX_OPT_ARGS];
 111        int option;
 112        int ret = 0;
 113
 114        clnt->proto_version = p9_proto_2000u;
 115        clnt->msize = 8192;
 116
 117        if (!opts)
 118                return 0;
 119
 120        tmp_options = kstrdup(opts, GFP_KERNEL);
 121        if (!tmp_options) {
 122                P9_DPRINTK(P9_DEBUG_ERROR,
 123                                "failed to allocate copy of option string\n");
 124                return -ENOMEM;
 125        }
 126        options = tmp_options;
 127
 128        while ((p = strsep(&options, ",")) != NULL) {
 129                int token;
 130                if (!*p)
 131                        continue;
 132                token = match_token(p, tokens, args);
 133                if (token < Opt_trans) {
 134                        int r = match_int(&args[0], &option);
 135                        if (r < 0) {
 136                                P9_DPRINTK(P9_DEBUG_ERROR,
 137                                        "integer field, but no integer?\n");
 138                                ret = r;
 139                                continue;
 140                        }
 141                }
 142                switch (token) {
 143                case Opt_msize:
 144                        clnt->msize = option;
 145                        break;
 146                case Opt_trans:
 147                        clnt->trans_mod = v9fs_get_trans_by_name(&args[0]);
 148                        if(clnt->trans_mod == NULL) {
 149                                P9_DPRINTK(P9_DEBUG_ERROR,
 150                                   "Could not find request transport: %s\n",
 151                                   (char *) &args[0]);
 152                                ret = -EINVAL;
 153                                goto free_and_return;
 154                        }
 155                        break;
 156                case Opt_legacy:
 157                        clnt->proto_version = p9_proto_legacy;
 158                        break;
 159                case Opt_version:
 160                        ret = get_protocol_version(&args[0]);
 161                        if (ret == -EINVAL)
 162                                goto free_and_return;
 163                        clnt->proto_version = ret;
 164                        break;
 165                default:
 166                        continue;
 167                }
 168        }
 169
 170free_and_return:
 171        kfree(tmp_options);
 172        return ret;
 173}
 174
 175/**
 176 * p9_tag_alloc - lookup/allocate a request by tag
 177 * @c: client session to lookup tag within
 178 * @tag: numeric id for transaction
 179 *
 180 * this is a simple array lookup, but will grow the
 181 * request_slots as necessary to accomodate transaction
 182 * ids which did not previously have a slot.
 183 *
 184 * this code relies on the client spinlock to manage locks, its
 185 * possible we should switch to something else, but I'd rather
 186 * stick with something low-overhead for the common case.
 187 *
 188 */
 189
 190static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
 191{
 192        unsigned long flags;
 193        int row, col;
 194        struct p9_req_t *req;
 195
 196        /* This looks up the original request by tag so we know which
 197         * buffer to read the data into */
 198        tag++;
 199
 200        if (tag >= c->max_tag) {
 201                spin_lock_irqsave(&c->lock, flags);
 202                /* check again since original check was outside of lock */
 203                while (tag >= c->max_tag) {
 204                        row = (tag / P9_ROW_MAXTAG);
 205                        c->reqs[row] = kcalloc(P9_ROW_MAXTAG,
 206                                        sizeof(struct p9_req_t), GFP_ATOMIC);
 207
 208                        if (!c->reqs[row]) {
 209                                printk(KERN_ERR "Couldn't grow tag array\n");
 210                                spin_unlock_irqrestore(&c->lock, flags);
 211                                return ERR_PTR(-ENOMEM);
 212                        }
 213                        for (col = 0; col < P9_ROW_MAXTAG; col++) {
 214                                c->reqs[row][col].status = REQ_STATUS_IDLE;
 215                                c->reqs[row][col].tc = NULL;
 216                        }
 217                        c->max_tag += P9_ROW_MAXTAG;
 218                }
 219                spin_unlock_irqrestore(&c->lock, flags);
 220        }
 221        row = tag / P9_ROW_MAXTAG;
 222        col = tag % P9_ROW_MAXTAG;
 223
 224        req = &c->reqs[row][col];
 225        if (!req->tc) {
 226                req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
 227                if (!req->wq) {
 228                        printk(KERN_ERR "Couldn't grow tag array\n");
 229                        return ERR_PTR(-ENOMEM);
 230                }
 231                init_waitqueue_head(req->wq);
 232                req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize,
 233                                                                GFP_KERNEL);
 234                req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize,
 235                                                                GFP_KERNEL);
 236                if ((!req->tc) || (!req->rc)) {
 237                        printk(KERN_ERR "Couldn't grow tag array\n");
 238                        kfree(req->tc);
 239                        kfree(req->rc);
 240                        kfree(req->wq);
 241                        req->tc = req->rc = NULL;
 242                        req->wq = NULL;
 243                        return ERR_PTR(-ENOMEM);
 244                }
 245                req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall);
 246                req->tc->capacity = c->msize;
 247                req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall);
 248                req->rc->capacity = c->msize;
 249        }
 250
 251        p9pdu_reset(req->tc);
 252        p9pdu_reset(req->rc);
 253
 254        req->tc->tag = tag-1;
 255        req->status = REQ_STATUS_ALLOC;
 256
 257        return &c->reqs[row][col];
 258}
 259
 260/**
 261 * p9_tag_lookup - lookup a request by tag
 262 * @c: client session to lookup tag within
 263 * @tag: numeric id for transaction
 264 *
 265 */
 266
 267struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag)
 268{
 269        int row, col;
 270
 271        /* This looks up the original request by tag so we know which
 272         * buffer to read the data into */
 273        tag++;
 274
 275        BUG_ON(tag >= c->max_tag);
 276
 277        row = tag / P9_ROW_MAXTAG;
 278        col = tag % P9_ROW_MAXTAG;
 279
 280        return &c->reqs[row][col];
 281}
 282EXPORT_SYMBOL(p9_tag_lookup);
 283
 284/**
 285 * p9_tag_init - setup tags structure and contents
 286 * @c:  v9fs client struct
 287 *
 288 * This initializes the tags structure for each client instance.
 289 *
 290 */
 291
 292static int p9_tag_init(struct p9_client *c)
 293{
 294        int err = 0;
 295
 296        c->tagpool = p9_idpool_create();
 297        if (IS_ERR(c->tagpool)) {
 298                err = PTR_ERR(c->tagpool);
 299                c->tagpool = NULL;
 300                goto error;
 301        }
 302
 303        p9_idpool_get(c->tagpool); /* reserve tag 0 */
 304
 305        c->max_tag = 0;
 306error:
 307        return err;
 308}
 309
 310/**
 311 * p9_tag_cleanup - cleans up tags structure and reclaims resources
 312 * @c:  v9fs client struct
 313 *
 314 * This frees resources associated with the tags structure
 315 *
 316 */
 317static void p9_tag_cleanup(struct p9_client *c)
 318{
 319        int row, col;
 320
 321        /* check to insure all requests are idle */
 322        for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
 323                for (col = 0; col < P9_ROW_MAXTAG; col++) {
 324                        if (c->reqs[row][col].status != REQ_STATUS_IDLE) {
 325                                P9_DPRINTK(P9_DEBUG_MUX,
 326                                  "Attempting to cleanup non-free tag %d,%d\n",
 327                                  row, col);
 328                                /* TODO: delay execution of cleanup */
 329                                return;
 330                        }
 331                }
 332        }
 333
 334        if (c->tagpool)
 335                p9_idpool_destroy(c->tagpool);
 336
 337        /* free requests associated with tags */
 338        for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
 339                for (col = 0; col < P9_ROW_MAXTAG; col++) {
 340                        kfree(c->reqs[row][col].wq);
 341                        kfree(c->reqs[row][col].tc);
 342                        kfree(c->reqs[row][col].rc);
 343                }
 344                kfree(c->reqs[row]);
 345        }
 346        c->max_tag = 0;
 347}
 348
 349/**
 350 * p9_free_req - free a request and clean-up as necessary
 351 * c: client state
 352 * r: request to release
 353 *
 354 */
 355
 356static void p9_free_req(struct p9_client *c, struct p9_req_t *r)
 357{
 358        int tag = r->tc->tag;
 359        P9_DPRINTK(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag);
 360
 361        r->status = REQ_STATUS_IDLE;
 362        if (tag != P9_NOTAG && p9_idpool_check(tag, c->tagpool))
 363                p9_idpool_put(tag, c->tagpool);
 364}
 365
 366/**
 367 * p9_client_cb - call back from transport to client
 368 * c: client state
 369 * req: request received
 370 *
 371 */
 372void p9_client_cb(struct p9_client *c, struct p9_req_t *req)
 373{
 374        P9_DPRINTK(P9_DEBUG_MUX, " tag %d\n", req->tc->tag);
 375        wake_up(req->wq);
 376        P9_DPRINTK(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag);
 377}
 378EXPORT_SYMBOL(p9_client_cb);
 379
 380/**
 381 * p9_parse_header - parse header arguments out of a packet
 382 * @pdu: packet to parse
 383 * @size: size of packet
 384 * @type: type of request
 385 * @tag: tag of packet
 386 * @rewind: set if we need to rewind offset afterwards
 387 */
 388
 389int
 390p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, int16_t *tag,
 391                                                                int rewind)
 392{
 393        int8_t r_type;
 394        int16_t r_tag;
 395        int32_t r_size;
 396        int offset = pdu->offset;
 397        int err;
 398
 399        pdu->offset = 0;
 400        if (pdu->size == 0)
 401                pdu->size = 7;
 402
 403        err = p9pdu_readf(pdu, 0, "dbw", &r_size, &r_type, &r_tag);
 404        if (err)
 405                goto rewind_and_exit;
 406
 407        pdu->size = r_size;
 408        pdu->id = r_type;
 409        pdu->tag = r_tag;
 410
 411        P9_DPRINTK(P9_DEBUG_9P, "<<< size=%d type: %d tag: %d\n", pdu->size,
 412                                                        pdu->id, pdu->tag);
 413
 414        if (type)
 415                *type = r_type;
 416        if (tag)
 417                *tag = r_tag;
 418        if (size)
 419                *size = r_size;
 420
 421
 422rewind_and_exit:
 423        if (rewind)
 424                pdu->offset = offset;
 425        return err;
 426}
 427EXPORT_SYMBOL(p9_parse_header);
 428
 429/**
 430 * p9_check_errors - check 9p packet for error return and process it
 431 * @c: current client instance
 432 * @req: request to parse and check for error conditions
 433 *
 434 * returns error code if one is discovered, otherwise returns 0
 435 *
 436 * this will have to be more complicated if we have multiple
 437 * error packet types
 438 */
 439
 440static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
 441{
 442        int8_t type;
 443        int err;
 444
 445        err = p9_parse_header(req->rc, NULL, &type, NULL, 0);
 446        if (err) {
 447                P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err);
 448                return err;
 449        }
 450
 451        if (type == P9_RERROR) {
 452                int ecode;
 453                char *ename;
 454
 455                err = p9pdu_readf(req->rc, c->proto_version, "s?d",
 456                                                        &ename, &ecode);
 457                if (err) {
 458                        P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
 459                                                                        err);
 460                        return err;
 461                }
 462
 463                if (p9_is_proto_dotu(c))
 464                        err = -ecode;
 465
 466                if (!err || !IS_ERR_VALUE(err))
 467                        err = p9_errstr2errno(ename, strlen(ename));
 468
 469                P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename);
 470
 471                kfree(ename);
 472        } else
 473                err = 0;
 474
 475        return err;
 476}
 477
 478/**
 479 * p9_client_flush - flush (cancel) a request
 480 * @c: client state
 481 * @oldreq: request to cancel
 482 *
 483 * This sents a flush for a particular requests and links
 484 * the flush request to the original request.  The current
 485 * code only supports a single flush request although the protocol
 486 * allows for multiple flush requests to be sent for a single request.
 487 *
 488 */
 489
 490static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
 491{
 492        struct p9_req_t *req;
 493        int16_t oldtag;
 494        int err;
 495
 496        err = p9_parse_header(oldreq->tc, NULL, NULL, &oldtag, 1);
 497        if (err)
 498                return err;
 499
 500        P9_DPRINTK(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag);
 501
 502        req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag);
 503        if (IS_ERR(req))
 504                return PTR_ERR(req);
 505
 506
 507        /* if we haven't received a response for oldreq,
 508           remove it from the list. */
 509        spin_lock(&c->lock);
 510        if (oldreq->status == REQ_STATUS_FLSH)
 511                list_del(&oldreq->req_list);
 512        spin_unlock(&c->lock);
 513
 514        p9_free_req(c, req);
 515        return 0;
 516}
 517
 518/**
 519 * p9_client_rpc - issue a request and wait for a response
 520 * @c: client session
 521 * @type: type of request
 522 * @fmt: protocol format string (see protocol.c)
 523 *
 524 * Returns request structure (which client must free using p9_free_req)
 525 */
 526
 527static struct p9_req_t *
 528p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
 529{
 530        va_list ap;
 531        int tag, err;
 532        struct p9_req_t *req;
 533        unsigned long flags;
 534        int sigpending;
 535
 536        P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type);
 537
 538        /* we allow for any status other than disconnected */
 539        if (c->status == Disconnected)
 540                return ERR_PTR(-EIO);
 541
 542        /* if status is begin_disconnected we allow only clunk request */
 543        if ((c->status == BeginDisconnect) && (type != P9_TCLUNK))
 544                return ERR_PTR(-EIO);
 545
 546        if (signal_pending(current)) {
 547                sigpending = 1;
 548                clear_thread_flag(TIF_SIGPENDING);
 549        } else
 550                sigpending = 0;
 551
 552        tag = P9_NOTAG;
 553        if (type != P9_TVERSION) {
 554                tag = p9_idpool_get(c->tagpool);
 555                if (tag < 0)
 556                        return ERR_PTR(-ENOMEM);
 557        }
 558
 559        req = p9_tag_alloc(c, tag);
 560        if (IS_ERR(req))
 561                return req;
 562
 563        /* marshall the data */
 564        p9pdu_prepare(req->tc, tag, type);
 565        va_start(ap, fmt);
 566        err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap);
 567        va_end(ap);
 568        p9pdu_finalize(req->tc);
 569
 570        err = c->trans_mod->request(c, req);
 571        if (err < 0) {
 572                c->status = Disconnected;
 573                goto reterr;
 574        }
 575
 576        P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d\n", req->wq, tag);
 577        err = wait_event_interruptible(*req->wq,
 578                                                req->status >= REQ_STATUS_RCVD);
 579        P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d returned %d\n",
 580                                                req->wq, tag, err);
 581
 582        if (req->status == REQ_STATUS_ERROR) {
 583                P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
 584                err = req->t_err;
 585        }
 586
 587        if ((err == -ERESTARTSYS) && (c->status == Connected)) {
 588                P9_DPRINTK(P9_DEBUG_MUX, "flushing\n");
 589                sigpending = 1;
 590                clear_thread_flag(TIF_SIGPENDING);
 591
 592                if (c->trans_mod->cancel(c, req))
 593                        p9_client_flush(c, req);
 594
 595                /* if we received the response anyway, don't signal error */
 596                if (req->status == REQ_STATUS_RCVD)
 597                        err = 0;
 598        }
 599
 600        if (sigpending) {
 601                spin_lock_irqsave(&current->sighand->siglock, flags);
 602                recalc_sigpending();
 603                spin_unlock_irqrestore(&current->sighand->siglock, flags);
 604        }
 605
 606        if (err < 0)
 607                goto reterr;
 608
 609        err = p9_check_errors(c, req);
 610        if (!err) {
 611                P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d\n", c, type);
 612                return req;
 613        }
 614
 615reterr:
 616        P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d error: %d\n", c, type,
 617                                                                        err);
 618        p9_free_req(c, req);
 619        return ERR_PTR(err);
 620}
 621
 622static struct p9_fid *p9_fid_create(struct p9_client *clnt)
 623{
 624        int ret;
 625        struct p9_fid *fid;
 626        unsigned long flags;
 627
 628        P9_DPRINTK(P9_DEBUG_FID, "clnt %p\n", clnt);
 629        fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
 630        if (!fid)
 631                return ERR_PTR(-ENOMEM);
 632
 633        ret = p9_idpool_get(clnt->fidpool);
 634        if (ret < 0) {
 635                ret = -ENOSPC;
 636                goto error;
 637        }
 638        fid->fid = ret;
 639
 640        memset(&fid->qid, 0, sizeof(struct p9_qid));
 641        fid->mode = -1;
 642        fid->uid = current_fsuid();
 643        fid->clnt = clnt;
 644        fid->rdir = NULL;
 645        spin_lock_irqsave(&clnt->lock, flags);
 646        list_add(&fid->flist, &clnt->fidlist);
 647        spin_unlock_irqrestore(&clnt->lock, flags);
 648
 649        return fid;
 650
 651error:
 652        kfree(fid);
 653        return ERR_PTR(ret);
 654}
 655
 656static void p9_fid_destroy(struct p9_fid *fid)
 657{
 658        struct p9_client *clnt;
 659        unsigned long flags;
 660
 661        P9_DPRINTK(P9_DEBUG_FID, "fid %d\n", fid->fid);
 662        clnt = fid->clnt;
 663        p9_idpool_put(fid->fid, clnt->fidpool);
 664        spin_lock_irqsave(&clnt->lock, flags);
 665        list_del(&fid->flist);
 666        spin_unlock_irqrestore(&clnt->lock, flags);
 667        kfree(fid->rdir);
 668        kfree(fid);
 669}
 670
 671int p9_client_version(struct p9_client *c)
 672{
 673        int err = 0;
 674        struct p9_req_t *req;
 675        char *version;
 676        int msize;
 677
 678        P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n",
 679                                                c->msize, c->proto_version);
 680
 681        switch (c->proto_version) {
 682        case p9_proto_2000L:
 683                req = p9_client_rpc(c, P9_TVERSION, "ds",
 684                                        c->msize, "9P2000.L");
 685                break;
 686        case p9_proto_2000u:
 687                req = p9_client_rpc(c, P9_TVERSION, "ds",
 688                                        c->msize, "9P2000.u");
 689                break;
 690        case p9_proto_legacy:
 691                req = p9_client_rpc(c, P9_TVERSION, "ds",
 692                                        c->msize, "9P2000");
 693                break;
 694        default:
 695                return -EINVAL;
 696                break;
 697        }
 698
 699        if (IS_ERR(req))
 700                return PTR_ERR(req);
 701
 702        err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version);
 703        if (err) {
 704                P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
 705                p9pdu_dump(1, req->rc);
 706                goto error;
 707        }
 708
 709        P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
 710        if (!strncmp(version, "9P2000.L", 8))
 711                c->proto_version = p9_proto_2000L;
 712        else if (!strncmp(version, "9P2000.u", 8))
 713                c->proto_version = p9_proto_2000u;
 714        else if (!strncmp(version, "9P2000", 6))
 715                c->proto_version = p9_proto_legacy;
 716        else {
 717                err = -EREMOTEIO;
 718                goto error;
 719        }
 720
 721        if (msize < c->msize)
 722                c->msize = msize;
 723
 724error:
 725        kfree(version);
 726        p9_free_req(c, req);
 727
 728        return err;
 729}
 730EXPORT_SYMBOL(p9_client_version);
 731
 732struct p9_client *p9_client_create(const char *dev_name, char *options)
 733{
 734        int err;
 735        struct p9_client *clnt;
 736
 737        err = 0;
 738        clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL);
 739        if (!clnt)
 740                return ERR_PTR(-ENOMEM);
 741
 742        clnt->trans_mod = NULL;
 743        clnt->trans = NULL;
 744        spin_lock_init(&clnt->lock);
 745        INIT_LIST_HEAD(&clnt->fidlist);
 746
 747        p9_tag_init(clnt);
 748
 749        err = parse_opts(options, clnt);
 750        if (err < 0)
 751                goto free_client;
 752
 753        if (!clnt->trans_mod)
 754                clnt->trans_mod = v9fs_get_default_trans();
 755
 756        if (clnt->trans_mod == NULL) {
 757                err = -EPROTONOSUPPORT;
 758                P9_DPRINTK(P9_DEBUG_ERROR,
 759                                "No transport defined or default transport\n");
 760                goto free_client;
 761        }
 762
 763        clnt->fidpool = p9_idpool_create();
 764        if (IS_ERR(clnt->fidpool)) {
 765                err = PTR_ERR(clnt->fidpool);
 766                clnt->fidpool = NULL;
 767                goto put_trans;
 768        }
 769
 770        P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n",
 771                clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
 772
 773        err = clnt->trans_mod->create(clnt, dev_name, options);
 774        if (err)
 775                goto destroy_fidpool;
 776
 777        if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize)
 778                clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ;
 779
 780        err = p9_client_version(clnt);
 781        if (err)
 782                goto close_trans;
 783
 784        return clnt;
 785
 786close_trans:
 787        clnt->trans_mod->close(clnt);
 788destroy_fidpool:
 789        p9_idpool_destroy(clnt->fidpool);
 790put_trans:
 791        v9fs_put_trans(clnt->trans_mod);
 792free_client:
 793        kfree(clnt);
 794        return ERR_PTR(err);
 795}
 796EXPORT_SYMBOL(p9_client_create);
 797
 798void p9_client_destroy(struct p9_client *clnt)
 799{
 800        struct p9_fid *fid, *fidptr;
 801
 802        P9_DPRINTK(P9_DEBUG_MUX, "clnt %p\n", clnt);
 803
 804        if (clnt->trans_mod)
 805                clnt->trans_mod->close(clnt);
 806
 807        v9fs_put_trans(clnt->trans_mod);
 808
 809        list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) {
 810                printk(KERN_INFO "Found fid %d not clunked\n", fid->fid);
 811                p9_fid_destroy(fid);
 812        }
 813
 814        if (clnt->fidpool)
 815                p9_idpool_destroy(clnt->fidpool);
 816
 817        p9_tag_cleanup(clnt);
 818
 819        kfree(clnt);
 820}
 821EXPORT_SYMBOL(p9_client_destroy);
 822
 823void p9_client_disconnect(struct p9_client *clnt)
 824{
 825        P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
 826        clnt->status = Disconnected;
 827}
 828EXPORT_SYMBOL(p9_client_disconnect);
 829
 830void p9_client_begin_disconnect(struct p9_client *clnt)
 831{
 832        P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
 833        clnt->status = BeginDisconnect;
 834}
 835EXPORT_SYMBOL(p9_client_begin_disconnect);
 836
 837struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
 838        char *uname, u32 n_uname, char *aname)
 839{
 840        int err;
 841        struct p9_req_t *req;
 842        struct p9_fid *fid;
 843        struct p9_qid qid;
 844
 845        P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n",
 846                                        afid ? afid->fid : -1, uname, aname);
 847        err = 0;
 848
 849        fid = p9_fid_create(clnt);
 850        if (IS_ERR(fid)) {
 851                err = PTR_ERR(fid);
 852                fid = NULL;
 853                goto error;
 854        }
 855
 856        req = p9_client_rpc(clnt, P9_TATTACH, "ddss?d", fid->fid,
 857                        afid ? afid->fid : P9_NOFID, uname, aname, n_uname);
 858        if (IS_ERR(req)) {
 859                err = PTR_ERR(req);
 860                goto error;
 861        }
 862
 863        err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
 864        if (err) {
 865                p9pdu_dump(1, req->rc);
 866                p9_free_req(clnt, req);
 867                goto error;
 868        }
 869
 870        P9_DPRINTK(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n",
 871                                        qid.type,
 872                                        (unsigned long long)qid.path,
 873                                        qid.version);
 874
 875        memmove(&fid->qid, &qid, sizeof(struct p9_qid));
 876
 877        p9_free_req(clnt, req);
 878        return fid;
 879
 880error:
 881        if (fid)
 882                p9_fid_destroy(fid);
 883        return ERR_PTR(err);
 884}
 885EXPORT_SYMBOL(p9_client_attach);
 886
 887struct p9_fid *
 888p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname)
 889{
 890        int err;
 891        struct p9_req_t *req;
 892        struct p9_qid qid;
 893        struct p9_fid *afid;
 894
 895        P9_DPRINTK(P9_DEBUG_9P, ">>> TAUTH uname %s aname %s\n", uname, aname);
 896        err = 0;
 897
 898        afid = p9_fid_create(clnt);
 899        if (IS_ERR(afid)) {
 900                err = PTR_ERR(afid);
 901                afid = NULL;
 902                goto error;
 903        }
 904
 905        req = p9_client_rpc(clnt, P9_TAUTH, "dss?d",
 906                        afid ? afid->fid : P9_NOFID, uname, aname, n_uname);
 907        if (IS_ERR(req)) {
 908                err = PTR_ERR(req);
 909                goto error;
 910        }
 911
 912        err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
 913        if (err) {
 914                p9pdu_dump(1, req->rc);
 915                p9_free_req(clnt, req);
 916                goto error;
 917        }
 918
 919        P9_DPRINTK(P9_DEBUG_9P, "<<< RAUTH qid %x.%llx.%x\n",
 920                                        qid.type,
 921                                        (unsigned long long)qid.path,
 922                                        qid.version);
 923
 924        memmove(&afid->qid, &qid, sizeof(struct p9_qid));
 925        p9_free_req(clnt, req);
 926        return afid;
 927
 928error:
 929        if (afid)
 930                p9_fid_destroy(afid);
 931        return ERR_PTR(err);
 932}
 933EXPORT_SYMBOL(p9_client_auth);
 934
 935struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
 936        int clone)
 937{
 938        int err;
 939        struct p9_client *clnt;
 940        struct p9_fid *fid;
 941        struct p9_qid *wqids;
 942        struct p9_req_t *req;
 943        int16_t nwqids, count;
 944
 945        err = 0;
 946        clnt = oldfid->clnt;
 947        if (clone) {
 948                fid = p9_fid_create(clnt);
 949                if (IS_ERR(fid)) {
 950                        err = PTR_ERR(fid);
 951                        fid = NULL;
 952                        goto error;
 953                }
 954
 955                fid->uid = oldfid->uid;
 956        } else
 957                fid = oldfid;
 958
 959
 960        P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n",
 961                oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL);
 962
 963        req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid,
 964                                                                nwname, wnames);
 965        if (IS_ERR(req)) {
 966                err = PTR_ERR(req);
 967                goto error;
 968        }
 969
 970        err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids);
 971        if (err) {
 972                p9pdu_dump(1, req->rc);
 973                p9_free_req(clnt, req);
 974                goto clunk_fid;
 975        }
 976        p9_free_req(clnt, req);
 977
 978        P9_DPRINTK(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids);
 979
 980        if (nwqids != nwname) {
 981                err = -ENOENT;
 982                goto clunk_fid;
 983        }
 984
 985        for (count = 0; count < nwqids; count++)
 986                P9_DPRINTK(P9_DEBUG_9P, "<<<     [%d] %x.%llx.%x\n",
 987                        count, wqids[count].type,
 988                        (unsigned long long)wqids[count].path,
 989                        wqids[count].version);
 990
 991        if (nwname)
 992                memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid));
 993        else
 994                fid->qid = oldfid->qid;
 995
 996        return fid;
 997
 998clunk_fid:
 999        p9_client_clunk(fid);
1000        fid = NULL;
1001
1002error:
1003        if (fid && (fid != oldfid))
1004                p9_fid_destroy(fid);
1005
1006        return ERR_PTR(err);
1007}
1008EXPORT_SYMBOL(p9_client_walk);
1009
1010int p9_client_open(struct p9_fid *fid, int mode)
1011{
1012        int err;
1013        struct p9_client *clnt;
1014        struct p9_req_t *req;
1015        struct p9_qid qid;
1016        int iounit;
1017
1018        P9_DPRINTK(P9_DEBUG_9P, ">>> TOPEN fid %d mode %d\n", fid->fid, mode);
1019        err = 0;
1020        clnt = fid->clnt;
1021
1022        if (fid->mode != -1)
1023                return -EINVAL;
1024
1025        req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode);
1026        if (IS_ERR(req)) {
1027                err = PTR_ERR(req);
1028                goto error;
1029        }
1030
1031        err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
1032        if (err) {
1033                p9pdu_dump(1, req->rc);
1034                goto free_and_error;
1035        }
1036
1037        P9_DPRINTK(P9_DEBUG_9P, "<<< ROPEN qid %x.%llx.%x iounit %x\n",
1038                                qid.type,
1039                                (unsigned long long)qid.path,
1040                                qid.version, iounit);
1041
1042        fid->mode = mode;
1043        fid->iounit = iounit;
1044
1045free_and_error:
1046        p9_free_req(clnt, req);
1047error:
1048        return err;
1049}
1050EXPORT_SYMBOL(p9_client_open);
1051
1052int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
1053                     char *extension)
1054{
1055        int err;
1056        struct p9_client *clnt;
1057        struct p9_req_t *req;
1058        struct p9_qid qid;
1059        int iounit;
1060
1061        P9_DPRINTK(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n",
1062                                                fid->fid, name, perm, mode);
1063        err = 0;
1064        clnt = fid->clnt;
1065
1066        if (fid->mode != -1)
1067                return -EINVAL;
1068
1069        req = p9_client_rpc(clnt, P9_TCREATE, "dsdb?s", fid->fid, name, perm,
1070                                mode, extension);
1071        if (IS_ERR(req)) {
1072                err = PTR_ERR(req);
1073                goto error;
1074        }
1075
1076        err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
1077        if (err) {
1078                p9pdu_dump(1, req->rc);
1079                goto free_and_error;
1080        }
1081
1082        P9_DPRINTK(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n",
1083                                qid.type,
1084                                (unsigned long long)qid.path,
1085                                qid.version, iounit);
1086
1087        fid->mode = mode;
1088        fid->iounit = iounit;
1089
1090free_and_error:
1091        p9_free_req(clnt, req);
1092error:
1093        return err;
1094}
1095EXPORT_SYMBOL(p9_client_fcreate);
1096
1097int p9_client_clunk(struct p9_fid *fid)
1098{
1099        int err;
1100        struct p9_client *clnt;
1101        struct p9_req_t *req;
1102
1103        P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid);
1104        err = 0;
1105        clnt = fid->clnt;
1106
1107        req = p9_client_rpc(clnt, P9_TCLUNK, "d", fid->fid);
1108        if (IS_ERR(req)) {
1109                err = PTR_ERR(req);
1110                goto error;
1111        }
1112
1113        P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid);
1114
1115        p9_free_req(clnt, req);
1116        p9_fid_destroy(fid);
1117
1118error:
1119        return err;
1120}
1121EXPORT_SYMBOL(p9_client_clunk);
1122
1123int p9_client_remove(struct p9_fid *fid)
1124{
1125        int err;
1126        struct p9_client *clnt;
1127        struct p9_req_t *req;
1128
1129        P9_DPRINTK(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid);
1130        err = 0;
1131        clnt = fid->clnt;
1132
1133        req = p9_client_rpc(clnt, P9_TREMOVE, "d", fid->fid);
1134        if (IS_ERR(req)) {
1135                err = PTR_ERR(req);
1136                goto error;
1137        }
1138
1139        P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid);
1140
1141        p9_free_req(clnt, req);
1142        p9_fid_destroy(fid);
1143
1144error:
1145        return err;
1146}
1147EXPORT_SYMBOL(p9_client_remove);
1148
1149int
1150p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
1151                                                                u32 count)
1152{
1153        int err, rsize, total;
1154        struct p9_client *clnt;
1155        struct p9_req_t *req;
1156        char *dataptr;
1157
1158        P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", fid->fid,
1159                                        (long long unsigned) offset, count);
1160        err = 0;
1161        clnt = fid->clnt;
1162        total = 0;
1163
1164        rsize = fid->iounit;
1165        if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
1166                rsize = clnt->msize - P9_IOHDRSZ;
1167
1168        if (count < rsize)
1169                rsize = count;
1170
1171        req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize);
1172        if (IS_ERR(req)) {
1173                err = PTR_ERR(req);
1174                goto error;
1175        }
1176
1177        err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
1178        if (err) {
1179                p9pdu_dump(1, req->rc);
1180                goto free_and_error;
1181        }
1182
1183        P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
1184
1185        if (data) {
1186                memmove(data, dataptr, count);
1187        }
1188
1189        if (udata) {
1190                err = copy_to_user(udata, dataptr, count);
1191                if (err) {
1192                        err = -EFAULT;
1193                        goto free_and_error;
1194                }
1195        }
1196
1197        p9_free_req(clnt, req);
1198        return count;
1199
1200free_and_error:
1201        p9_free_req(clnt, req);
1202error:
1203        return err;
1204}
1205EXPORT_SYMBOL(p9_client_read);
1206
1207int
1208p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
1209                                                        u64 offset, u32 count)
1210{
1211        int err, rsize, total;
1212        struct p9_client *clnt;
1213        struct p9_req_t *req;
1214
1215        P9_DPRINTK(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n",
1216                                fid->fid, (long long unsigned) offset, count);
1217        err = 0;
1218        clnt = fid->clnt;
1219        total = 0;
1220
1221        rsize = fid->iounit;
1222        if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
1223                rsize = clnt->msize - P9_IOHDRSZ;
1224
1225        if (count < rsize)
1226                rsize = count;
1227        if (data)
1228                req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset,
1229                                                                rsize, data);
1230        else
1231                req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset,
1232                                                                rsize, udata);
1233        if (IS_ERR(req)) {
1234                err = PTR_ERR(req);
1235                goto error;
1236        }
1237
1238        err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count);
1239        if (err) {
1240                p9pdu_dump(1, req->rc);
1241                goto free_and_error;
1242        }
1243
1244        P9_DPRINTK(P9_DEBUG_9P, "<<< RWRITE count %d\n", count);
1245
1246        p9_free_req(clnt, req);
1247        return count;
1248
1249free_and_error:
1250        p9_free_req(clnt, req);
1251error:
1252        return err;
1253}
1254EXPORT_SYMBOL(p9_client_write);
1255
1256struct p9_wstat *p9_client_stat(struct p9_fid *fid)
1257{
1258        int err;
1259        struct p9_client *clnt;
1260        struct p9_wstat *ret = kmalloc(sizeof(struct p9_wstat), GFP_KERNEL);
1261        struct p9_req_t *req;
1262        u16 ignored;
1263
1264        P9_DPRINTK(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid);
1265
1266        if (!ret)
1267                return ERR_PTR(-ENOMEM);
1268
1269        err = 0;
1270        clnt = fid->clnt;
1271
1272        req = p9_client_rpc(clnt, P9_TSTAT, "d", fid->fid);
1273        if (IS_ERR(req)) {
1274                err = PTR_ERR(req);
1275                goto error;
1276        }
1277
1278        err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret);
1279        if (err) {
1280                p9pdu_dump(1, req->rc);
1281                p9_free_req(clnt, req);
1282                goto error;
1283        }
1284
1285        P9_DPRINTK(P9_DEBUG_9P,
1286                "<<< RSTAT sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
1287                "<<<    mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n"
1288                "<<<    name=%s uid=%s gid=%s muid=%s extension=(%s)\n"
1289                "<<<    uid=%d gid=%d n_muid=%d\n",
1290                ret->size, ret->type, ret->dev, ret->qid.type,
1291                (unsigned long long)ret->qid.path, ret->qid.version, ret->mode,
1292                ret->atime, ret->mtime, (unsigned long long)ret->length,
1293                ret->name, ret->uid, ret->gid, ret->muid, ret->extension,
1294                ret->n_uid, ret->n_gid, ret->n_muid);
1295
1296        p9_free_req(clnt, req);
1297        return ret;
1298
1299error:
1300        kfree(ret);
1301        return ERR_PTR(err);
1302}
1303EXPORT_SYMBOL(p9_client_stat);
1304
1305static int p9_client_statsize(struct p9_wstat *wst, int proto_version)
1306{
1307        int ret;
1308
1309        /* NOTE: size shouldn't include its own length */
1310        /* size[2] type[2] dev[4] qid[13] */
1311        /* mode[4] atime[4] mtime[4] length[8]*/
1312        /* name[s] uid[s] gid[s] muid[s] */
1313        ret = 2+4+13+4+4+4+8+2+2+2+2;
1314
1315        if (wst->name)
1316                ret += strlen(wst->name);
1317        if (wst->uid)
1318                ret += strlen(wst->uid);
1319        if (wst->gid)
1320                ret += strlen(wst->gid);
1321        if (wst->muid)
1322                ret += strlen(wst->muid);
1323
1324        if ((proto_version == p9_proto_2000u) ||
1325                (proto_version == p9_proto_2000L)) {
1326                ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */
1327                if (wst->extension)
1328                        ret += strlen(wst->extension);
1329        }
1330
1331        return ret;
1332}
1333
1334int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
1335{
1336        int err;
1337        struct p9_req_t *req;
1338        struct p9_client *clnt;
1339
1340        err = 0;
1341        clnt = fid->clnt;
1342        wst->size = p9_client_statsize(wst, clnt->proto_version);
1343        P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid);
1344        P9_DPRINTK(P9_DEBUG_9P,
1345                "     sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
1346                "     mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n"
1347                "     name=%s uid=%s gid=%s muid=%s extension=(%s)\n"
1348                "     uid=%d gid=%d n_muid=%d\n",
1349                wst->size, wst->type, wst->dev, wst->qid.type,
1350                (unsigned long long)wst->qid.path, wst->qid.version, wst->mode,
1351                wst->atime, wst->mtime, (unsigned long long)wst->length,
1352                wst->name, wst->uid, wst->gid, wst->muid, wst->extension,
1353                wst->n_uid, wst->n_gid, wst->n_muid);
1354
1355        req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, wst->size+2, wst);
1356        if (IS_ERR(req)) {
1357                err = PTR_ERR(req);
1358                goto error;
1359        }
1360
1361        P9_DPRINTK(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid);
1362
1363        p9_free_req(clnt, req);
1364error:
1365        return err;
1366}
1367EXPORT_SYMBOL(p9_client_wstat);
1368
1369int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
1370{
1371        int err;
1372        struct p9_req_t *req;
1373        struct p9_client *clnt;
1374
1375        err = 0;
1376        clnt = fid->clnt;
1377
1378        P9_DPRINTK(P9_DEBUG_9P, ">>> TSTATFS fid %d\n", fid->fid);
1379
1380        req = p9_client_rpc(clnt, P9_TSTATFS, "d", fid->fid);
1381        if (IS_ERR(req)) {
1382                err = PTR_ERR(req);
1383                goto error;
1384        }
1385
1386        err = p9pdu_readf(req->rc, clnt->proto_version, "ddqqqqqqd", &sb->type,
1387                &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail,
1388                &sb->files, &sb->ffree, &sb->fsid, &sb->namelen);
1389        if (err) {
1390                p9pdu_dump(1, req->rc);
1391                p9_free_req(clnt, req);
1392                goto error;
1393        }
1394
1395        P9_DPRINTK(P9_DEBUG_9P, "<<< RSTATFS fid %d type 0x%lx bsize %ld "
1396                "blocks %llu bfree %llu bavail %llu files %llu ffree %llu "
1397                "fsid %llu namelen %ld\n",
1398                fid->fid, (long unsigned int)sb->type, (long int)sb->bsize,
1399                sb->blocks, sb->bfree, sb->bavail, sb->files,  sb->ffree,
1400                sb->fsid, (long int)sb->namelen);
1401
1402        p9_free_req(clnt, req);
1403error:
1404        return err;
1405}
1406EXPORT_SYMBOL(p9_client_statfs);
1407
1408int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name)
1409{
1410        int err;
1411        struct p9_req_t *req;
1412        struct p9_client *clnt;
1413
1414        err = 0;
1415        clnt = fid->clnt;
1416
1417        P9_DPRINTK(P9_DEBUG_9P, ">>> TRENAME fid %d newdirfid %d name %s\n",
1418                        fid->fid, newdirfid->fid, name);
1419
1420        req = p9_client_rpc(clnt, P9_TRENAME, "dds", fid->fid,
1421                        newdirfid->fid, name);
1422        if (IS_ERR(req)) {
1423                err = PTR_ERR(req);
1424                goto error;
1425        }
1426
1427        P9_DPRINTK(P9_DEBUG_9P, "<<< RRENAME fid %d\n", fid->fid);
1428
1429        p9_free_req(clnt, req);
1430error:
1431        return err;
1432}
1433EXPORT_SYMBOL(p9_client_rename);
1434
1435