at v2.6.24 929 lines 20 kB view raw
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 inline void buf_put_string(struct cbuf *buf, const char *s) 132{ 133 buf_put_stringn(buf, s, strlen(s)); 134} 135 136static u8 buf_get_int8(struct cbuf *buf) 137{ 138 u8 ret = 0; 139 140 if (buf_check_size(buf, 1)) { 141 ret = buf->p[0]; 142 buf->p++; 143 } 144 145 return ret; 146} 147 148static u16 buf_get_int16(struct cbuf *buf) 149{ 150 u16 ret = 0; 151 152 if (buf_check_size(buf, 2)) { 153 ret = le16_to_cpu(*(__le16 *)buf->p); 154 buf->p += 2; 155 } 156 157 return ret; 158} 159 160static u32 buf_get_int32(struct cbuf *buf) 161{ 162 u32 ret = 0; 163 164 if (buf_check_size(buf, 4)) { 165 ret = le32_to_cpu(*(__le32 *)buf->p); 166 buf->p += 4; 167 } 168 169 return ret; 170} 171 172static u64 buf_get_int64(struct cbuf *buf) 173{ 174 u64 ret = 0; 175 176 if (buf_check_size(buf, 8)) { 177 ret = le64_to_cpu(*(__le64 *)buf->p); 178 buf->p += 8; 179 } 180 181 return ret; 182} 183 184static void buf_get_str(struct cbuf *buf, struct p9_str *vstr) 185{ 186 vstr->len = buf_get_int16(buf); 187 if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) { 188 vstr->str = buf->p; 189 buf->p += vstr->len; 190 } else { 191 vstr->len = 0; 192 vstr->str = NULL; 193 } 194} 195 196static void buf_get_qid(struct cbuf *bufp, struct p9_qid *qid) 197{ 198 qid->type = buf_get_int8(bufp); 199 qid->version = buf_get_int32(bufp); 200 qid->path = buf_get_int64(bufp); 201} 202 203/** 204 * p9_size_wstat - calculate the size of a variable length stat struct 205 * @stat: metadata (stat) structure 206 * @dotu: non-zero if 9P2000.u 207 * 208 */ 209 210static int p9_size_wstat(struct p9_wstat *wstat, int dotu) 211{ 212 int size = 0; 213 214 if (wstat == NULL) { 215 P9_EPRINTK(KERN_ERR, "p9_size_stat: got a NULL stat pointer\n"); 216 return 0; 217 } 218 219 size = /* 2 + *//* size[2] */ 220 2 + /* type[2] */ 221 4 + /* dev[4] */ 222 1 + /* qid.type[1] */ 223 4 + /* qid.vers[4] */ 224 8 + /* qid.path[8] */ 225 4 + /* mode[4] */ 226 4 + /* atime[4] */ 227 4 + /* mtime[4] */ 228 8 + /* length[8] */ 229 8; /* minimum sum of string lengths */ 230 231 if (wstat->name) 232 size += strlen(wstat->name); 233 if (wstat->uid) 234 size += strlen(wstat->uid); 235 if (wstat->gid) 236 size += strlen(wstat->gid); 237 if (wstat->muid) 238 size += strlen(wstat->muid); 239 240 if (dotu) { 241 size += 4 + /* n_uid[4] */ 242 4 + /* n_gid[4] */ 243 4 + /* n_muid[4] */ 244 2; /* string length of extension[4] */ 245 if (wstat->extension) 246 size += strlen(wstat->extension); 247 } 248 249 return size; 250} 251 252/** 253 * buf_get_stat - safely decode a recieved metadata (stat) structure 254 * @bufp: buffer to deserialize 255 * @stat: metadata (stat) structure 256 * @dotu: non-zero if 9P2000.u 257 * 258 */ 259 260static void 261buf_get_stat(struct cbuf *bufp, struct p9_stat *stat, int dotu) 262{ 263 stat->size = buf_get_int16(bufp); 264 stat->type = buf_get_int16(bufp); 265 stat->dev = buf_get_int32(bufp); 266 stat->qid.type = buf_get_int8(bufp); 267 stat->qid.version = buf_get_int32(bufp); 268 stat->qid.path = buf_get_int64(bufp); 269 stat->mode = buf_get_int32(bufp); 270 stat->atime = buf_get_int32(bufp); 271 stat->mtime = buf_get_int32(bufp); 272 stat->length = buf_get_int64(bufp); 273 buf_get_str(bufp, &stat->name); 274 buf_get_str(bufp, &stat->uid); 275 buf_get_str(bufp, &stat->gid); 276 buf_get_str(bufp, &stat->muid); 277 278 if (dotu) { 279 buf_get_str(bufp, &stat->extension); 280 stat->n_uid = buf_get_int32(bufp); 281 stat->n_gid = buf_get_int32(bufp); 282 stat->n_muid = buf_get_int32(bufp); 283 } 284} 285 286/** 287 * p9_deserialize_stat - decode a received metadata structure 288 * @buf: buffer to deserialize 289 * @buflen: length of received buffer 290 * @stat: metadata structure to decode into 291 * @dotu: non-zero if 9P2000.u 292 * 293 * Note: stat will point to the buf region. 294 */ 295 296int 297p9_deserialize_stat(void *buf, u32 buflen, struct p9_stat *stat, 298 int dotu) 299{ 300 struct cbuf buffer; 301 struct cbuf *bufp = &buffer; 302 unsigned char *p; 303 304 buf_init(bufp, buf, buflen); 305 p = bufp->p; 306 buf_get_stat(bufp, stat, dotu); 307 308 if (buf_check_overflow(bufp)) 309 return 0; 310 else 311 return bufp->p - p; 312} 313EXPORT_SYMBOL(p9_deserialize_stat); 314 315/** 316 * deserialize_fcall - unmarshal a response 317 * @buf: recieved buffer 318 * @buflen: length of received buffer 319 * @rcall: fcall structure to populate 320 * @rcalllen: length of fcall structure to populate 321 * @dotu: non-zero if 9P2000.u 322 * 323 */ 324 325int 326p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *rcall, 327 int dotu) 328{ 329 330 struct cbuf buffer; 331 struct cbuf *bufp = &buffer; 332 int i = 0; 333 334 buf_init(bufp, buf, buflen); 335 336 rcall->size = buf_get_int32(bufp); 337 rcall->id = buf_get_int8(bufp); 338 rcall->tag = buf_get_int16(bufp); 339 340 P9_DPRINTK(P9_DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, 341 rcall->id, rcall->tag); 342 343 switch (rcall->id) { 344 default: 345 P9_EPRINTK(KERN_ERR, "unknown message type: %d\n", rcall->id); 346 return -EPROTO; 347 case P9_RVERSION: 348 rcall->params.rversion.msize = buf_get_int32(bufp); 349 buf_get_str(bufp, &rcall->params.rversion.version); 350 break; 351 case P9_RFLUSH: 352 break; 353 case P9_RATTACH: 354 rcall->params.rattach.qid.type = buf_get_int8(bufp); 355 rcall->params.rattach.qid.version = buf_get_int32(bufp); 356 rcall->params.rattach.qid.path = buf_get_int64(bufp); 357 break; 358 case P9_RWALK: 359 rcall->params.rwalk.nwqid = buf_get_int16(bufp); 360 if (rcall->params.rwalk.nwqid > P9_MAXWELEM) { 361 P9_EPRINTK(KERN_ERR, 362 "Rwalk with more than %d qids: %d\n", 363 P9_MAXWELEM, rcall->params.rwalk.nwqid); 364 return -EPROTO; 365 } 366 367 for (i = 0; i < rcall->params.rwalk.nwqid; i++) 368 buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]); 369 break; 370 case P9_ROPEN: 371 buf_get_qid(bufp, &rcall->params.ropen.qid); 372 rcall->params.ropen.iounit = buf_get_int32(bufp); 373 break; 374 case P9_RCREATE: 375 buf_get_qid(bufp, &rcall->params.rcreate.qid); 376 rcall->params.rcreate.iounit = buf_get_int32(bufp); 377 break; 378 case P9_RREAD: 379 rcall->params.rread.count = buf_get_int32(bufp); 380 rcall->params.rread.data = bufp->p; 381 buf_check_size(bufp, rcall->params.rread.count); 382 break; 383 case P9_RWRITE: 384 rcall->params.rwrite.count = buf_get_int32(bufp); 385 break; 386 case P9_RCLUNK: 387 break; 388 case P9_RREMOVE: 389 break; 390 case P9_RSTAT: 391 buf_get_int16(bufp); 392 buf_get_stat(bufp, &rcall->params.rstat.stat, dotu); 393 break; 394 case P9_RWSTAT: 395 break; 396 case P9_RERROR: 397 buf_get_str(bufp, &rcall->params.rerror.error); 398 if (dotu) 399 rcall->params.rerror.errno = buf_get_int16(bufp); 400 break; 401 } 402 403 if (buf_check_overflow(bufp)) { 404 P9_DPRINTK(P9_DEBUG_ERROR, "buffer overflow\n"); 405 return -EIO; 406 } 407 408 return bufp->p - bufp->sp; 409} 410EXPORT_SYMBOL(p9_deserialize_fcall); 411 412static inline void p9_put_int8(struct cbuf *bufp, u8 val, u8 * p) 413{ 414 *p = val; 415 buf_put_int8(bufp, val); 416} 417 418static inline void p9_put_int16(struct cbuf *bufp, u16 val, u16 * p) 419{ 420 *p = val; 421 buf_put_int16(bufp, val); 422} 423 424static inline void p9_put_int32(struct cbuf *bufp, u32 val, u32 * p) 425{ 426 *p = val; 427 buf_put_int32(bufp, val); 428} 429 430static inline void p9_put_int64(struct cbuf *bufp, u64 val, u64 * p) 431{ 432 *p = val; 433 buf_put_int64(bufp, val); 434} 435 436static void 437p9_put_str(struct cbuf *bufp, char *data, struct p9_str *str) 438{ 439 int len; 440 char *s; 441 442 if (data) 443 len = strlen(data); 444 else 445 len = 0; 446 447 s = buf_put_stringn(bufp, data, len); 448 if (str) { 449 str->len = len; 450 str->str = s; 451 } 452} 453 454static int 455p9_put_data(struct cbuf *bufp, const char *data, int count, 456 unsigned char **pdata) 457{ 458 *pdata = buf_alloc(bufp, count); 459 memmove(*pdata, data, count); 460 return count; 461} 462 463static int 464p9_put_user_data(struct cbuf *bufp, const char __user *data, int count, 465 unsigned char **pdata) 466{ 467 *pdata = buf_alloc(bufp, count); 468 return copy_from_user(*pdata, data, count); 469} 470 471static void 472p9_put_wstat(struct cbuf *bufp, struct p9_wstat *wstat, 473 struct p9_stat *stat, int statsz, int dotu) 474{ 475 p9_put_int16(bufp, statsz, &stat->size); 476 p9_put_int16(bufp, wstat->type, &stat->type); 477 p9_put_int32(bufp, wstat->dev, &stat->dev); 478 p9_put_int8(bufp, wstat->qid.type, &stat->qid.type); 479 p9_put_int32(bufp, wstat->qid.version, &stat->qid.version); 480 p9_put_int64(bufp, wstat->qid.path, &stat->qid.path); 481 p9_put_int32(bufp, wstat->mode, &stat->mode); 482 p9_put_int32(bufp, wstat->atime, &stat->atime); 483 p9_put_int32(bufp, wstat->mtime, &stat->mtime); 484 p9_put_int64(bufp, wstat->length, &stat->length); 485 486 p9_put_str(bufp, wstat->name, &stat->name); 487 p9_put_str(bufp, wstat->uid, &stat->uid); 488 p9_put_str(bufp, wstat->gid, &stat->gid); 489 p9_put_str(bufp, wstat->muid, &stat->muid); 490 491 if (dotu) { 492 p9_put_str(bufp, wstat->extension, &stat->extension); 493 p9_put_int32(bufp, wstat->n_uid, &stat->n_uid); 494 p9_put_int32(bufp, wstat->n_gid, &stat->n_gid); 495 p9_put_int32(bufp, wstat->n_muid, &stat->n_muid); 496 } 497} 498 499static struct p9_fcall * 500p9_create_common(struct cbuf *bufp, u32 size, u8 id) 501{ 502 struct p9_fcall *fc; 503 504 size += 4 + 1 + 2; /* size[4] id[1] tag[2] */ 505 fc = kmalloc(sizeof(struct p9_fcall) + size, GFP_KERNEL); 506 if (!fc) 507 return ERR_PTR(-ENOMEM); 508 509 fc->sdata = (char *)fc + sizeof(*fc); 510 511 buf_init(bufp, (char *)fc->sdata, size); 512 p9_put_int32(bufp, size, &fc->size); 513 p9_put_int8(bufp, id, &fc->id); 514 p9_put_int16(bufp, P9_NOTAG, &fc->tag); 515 516 return fc; 517} 518 519void p9_set_tag(struct p9_fcall *fc, u16 tag) 520{ 521 fc->tag = tag; 522 *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag); 523} 524EXPORT_SYMBOL(p9_set_tag); 525 526struct p9_fcall *p9_create_tversion(u32 msize, char *version) 527{ 528 int size; 529 struct p9_fcall *fc; 530 struct cbuf buffer; 531 struct cbuf *bufp = &buffer; 532 533 size = 4 + 2 + strlen(version); /* msize[4] version[s] */ 534 fc = p9_create_common(bufp, size, P9_TVERSION); 535 if (IS_ERR(fc)) 536 goto error; 537 538 p9_put_int32(bufp, msize, &fc->params.tversion.msize); 539 p9_put_str(bufp, version, &fc->params.tversion.version); 540 541 if (buf_check_overflow(bufp)) { 542 kfree(fc); 543 fc = ERR_PTR(-ENOMEM); 544 } 545error: 546 return fc; 547} 548EXPORT_SYMBOL(p9_create_tversion); 549 550struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname, 551 u32 n_uname, int dotu) 552{ 553 int size; 554 struct p9_fcall *fc; 555 struct cbuf buffer; 556 struct cbuf *bufp = &buffer; 557 558 /* afid[4] uname[s] aname[s] */ 559 size = 4 + 2 + 2; 560 if (uname) 561 size += strlen(uname); 562 563 if (aname) 564 size += strlen(aname); 565 566 if (dotu) 567 size += 4; /* n_uname */ 568 569 fc = p9_create_common(bufp, size, P9_TAUTH); 570 if (IS_ERR(fc)) 571 goto error; 572 573 p9_put_int32(bufp, afid, &fc->params.tauth.afid); 574 p9_put_str(bufp, uname, &fc->params.tauth.uname); 575 p9_put_str(bufp, aname, &fc->params.tauth.aname); 576 if (dotu) 577 p9_put_int32(bufp, n_uname, &fc->params.tauth.n_uname); 578 579 if (buf_check_overflow(bufp)) { 580 kfree(fc); 581 fc = ERR_PTR(-ENOMEM); 582 } 583error: 584 return fc; 585} 586EXPORT_SYMBOL(p9_create_tauth); 587 588struct p9_fcall * 589p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname, 590 u32 n_uname, int dotu) 591{ 592 int size; 593 struct p9_fcall *fc; 594 struct cbuf buffer; 595 struct cbuf *bufp = &buffer; 596 597 /* fid[4] afid[4] uname[s] aname[s] */ 598 size = 4 + 4 + 2 + 2; 599 if (uname) 600 size += strlen(uname); 601 602 if (aname) 603 size += strlen(aname); 604 605 if (dotu) 606 size += 4; /* n_uname */ 607 608 fc = p9_create_common(bufp, size, P9_TATTACH); 609 if (IS_ERR(fc)) 610 goto error; 611 612 p9_put_int32(bufp, fid, &fc->params.tattach.fid); 613 p9_put_int32(bufp, afid, &fc->params.tattach.afid); 614 p9_put_str(bufp, uname, &fc->params.tattach.uname); 615 p9_put_str(bufp, aname, &fc->params.tattach.aname); 616 if (dotu) 617 p9_put_int32(bufp, n_uname, &fc->params.tattach.n_uname); 618 619error: 620 return fc; 621} 622EXPORT_SYMBOL(p9_create_tattach); 623 624struct p9_fcall *p9_create_tflush(u16 oldtag) 625{ 626 int size; 627 struct p9_fcall *fc; 628 struct cbuf buffer; 629 struct cbuf *bufp = &buffer; 630 631 size = 2; /* oldtag[2] */ 632 fc = p9_create_common(bufp, size, P9_TFLUSH); 633 if (IS_ERR(fc)) 634 goto error; 635 636 p9_put_int16(bufp, oldtag, &fc->params.tflush.oldtag); 637 638 if (buf_check_overflow(bufp)) { 639 kfree(fc); 640 fc = ERR_PTR(-ENOMEM); 641 } 642error: 643 return fc; 644} 645EXPORT_SYMBOL(p9_create_tflush); 646 647struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname, 648 char **wnames) 649{ 650 int i, size; 651 struct p9_fcall *fc; 652 struct cbuf buffer; 653 struct cbuf *bufp = &buffer; 654 655 if (nwname > P9_MAXWELEM) { 656 P9_DPRINTK(P9_DEBUG_ERROR, "nwname > %d\n", P9_MAXWELEM); 657 return NULL; 658 } 659 660 size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */ 661 for (i = 0; i < nwname; i++) { 662 size += 2 + strlen(wnames[i]); /* wname[s] */ 663 } 664 665 fc = p9_create_common(bufp, size, P9_TWALK); 666 if (IS_ERR(fc)) 667 goto error; 668 669 p9_put_int32(bufp, fid, &fc->params.twalk.fid); 670 p9_put_int32(bufp, newfid, &fc->params.twalk.newfid); 671 p9_put_int16(bufp, nwname, &fc->params.twalk.nwname); 672 for (i = 0; i < nwname; i++) { 673 p9_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]); 674 } 675 676 if (buf_check_overflow(bufp)) { 677 kfree(fc); 678 fc = ERR_PTR(-ENOMEM); 679 } 680error: 681 return fc; 682} 683EXPORT_SYMBOL(p9_create_twalk); 684 685struct p9_fcall *p9_create_topen(u32 fid, u8 mode) 686{ 687 int size; 688 struct p9_fcall *fc; 689 struct cbuf buffer; 690 struct cbuf *bufp = &buffer; 691 692 size = 4 + 1; /* fid[4] mode[1] */ 693 fc = p9_create_common(bufp, size, P9_TOPEN); 694 if (IS_ERR(fc)) 695 goto error; 696 697 p9_put_int32(bufp, fid, &fc->params.topen.fid); 698 p9_put_int8(bufp, mode, &fc->params.topen.mode); 699 700 if (buf_check_overflow(bufp)) { 701 kfree(fc); 702 fc = ERR_PTR(-ENOMEM); 703 } 704error: 705 return fc; 706} 707EXPORT_SYMBOL(p9_create_topen); 708 709struct p9_fcall *p9_create_tcreate(u32 fid, char *name, u32 perm, u8 mode, 710 char *extension, int dotu) 711{ 712 int size; 713 struct p9_fcall *fc; 714 struct cbuf buffer; 715 struct cbuf *bufp = &buffer; 716 717 /* fid[4] name[s] perm[4] mode[1] */ 718 size = 4 + 2 + strlen(name) + 4 + 1; 719 if (dotu) { 720 size += 2 + /* extension[s] */ 721 (extension == NULL ? 0 : strlen(extension)); 722 } 723 724 fc = p9_create_common(bufp, size, P9_TCREATE); 725 if (IS_ERR(fc)) 726 goto error; 727 728 p9_put_int32(bufp, fid, &fc->params.tcreate.fid); 729 p9_put_str(bufp, name, &fc->params.tcreate.name); 730 p9_put_int32(bufp, perm, &fc->params.tcreate.perm); 731 p9_put_int8(bufp, mode, &fc->params.tcreate.mode); 732 if (dotu) 733 p9_put_str(bufp, extension, &fc->params.tcreate.extension); 734 735 if (buf_check_overflow(bufp)) { 736 kfree(fc); 737 fc = ERR_PTR(-ENOMEM); 738 } 739error: 740 return fc; 741} 742EXPORT_SYMBOL(p9_create_tcreate); 743 744struct p9_fcall *p9_create_tread(u32 fid, u64 offset, u32 count) 745{ 746 int size; 747 struct p9_fcall *fc; 748 struct cbuf buffer; 749 struct cbuf *bufp = &buffer; 750 751 size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */ 752 fc = p9_create_common(bufp, size, P9_TREAD); 753 if (IS_ERR(fc)) 754 goto error; 755 756 p9_put_int32(bufp, fid, &fc->params.tread.fid); 757 p9_put_int64(bufp, offset, &fc->params.tread.offset); 758 p9_put_int32(bufp, count, &fc->params.tread.count); 759 760 if (buf_check_overflow(bufp)) { 761 kfree(fc); 762 fc = ERR_PTR(-ENOMEM); 763 } 764error: 765 return fc; 766} 767EXPORT_SYMBOL(p9_create_tread); 768 769struct p9_fcall *p9_create_twrite(u32 fid, u64 offset, u32 count, 770 const char *data) 771{ 772 int size, err; 773 struct p9_fcall *fc; 774 struct cbuf buffer; 775 struct cbuf *bufp = &buffer; 776 777 /* fid[4] offset[8] count[4] data[count] */ 778 size = 4 + 8 + 4 + count; 779 fc = p9_create_common(bufp, size, P9_TWRITE); 780 if (IS_ERR(fc)) 781 goto error; 782 783 p9_put_int32(bufp, fid, &fc->params.twrite.fid); 784 p9_put_int64(bufp, offset, &fc->params.twrite.offset); 785 p9_put_int32(bufp, count, &fc->params.twrite.count); 786 err = p9_put_data(bufp, data, count, &fc->params.twrite.data); 787 if (err) { 788 kfree(fc); 789 fc = ERR_PTR(err); 790 goto error; 791 } 792 793 if (buf_check_overflow(bufp)) { 794 kfree(fc); 795 fc = ERR_PTR(-ENOMEM); 796 } 797error: 798 return fc; 799} 800EXPORT_SYMBOL(p9_create_twrite); 801 802struct p9_fcall *p9_create_twrite_u(u32 fid, u64 offset, u32 count, 803 const char __user *data) 804{ 805 int size, err; 806 struct p9_fcall *fc; 807 struct cbuf buffer; 808 struct cbuf *bufp = &buffer; 809 810 /* fid[4] offset[8] count[4] data[count] */ 811 size = 4 + 8 + 4 + count; 812 fc = p9_create_common(bufp, size, P9_TWRITE); 813 if (IS_ERR(fc)) 814 goto error; 815 816 p9_put_int32(bufp, fid, &fc->params.twrite.fid); 817 p9_put_int64(bufp, offset, &fc->params.twrite.offset); 818 p9_put_int32(bufp, count, &fc->params.twrite.count); 819 err = p9_put_user_data(bufp, data, count, &fc->params.twrite.data); 820 if (err) { 821 kfree(fc); 822 fc = ERR_PTR(err); 823 goto error; 824 } 825 826 if (buf_check_overflow(bufp)) { 827 kfree(fc); 828 fc = ERR_PTR(-ENOMEM); 829 } 830error: 831 return fc; 832} 833EXPORT_SYMBOL(p9_create_twrite_u); 834 835struct p9_fcall *p9_create_tclunk(u32 fid) 836{ 837 int size; 838 struct p9_fcall *fc; 839 struct cbuf buffer; 840 struct cbuf *bufp = &buffer; 841 842 size = 4; /* fid[4] */ 843 fc = p9_create_common(bufp, size, P9_TCLUNK); 844 if (IS_ERR(fc)) 845 goto error; 846 847 p9_put_int32(bufp, fid, &fc->params.tclunk.fid); 848 849 if (buf_check_overflow(bufp)) { 850 kfree(fc); 851 fc = ERR_PTR(-ENOMEM); 852 } 853error: 854 return fc; 855} 856EXPORT_SYMBOL(p9_create_tclunk); 857 858struct p9_fcall *p9_create_tremove(u32 fid) 859{ 860 int size; 861 struct p9_fcall *fc; 862 struct cbuf buffer; 863 struct cbuf *bufp = &buffer; 864 865 size = 4; /* fid[4] */ 866 fc = p9_create_common(bufp, size, P9_TREMOVE); 867 if (IS_ERR(fc)) 868 goto error; 869 870 p9_put_int32(bufp, fid, &fc->params.tremove.fid); 871 872 if (buf_check_overflow(bufp)) { 873 kfree(fc); 874 fc = ERR_PTR(-ENOMEM); 875 } 876error: 877 return fc; 878} 879EXPORT_SYMBOL(p9_create_tremove); 880 881struct p9_fcall *p9_create_tstat(u32 fid) 882{ 883 int size; 884 struct p9_fcall *fc; 885 struct cbuf buffer; 886 struct cbuf *bufp = &buffer; 887 888 size = 4; /* fid[4] */ 889 fc = p9_create_common(bufp, size, P9_TSTAT); 890 if (IS_ERR(fc)) 891 goto error; 892 893 p9_put_int32(bufp, fid, &fc->params.tstat.fid); 894 895 if (buf_check_overflow(bufp)) { 896 kfree(fc); 897 fc = ERR_PTR(-ENOMEM); 898 } 899error: 900 return fc; 901} 902EXPORT_SYMBOL(p9_create_tstat); 903 904struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat, 905 int dotu) 906{ 907 int size, statsz; 908 struct p9_fcall *fc; 909 struct cbuf buffer; 910 struct cbuf *bufp = &buffer; 911 912 statsz = p9_size_wstat(wstat, dotu); 913 size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */ 914 fc = p9_create_common(bufp, size, P9_TWSTAT); 915 if (IS_ERR(fc)) 916 goto error; 917 918 p9_put_int32(bufp, fid, &fc->params.twstat.fid); 919 buf_put_int16(bufp, statsz + 2); 920 p9_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, dotu); 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_twstat);