linux/net/9p/conv.c
<<
>>
Prefs
   1/*
   2 * net/9p/conv.c
   3 *
   4 * 9P protocol conversion functions
   5 *
   6 *  Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net>
   7 *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
   8 *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
   9 *
  10 *  This program is free software; you can redistribute it and/or modify
  11 *  it under the terms of the GNU General Public License version 2
  12 *  as published by the Free Software Foundation.
  13 *
  14 *  This program is distributed in the hope that it will be useful,
  15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 *  GNU General Public License for more details.
  18 *
  19 *  You should have received a copy of the GNU General Public License
  20 *  along with this program; if not, write to:
  21 *  Free Software Foundation
  22 *  51 Franklin Street, Fifth Floor
  23 *  Boston, MA  02111-1301  USA
  24 *
  25 */
  26
  27#include <linux/module.h>
  28#include <linux/errno.h>
  29#include <linux/fs.h>
  30#include <linux/sched.h>
  31#include <linux/idr.h>
  32#include <linux/uaccess.h>
  33#include <net/9p/9p.h>
  34
  35/*
  36 * Buffer to help with string parsing
  37 */
  38struct cbuf {
  39        unsigned char *sp;
  40        unsigned char *p;
  41        unsigned char *ep;
  42};
  43
  44static inline void buf_init(struct cbuf *buf, void *data, int datalen)
  45{
  46        buf->sp = buf->p = data;
  47        buf->ep = data + datalen;
  48}
  49
  50static inline int buf_check_overflow(struct cbuf *buf)
  51{
  52        return buf->p > buf->ep;
  53}
  54
  55static int buf_check_size(struct cbuf *buf, int len)
  56{
  57        if (buf->p + len > buf->ep) {
  58                if (buf->p < buf->ep) {
  59                        P9_EPRINTK(KERN_ERR,
  60                                "buffer overflow: want %d has %d\n", len,
  61                                (int)(buf->ep - buf->p));
  62                        dump_stack();
  63                        buf->p = buf->ep + 1;
  64                }
  65
  66                return 0;
  67        }
  68
  69        return 1;
  70}
  71
  72static void *buf_alloc(struct cbuf *buf, int len)
  73{
  74        void *ret = NULL;
  75
  76        if (buf_check_size(buf, len)) {
  77                ret = buf->p;
  78                buf->p += len;
  79        }
  80
  81        return ret;
  82}
  83
  84static void buf_put_int8(struct cbuf *buf, u8 val)
  85{
  86        if (buf_check_size(buf, 1)) {
  87                buf->p[0] = val;
  88                buf->p++;
  89        }
  90}
  91
  92static void buf_put_int16(struct cbuf *buf, u16 val)
  93{
  94        if (buf_check_size(buf, 2)) {
  95                *(__le16 *) buf->p = cpu_to_le16(val);
  96                buf->p += 2;
  97        }
  98}
  99
 100static void buf_put_int32(struct cbuf *buf, u32 val)
 101{
 102        if (buf_check_size(buf, 4)) {
 103                *(__le32 *)buf->p = cpu_to_le32(val);
 104                buf->p += 4;
 105        }
 106}
 107
 108static void buf_put_int64(struct cbuf *buf, u64 val)
 109{
 110        if (buf_check_size(buf, 8)) {
 111                *(__le64 *)buf->p = cpu_to_le64(val);
 112                buf->p += 8;
 113        }
 114}
 115
 116static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
 117{
 118        char *ret;
 119
 120        ret = NULL;
 121        if (buf_check_size(buf, slen + 2)) {
 122                buf_put_int16(buf, slen);
 123                ret = buf->p;
 124                memcpy(buf->p, s, slen);
 125                buf->p += slen;
 126        }
 127
 128        return ret;
 129}
 130
 131static u8 buf_get_int8(struct cbuf *buf)
 132{
 133        u8 ret = 0;
 134
 135        if (buf_check_size(buf, 1)) {
 136                ret = buf->p[0];
 137                buf->p++;
 138        }
 139
 140        return ret;
 141}
 142
 143static u16 buf_get_int16(struct cbuf *buf)
 144{
 145        u16 ret = 0;
 146
 147        if (buf_check_size(buf, 2)) {
 148                ret = le16_to_cpu(*(__le16 *)buf->p);
 149                buf->p += 2;
 150        }
 151
 152        return ret;
 153}
 154
 155static u32 buf_get_int32(struct cbuf *buf)
 156{
 157        u32 ret = 0;
 158
 159        if (buf_check_size(buf, 4)) {
 160                ret = le32_to_cpu(*(__le32 *)buf->p);
 161                buf->p += 4;
 162        }
 163
 164        return ret;
 165}
 166
 167static u64 buf_get_int64(struct cbuf *buf)
 168{
 169        u64 ret = 0;
 170
 171        if (buf_check_size(buf, 8)) {
 172                ret = le64_to_cpu(*(__le64 *)buf->p);
 173                buf->p += 8;
 174        }
 175
 176        return ret;
 177}
 178
 179static void buf_get_str(struct cbuf *buf, struct p9_str *vstr)
 180{
 181        vstr->len = buf_get_int16(buf);
 182        if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
 183                vstr->str = buf->p;
 184                buf->p += vstr->len;
 185        } else {
 186                vstr->len = 0;
 187                vstr->str = NULL;
 188        }
 189}
 190
 191static void buf_get_qid(struct cbuf *bufp, struct p9_qid *qid)
 192{
 193        qid->type = buf_get_int8(bufp);
 194        qid->version = buf_get_int32(bufp);
 195        qid->path = buf_get_int64(bufp);
 196}
 197
 198/**
 199 * p9_size_wstat - calculate the size of a variable length stat struct
 200 * @wstat: metadata (stat) structure
 201 * @dotu: non-zero if 9P2000.u
 202 *
 203 */
 204
 205static int p9_size_wstat(struct p9_wstat *wstat, int dotu)
 206{
 207        int size = 0;
 208
 209        if (wstat == NULL) {
 210                P9_EPRINTK(KERN_ERR, "p9_size_stat: got a NULL stat pointer\n");
 211                return 0;
 212        }
 213
 214        size =                  /* 2 + *//* size[2] */
 215            2 +                 /* type[2] */
 216            4 +                 /* dev[4] */
 217            1 +                 /* qid.type[1] */
 218            4 +                 /* qid.vers[4] */
 219            8 +                 /* qid.path[8] */
 220            4 +                 /* mode[4] */
 221            4 +                 /* atime[4] */
 222            4 +                 /* mtime[4] */
 223            8 +                 /* length[8] */
 224            8;                  /* minimum sum of string lengths */
 225
 226        if (wstat->name)
 227                size += strlen(wstat->name);
 228        if (wstat->uid)
 229                size += strlen(wstat->uid);
 230        if (wstat->gid)
 231                size += strlen(wstat->gid);
 232        if (wstat->muid)
 233                size += strlen(wstat->muid);
 234
 235        if (dotu) {
 236                size += 4 +     /* n_uid[4] */
 237                    4 +         /* n_gid[4] */
 238                    4 +         /* n_muid[4] */
 239                    2;          /* string length of extension[4] */
 240                if (wstat->extension)
 241                        size += strlen(wstat->extension);
 242        }
 243
 244        return size;
 245}
 246
 247/**
 248 * buf_get_stat - safely decode a recieved metadata (stat) structure
 249 * @bufp: buffer to deserialize
 250 * @stat: metadata (stat) structure
 251 * @dotu: non-zero if 9P2000.u
 252 *
 253 */
 254
 255static void
 256buf_get_stat(struct cbuf *bufp, struct p9_stat *stat, int dotu)
 257{
 258        stat->size = buf_get_int16(bufp);
 259        stat->type = buf_get_int16(bufp);
 260        stat->dev = buf_get_int32(bufp);
 261        stat->qid.type = buf_get_int8(bufp);
 262        stat->qid.version = buf_get_int32(bufp);
 263        stat->qid.path = buf_get_int64(bufp);
 264        stat->mode = buf_get_int32(bufp);
 265        stat->atime = buf_get_int32(bufp);
 266        stat->mtime = buf_get_int32(bufp);
 267        stat->length = buf_get_int64(bufp);
 268        buf_get_str(bufp, &stat->name);
 269        buf_get_str(bufp, &stat->uid);
 270        buf_get_str(bufp, &stat->gid);
 271        buf_get_str(bufp, &stat->muid);
 272
 273        if (dotu) {
 274                buf_get_str(bufp, &stat->extension);
 275                stat->n_uid = buf_get_int32(bufp);
 276                stat->n_gid = buf_get_int32(bufp);
 277                stat->n_muid = buf_get_int32(bufp);
 278        }
 279}
 280
 281/**
 282 * p9_deserialize_stat - decode a received metadata structure
 283 * @buf: buffer to deserialize
 284 * @buflen: length of received buffer
 285 * @stat: metadata structure to decode into
 286 * @dotu: non-zero if 9P2000.u
 287 *
 288 * Note: stat will point to the buf region.
 289 */
 290
 291int
 292p9_deserialize_stat(void *buf, u32 buflen, struct p9_stat *stat,
 293                int dotu)
 294{
 295        struct cbuf buffer;
 296        struct cbuf *bufp = &buffer;
 297        unsigned char *p;
 298
 299        buf_init(bufp, buf, buflen);
 300        p = bufp->p;
 301        buf_get_stat(bufp, stat, dotu);
 302
 303        if (buf_check_overflow(bufp))
 304                return 0;
 305        else
 306                return bufp->p - p;
 307}
 308EXPORT_SYMBOL(p9_deserialize_stat);
 309
 310/**
 311 * deserialize_fcall - unmarshal a response
 312 * @buf: recieved buffer
 313 * @buflen: length of received buffer
 314 * @rcall: fcall structure to populate
 315 * @rcalllen: length of fcall structure to populate
 316 * @dotu: non-zero if 9P2000.u
 317 *
 318 */
 319
 320int
 321p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *rcall,
 322                       int dotu)
 323{
 324
 325        struct cbuf buffer;
 326        struct cbuf *bufp = &buffer;
 327        int i = 0;
 328
 329        buf_init(bufp, buf, buflen);
 330
 331        rcall->size = buf_get_int32(bufp);
 332        rcall->id = buf_get_int8(bufp);
 333        rcall->tag = buf_get_int16(bufp);
 334
 335        P9_DPRINTK(P9_DEBUG_CONV, "size %d id %d tag %d\n", rcall->size,
 336                                                        rcall->id, rcall->tag);
 337
 338        switch (rcall->id) {
 339        default:
 340                P9_EPRINTK(KERN_ERR, "unknown message type: %d\n", rcall->id);
 341                return -EPROTO;
 342        case P9_RVERSION:
 343                rcall->params.rversion.msize = buf_get_int32(bufp);
 344                buf_get_str(bufp, &rcall->params.rversion.version);
 345                break;
 346        case P9_RFLUSH:
 347                break;
 348        case P9_RATTACH:
 349                rcall->params.rattach.qid.type = buf_get_int8(bufp);
 350                rcall->params.rattach.qid.version = buf_get_int32(bufp);
 351                rcall->params.rattach.qid.path = buf_get_int64(bufp);
 352                break;
 353        case P9_RWALK:
 354                rcall->params.rwalk.nwqid = buf_get_int16(bufp);
 355                if (rcall->params.rwalk.nwqid > P9_MAXWELEM) {
 356                        P9_EPRINTK(KERN_ERR,
 357                                        "Rwalk with more than %d qids: %d\n",
 358                                        P9_MAXWELEM, rcall->params.rwalk.nwqid);
 359                        return -EPROTO;
 360                }
 361
 362                for (i = 0; i < rcall->params.rwalk.nwqid; i++)
 363                        buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
 364                break;
 365        case P9_ROPEN:
 366                buf_get_qid(bufp, &rcall->params.ropen.qid);
 367                rcall->params.ropen.iounit = buf_get_int32(bufp);
 368                break;
 369        case P9_RCREATE:
 370                buf_get_qid(bufp, &rcall->params.rcreate.qid);
 371                rcall->params.rcreate.iounit = buf_get_int32(bufp);
 372                break;
 373        case P9_RREAD:
 374                rcall->params.rread.count = buf_get_int32(bufp);
 375                rcall->params.rread.data = bufp->p;
 376                buf_check_size(bufp, rcall->params.rread.count);
 377                break;
 378        case P9_RWRITE:
 379                rcall->params.rwrite.count = buf_get_int32(bufp);
 380                break;
 381        case P9_RCLUNK:
 382                break;
 383        case P9_RREMOVE:
 384                break;
 385        case P9_RSTAT:
 386                buf_get_int16(bufp);
 387                buf_get_stat(bufp, &rcall->params.rstat.stat, dotu);
 388                break;
 389        case P9_RWSTAT:
 390                break;
 391        case P9_RERROR:
 392                buf_get_str(bufp, &rcall->params.rerror.error);
 393                if (dotu)
 394                        rcall->params.rerror.errno = buf_get_int16(bufp);
 395                break;
 396        }
 397
 398        if (buf_check_overflow(bufp)) {
 399                P9_DPRINTK(P9_DEBUG_ERROR, "buffer overflow\n");
 400                return -EIO;
 401        }
 402
 403        return bufp->p - bufp->sp;
 404}
 405EXPORT_SYMBOL(p9_deserialize_fcall);
 406
 407static inline void p9_put_int8(struct cbuf *bufp, u8 val, u8 * p)
 408{
 409        *p = val;
 410        buf_put_int8(bufp, val);
 411}
 412
 413static inline void p9_put_int16(struct cbuf *bufp, u16 val, u16 * p)
 414{
 415        *p = val;
 416        buf_put_int16(bufp, val);
 417}
 418
 419static inline void p9_put_int32(struct cbuf *bufp, u32 val, u32 * p)
 420{
 421        *p = val;
 422        buf_put_int32(bufp, val);
 423}
 424
 425static inline void p9_put_int64(struct cbuf *bufp, u64 val, u64 * p)
 426{
 427        *p = val;
 428        buf_put_int64(bufp, val);
 429}
 430
 431static void
 432p9_put_str(struct cbuf *bufp, char *data, struct p9_str *str)
 433{
 434        int len;
 435        char *s;
 436
 437        if (data)
 438                len = strlen(data);
 439        else
 440                len = 0;
 441
 442        s = buf_put_stringn(bufp, data, len);
 443        if (str) {
 444                str->len = len;
 445                str->str = s;
 446        }
 447}
 448
 449static int
 450p9_put_data(struct cbuf *bufp, const char *data, int count,
 451                   unsigned char **pdata)
 452{
 453        *pdata = buf_alloc(bufp, count);
 454        if (*pdata == NULL)
 455                return -ENOMEM;
 456        memmove(*pdata, data, count);
 457        return 0;
 458}
 459
 460static int
 461p9_put_user_data(struct cbuf *bufp, const char __user *data, int count,
 462                   unsigned char **pdata)
 463{
 464        *pdata = buf_alloc(bufp, count);
 465        if (*pdata == NULL)
 466                return -ENOMEM;
 467        return copy_from_user(*pdata, data, count);
 468}
 469
 470static void
 471p9_put_wstat(struct cbuf *bufp, struct p9_wstat *wstat,
 472               struct p9_stat *stat, int statsz, int dotu)
 473{
 474        p9_put_int16(bufp, statsz, &stat->size);
 475        p9_put_int16(bufp, wstat->type, &stat->type);
 476        p9_put_int32(bufp, wstat->dev, &stat->dev);
 477        p9_put_int8(bufp, wstat->qid.type, &stat->qid.type);
 478        p9_put_int32(bufp, wstat->qid.version, &stat->qid.version);
 479        p9_put_int64(bufp, wstat->qid.path, &stat->qid.path);
 480        p9_put_int32(bufp, wstat->mode, &stat->mode);
 481        p9_put_int32(bufp, wstat->atime, &stat->atime);
 482        p9_put_int32(bufp, wstat->mtime, &stat->mtime);
 483        p9_put_int64(bufp, wstat->length, &stat->length);
 484
 485        p9_put_str(bufp, wstat->name, &stat->name);
 486        p9_put_str(bufp, wstat->uid, &stat->uid);
 487        p9_put_str(bufp, wstat->gid, &stat->gid);
 488        p9_put_str(bufp, wstat->muid, &stat->muid);
 489
 490        if (dotu) {
 491                p9_put_str(bufp, wstat->extension, &stat->extension);
 492                p9_put_int32(bufp, wstat->n_uid, &stat->n_uid);
 493                p9_put_int32(bufp, wstat->n_gid, &stat->n_gid);
 494                p9_put_int32(bufp, wstat->n_muid, &stat->n_muid);
 495        }
 496}
 497
 498static struct p9_fcall *
 499p9_create_common(struct cbuf *bufp, u32 size, u8 id)
 500{
 501        struct p9_fcall *fc;
 502
 503        size += 4 + 1 + 2;      /* size[4] id[1] tag[2] */
 504        fc = kmalloc(sizeof(struct p9_fcall) + size, GFP_KERNEL);
 505        if (!fc)
 506                return ERR_PTR(-ENOMEM);
 507
 508        fc->sdata = (char *)fc + sizeof(*fc);
 509
 510        buf_init(bufp, (char *)fc->sdata, size);
 511        p9_put_int32(bufp, size, &fc->size);
 512        p9_put_int8(bufp, id, &fc->id);
 513        p9_put_int16(bufp, P9_NOTAG, &fc->tag);
 514
 515        return fc;
 516}
 517
 518/**
 519 * p9_set_tag - set the tag field of an &p9_fcall structure
 520 * @fc: fcall structure to set tag within
 521 * @tag: tag id to set
 522 */
 523
 524void p9_set_tag(struct p9_fcall *fc, u16 tag)
 525{
 526        fc->tag = tag;
 527        *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
 528}
 529EXPORT_SYMBOL(p9_set_tag);
 530
 531/**
 532 * p9_create_tversion - allocates and creates a T_VERSION request
 533 * @msize: requested maximum data size
 534 * @version: version string to negotiate
 535 *
 536 */
 537struct p9_fcall *p9_create_tversion(u32 msize, char *version)
 538{
 539        int size;
 540        struct p9_fcall *fc;
 541        struct cbuf buffer;
 542        struct cbuf *bufp = &buffer;
 543
 544        size = 4 + 2 + strlen(version); /* msize[4] version[s] */
 545        fc = p9_create_common(bufp, size, P9_TVERSION);
 546        if (IS_ERR(fc))
 547                goto error;
 548
 549        p9_put_int32(bufp, msize, &fc->params.tversion.msize);
 550        p9_put_str(bufp, version, &fc->params.tversion.version);
 551
 552        if (buf_check_overflow(bufp)) {
 553                kfree(fc);
 554                fc = ERR_PTR(-ENOMEM);
 555        }
 556error:
 557        return fc;
 558}
 559EXPORT_SYMBOL(p9_create_tversion);
 560
 561/**
 562 * p9_create_tauth - allocates and creates a T_AUTH request
 563 * @afid: handle to use for authentication protocol
 564 * @uname: user name attempting to authenticate
 565 * @aname: mount specifier for remote server
 566 * @n_uname: numeric id for user attempting to authneticate
 567 * @dotu: 9P2000.u extension flag
 568 *
 569 */
 570
 571struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname,
 572        u32 n_uname, int dotu)
 573{
 574        int size;
 575        struct p9_fcall *fc;
 576        struct cbuf buffer;
 577        struct cbuf *bufp = &buffer;
 578
 579        /* afid[4] uname[s] aname[s] */
 580        size = 4 + 2 + 2;
 581        if (uname)
 582                size += strlen(uname);
 583
 584        if (aname)
 585                size += strlen(aname);
 586
 587        if (dotu)
 588                size += 4;      /* n_uname */
 589
 590        fc = p9_create_common(bufp, size, P9_TAUTH);
 591        if (IS_ERR(fc))
 592                goto error;
 593
 594        p9_put_int32(bufp, afid, &fc->params.tauth.afid);
 595        p9_put_str(bufp, uname, &fc->params.tauth.uname);
 596        p9_put_str(bufp, aname, &fc->params.tauth.aname);
 597        if (dotu)
 598                p9_put_int32(bufp, n_uname, &fc->params.tauth.n_uname);
 599
 600        if (buf_check_overflow(bufp)) {
 601                kfree(fc);
 602                fc = ERR_PTR(-ENOMEM);
 603        }
 604error:
 605        return fc;
 606}
 607EXPORT_SYMBOL(p9_create_tauth);
 608
 609/**
 610 * p9_create_tattach - allocates and creates a T_ATTACH request
 611 * @fid: handle to use for the new mount point
 612 * @afid: handle to use for authentication protocol
 613 * @uname: user name attempting to attach
 614 * @aname: mount specifier for remote server
 615 * @n_uname: numeric id for user attempting to attach
 616 * @n_uname: numeric id for user attempting to attach
 617 * @dotu: 9P2000.u extension flag
 618 *
 619 */
 620
 621struct p9_fcall *
 622p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname,
 623        u32 n_uname, int dotu)
 624{
 625        int size;
 626        struct p9_fcall *fc;
 627        struct cbuf buffer;
 628        struct cbuf *bufp = &buffer;
 629
 630        /* fid[4] afid[4] uname[s] aname[s] */
 631        size = 4 + 4 + 2 + 2;
 632        if (uname)
 633                size += strlen(uname);
 634
 635        if (aname)
 636                size += strlen(aname);
 637
 638        if (dotu)
 639                size += 4;      /* n_uname */
 640
 641        fc = p9_create_common(bufp, size, P9_TATTACH);
 642        if (IS_ERR(fc))
 643                goto error;
 644
 645        p9_put_int32(bufp, fid, &fc->params.tattach.fid);
 646        p9_put_int32(bufp, afid, &fc->params.tattach.afid);
 647        p9_put_str(bufp, uname, &fc->params.tattach.uname);
 648        p9_put_str(bufp, aname, &fc->params.tattach.aname);
 649        if (dotu)
 650                p9_put_int32(bufp, n_uname, &fc->params.tattach.n_uname);
 651
 652error:
 653        return fc;
 654}
 655EXPORT_SYMBOL(p9_create_tattach);
 656
 657/**
 658 * p9_create_tflush - allocates and creates a T_FLUSH request
 659 * @oldtag: tag id for the transaction we are attempting to cancel
 660 *
 661 */
 662
 663struct p9_fcall *p9_create_tflush(u16 oldtag)
 664{
 665        int size;
 666        struct p9_fcall *fc;
 667        struct cbuf buffer;
 668        struct cbuf *bufp = &buffer;
 669
 670        size = 2;               /* oldtag[2] */
 671        fc = p9_create_common(bufp, size, P9_TFLUSH);
 672        if (IS_ERR(fc))
 673                goto error;
 674
 675        p9_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
 676
 677        if (buf_check_overflow(bufp)) {
 678                kfree(fc);
 679                fc = ERR_PTR(-ENOMEM);
 680        }
 681error:
 682        return fc;
 683}
 684EXPORT_SYMBOL(p9_create_tflush);
 685
 686/**
 687 * p9_create_twalk - allocates and creates a T_FLUSH request
 688 * @fid: handle we are traversing from
 689 * @newfid: a new handle for this transaction
 690 * @nwname: number of path elements to traverse
 691 * @wnames: array of path elements
 692 *
 693 */
 694
 695struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname,
 696                                     char **wnames)
 697{
 698        int i, size;
 699        struct p9_fcall *fc;
 700        struct cbuf buffer;
 701        struct cbuf *bufp = &buffer;
 702
 703        if (nwname > P9_MAXWELEM) {
 704                P9_DPRINTK(P9_DEBUG_ERROR, "nwname > %d\n", P9_MAXWELEM);
 705                return NULL;
 706        }
 707
 708        size = 4 + 4 + 2;       /* fid[4] newfid[4] nwname[2] ... */
 709        for (i = 0; i < nwname; i++) {
 710                size += 2 + strlen(wnames[i]);  /* wname[s] */
 711        }
 712
 713        fc = p9_create_common(bufp, size, P9_TWALK);
 714        if (IS_ERR(fc))
 715                goto error;
 716
 717        p9_put_int32(bufp, fid, &fc->params.twalk.fid);
 718        p9_put_int32(bufp, newfid, &fc->params.twalk.newfid);
 719        p9_put_int16(bufp, nwname, &fc->params.twalk.nwname);
 720        for (i = 0; i < nwname; i++) {
 721                p9_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
 722        }
 723
 724        if (buf_check_overflow(bufp)) {
 725                kfree(fc);
 726                fc = ERR_PTR(-ENOMEM);
 727        }
 728error:
 729        return fc;
 730}
 731EXPORT_SYMBOL(p9_create_twalk);
 732
 733/**
 734 * p9_create_topen - allocates and creates a T_OPEN request
 735 * @fid: handle we are trying to open
 736 * @mode: what mode we are trying to open the file in
 737 *
 738 */
 739
 740struct p9_fcall *p9_create_topen(u32 fid, u8 mode)
 741{
 742        int size;
 743        struct p9_fcall *fc;
 744        struct cbuf buffer;
 745        struct cbuf *bufp = &buffer;
 746
 747        size = 4 + 1;           /* fid[4] mode[1] */
 748        fc = p9_create_common(bufp, size, P9_TOPEN);
 749        if (IS_ERR(fc))
 750                goto error;
 751
 752        p9_put_int32(bufp, fid, &fc->params.topen.fid);
 753        p9_put_int8(bufp, mode, &fc->params.topen.mode);
 754
 755        if (buf_check_overflow(bufp)) {
 756                kfree(fc);
 757                fc = ERR_PTR(-ENOMEM);
 758        }
 759error:
 760        return fc;
 761}
 762EXPORT_SYMBOL(p9_create_topen);
 763
 764/**
 765 * p9_create_tcreate - allocates and creates a T_CREATE request
 766 * @fid: handle of directory we are trying to create in
 767 * @name: name of the file we are trying to create
 768 * @perm: permissions for the file we are trying to create
 769 * @mode: what mode we are trying to open the file in
 770 * @extension: 9p2000.u extension string (for special files)
 771 * @dotu: 9p2000.u enabled flag
 772 *
 773 * Note: Plan 9 create semantics include opening the resulting file
 774 * which is why mode is included.
 775 */
 776
 777struct p9_fcall *p9_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
 778        char *extension, int dotu)
 779{
 780        int size;
 781        struct p9_fcall *fc;
 782        struct cbuf buffer;
 783        struct cbuf *bufp = &buffer;
 784
 785        /* fid[4] name[s] perm[4] mode[1] */
 786        size = 4 + 2 + strlen(name) + 4 + 1;
 787        if (dotu) {
 788                size += 2 +                     /* extension[s] */
 789                    (extension == NULL ? 0 : strlen(extension));
 790        }
 791
 792        fc = p9_create_common(bufp, size, P9_TCREATE);
 793        if (IS_ERR(fc))
 794                goto error;
 795
 796        p9_put_int32(bufp, fid, &fc->params.tcreate.fid);
 797        p9_put_str(bufp, name, &fc->params.tcreate.name);
 798        p9_put_int32(bufp, perm, &fc->params.tcreate.perm);
 799        p9_put_int8(bufp, mode, &fc->params.tcreate.mode);
 800        if (dotu)
 801                p9_put_str(bufp, extension, &fc->params.tcreate.extension);
 802
 803        if (buf_check_overflow(bufp)) {
 804                kfree(fc);
 805                fc = ERR_PTR(-ENOMEM);
 806        }
 807error:
 808        return fc;
 809}
 810EXPORT_SYMBOL(p9_create_tcreate);
 811
 812/**
 813 * p9_create_tread - allocates and creates a T_READ request
 814 * @fid: handle of the file we are trying to read
 815 * @offset: offset to start reading from
 816 * @count: how many bytes to read
 817 */
 818
 819struct p9_fcall *p9_create_tread(u32 fid, u64 offset, u32 count)
 820{
 821        int size;
 822        struct p9_fcall *fc;
 823        struct cbuf buffer;
 824        struct cbuf *bufp = &buffer;
 825
 826        size = 4 + 8 + 4;       /* fid[4] offset[8] count[4] */
 827        fc = p9_create_common(bufp, size, P9_TREAD);
 828        if (IS_ERR(fc))
 829                goto error;
 830
 831        p9_put_int32(bufp, fid, &fc->params.tread.fid);
 832        p9_put_int64(bufp, offset, &fc->params.tread.offset);
 833        p9_put_int32(bufp, count, &fc->params.tread.count);
 834
 835        if (buf_check_overflow(bufp)) {
 836                kfree(fc);
 837                fc = ERR_PTR(-ENOMEM);
 838        }
 839error:
 840        return fc;
 841}
 842EXPORT_SYMBOL(p9_create_tread);
 843
 844/**
 845 * p9_create_twrite - allocates and creates a T_WRITE request from the kernel
 846 * @fid: handle of the file we are trying to write
 847 * @offset: offset to start writing at
 848 * @count: how many bytes to write
 849 * @data: data to write
 850 *
 851 * This function will create a requst with data buffers from the kernel
 852 * such as the page cache.
 853 */
 854
 855struct p9_fcall *p9_create_twrite(u32 fid, u64 offset, u32 count,
 856                                      const char *data)
 857{
 858        int size, err;
 859        struct p9_fcall *fc;
 860        struct cbuf buffer;
 861        struct cbuf *bufp = &buffer;
 862
 863        /* fid[4] offset[8] count[4] data[count] */
 864        size = 4 + 8 + 4 + count;
 865        fc = p9_create_common(bufp, size, P9_TWRITE);
 866        if (IS_ERR(fc))
 867                goto error;
 868
 869        p9_put_int32(bufp, fid, &fc->params.twrite.fid);
 870        p9_put_int64(bufp, offset, &fc->params.twrite.offset);
 871        p9_put_int32(bufp, count, &fc->params.twrite.count);
 872        err = p9_put_data(bufp, data, count, &fc->params.twrite.data);
 873        if (err) {
 874                kfree(fc);
 875                fc = ERR_PTR(err);
 876                goto error;
 877        }
 878
 879        if (buf_check_overflow(bufp)) {
 880                kfree(fc);
 881                fc = ERR_PTR(-ENOMEM);
 882        }
 883error:
 884        return fc;
 885}
 886EXPORT_SYMBOL(p9_create_twrite);
 887
 888/**
 889 * p9_create_twrite_u - allocates and creates a T_WRITE request from userspace
 890 * @fid: handle of the file we are trying to write
 891 * @offset: offset to start writing at
 892 * @count: how many bytes to write
 893 * @data: data to write
 894 *
 895 * This function will create a request with data buffers from userspace
 896 */
 897
 898struct p9_fcall *p9_create_twrite_u(u32 fid, u64 offset, u32 count,
 899                                      const char __user *data)
 900{
 901        int size, err;
 902        struct p9_fcall *fc;
 903        struct cbuf buffer;
 904        struct cbuf *bufp = &buffer;
 905
 906        /* fid[4] offset[8] count[4] data[count] */
 907        size = 4 + 8 + 4 + count;
 908        fc = p9_create_common(bufp, size, P9_TWRITE);
 909        if (IS_ERR(fc))
 910                goto error;
 911
 912        p9_put_int32(bufp, fid, &fc->params.twrite.fid);
 913        p9_put_int64(bufp, offset, &fc->params.twrite.offset);
 914        p9_put_int32(bufp, count, &fc->params.twrite.count);
 915        err = p9_put_user_data(bufp, data, count, &fc->params.twrite.data);
 916        if (err) {
 917                kfree(fc);
 918                fc = ERR_PTR(err);
 919                goto error;
 920        }
 921
 922        if (buf_check_overflow(bufp)) {
 923                kfree(fc);
 924                fc = ERR_PTR(-ENOMEM);
 925        }
 926error:
 927        return fc;
 928}
 929EXPORT_SYMBOL(p9_create_twrite_u);
 930
 931/**
 932 * p9_create_tclunk - allocate a request to forget about a file handle
 933 * @fid: handle of the file we closing or forgetting about
 934 *
 935 * clunk is used both to close open files and to discard transient handles
 936 * which may be created during meta-data operations and hierarchy traversal.
 937 */
 938
 939struct p9_fcall *p9_create_tclunk(u32 fid)
 940{
 941        int size;
 942        struct p9_fcall *fc;
 943        struct cbuf buffer;
 944        struct cbuf *bufp = &buffer;
 945
 946        size = 4;               /* fid[4] */
 947        fc = p9_create_common(bufp, size, P9_TCLUNK);
 948        if (IS_ERR(fc))
 949                goto error;
 950
 951        p9_put_int32(bufp, fid, &fc->params.tclunk.fid);
 952
 953        if (buf_check_overflow(bufp)) {
 954                kfree(fc);
 955                fc = ERR_PTR(-ENOMEM);
 956        }
 957error:
 958        return fc;
 959}
 960EXPORT_SYMBOL(p9_create_tclunk);
 961
 962/**
 963 * p9_create_tremove - allocate and create a request to remove a file
 964 * @fid: handle of the file or directory we are removing
 965 *
 966 */
 967
 968struct p9_fcall *p9_create_tremove(u32 fid)
 969{
 970        int size;
 971        struct p9_fcall *fc;
 972        struct cbuf buffer;
 973        struct cbuf *bufp = &buffer;
 974
 975        size = 4;               /* fid[4] */
 976        fc = p9_create_common(bufp, size, P9_TREMOVE);
 977        if (IS_ERR(fc))
 978                goto error;
 979
 980        p9_put_int32(bufp, fid, &fc->params.tremove.fid);
 981
 982        if (buf_check_overflow(bufp)) {
 983                kfree(fc);
 984                fc = ERR_PTR(-ENOMEM);
 985        }
 986error:
 987        return fc;
 988}
 989EXPORT_SYMBOL(p9_create_tremove);
 990
 991/**
 992 * p9_create_tstat - allocate and populate a request for attributes
 993 * @fid: handle of the file or directory we are trying to get the attributes of
 994 *
 995 */
 996
 997struct p9_fcall *p9_create_tstat(u32 fid)
 998{
 999        int size;
1000        struct p9_fcall *fc;
1001        struct cbuf buffer;
1002        struct cbuf *bufp = &buffer;
1003
1004        size = 4;               /* fid[4] */
1005        fc = p9_create_common(bufp, size, P9_TSTAT);
1006        if (IS_ERR(fc))
1007                goto error;
1008
1009        p9_put_int32(bufp, fid, &fc->params.tstat.fid);
1010
1011        if (buf_check_overflow(bufp)) {
1012                kfree(fc);
1013                fc = ERR_PTR(-ENOMEM);
1014        }
1015error:
1016        return fc;
1017}
1018EXPORT_SYMBOL(p9_create_tstat);
1019
1020/**
1021 * p9_create_tstat - allocate and populate a request to change attributes
1022 * @fid: handle of the file or directory we are trying to change
1023 * @wstat: &p9_stat structure with attributes we wish to set
1024 * @dotu: 9p2000.u enabled flag
1025 *
1026 */
1027
1028struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat,
1029                                      int dotu)
1030{
1031        int size, statsz;
1032        struct p9_fcall *fc;
1033        struct cbuf buffer;
1034        struct cbuf *bufp = &buffer;
1035
1036        statsz = p9_size_wstat(wstat, dotu);
1037        size = 4 + 2 + 2 + statsz;      /* fid[4] stat[n] */
1038        fc = p9_create_common(bufp, size, P9_TWSTAT);
1039        if (IS_ERR(fc))
1040                goto error;
1041
1042        p9_put_int32(bufp, fid, &fc->params.twstat.fid);
1043        buf_put_int16(bufp, statsz + 2);
1044        p9_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, dotu);
1045
1046        if (buf_check_overflow(bufp)) {
1047                kfree(fc);
1048                fc = ERR_PTR(-ENOMEM);
1049        }
1050error:
1051        return fc;
1052}
1053EXPORT_SYMBOL(p9_create_twstat);
1054
1055