Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.23-rc2 904 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{ 552 int size; 553 struct p9_fcall *fc; 554 struct cbuf buffer; 555 struct cbuf *bufp = &buffer; 556 557 /* afid[4] uname[s] aname[s] */ 558 size = 4 + 2 + strlen(uname) + 2 + strlen(aname); 559 fc = p9_create_common(bufp, size, P9_TAUTH); 560 if (IS_ERR(fc)) 561 goto error; 562 563 p9_put_int32(bufp, afid, &fc->params.tauth.afid); 564 p9_put_str(bufp, uname, &fc->params.tauth.uname); 565 p9_put_str(bufp, aname, &fc->params.tauth.aname); 566 567 if (buf_check_overflow(bufp)) { 568 kfree(fc); 569 fc = ERR_PTR(-ENOMEM); 570 } 571error: 572 return fc; 573} 574EXPORT_SYMBOL(p9_create_tauth); 575 576struct p9_fcall * 577p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname) 578{ 579 int size; 580 struct p9_fcall *fc; 581 struct cbuf buffer; 582 struct cbuf *bufp = &buffer; 583 584 /* fid[4] afid[4] uname[s] aname[s] */ 585 size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); 586 fc = p9_create_common(bufp, size, P9_TATTACH); 587 if (IS_ERR(fc)) 588 goto error; 589 590 p9_put_int32(bufp, fid, &fc->params.tattach.fid); 591 p9_put_int32(bufp, afid, &fc->params.tattach.afid); 592 p9_put_str(bufp, uname, &fc->params.tattach.uname); 593 p9_put_str(bufp, aname, &fc->params.tattach.aname); 594 595error: 596 return fc; 597} 598EXPORT_SYMBOL(p9_create_tattach); 599 600struct p9_fcall *p9_create_tflush(u16 oldtag) 601{ 602 int size; 603 struct p9_fcall *fc; 604 struct cbuf buffer; 605 struct cbuf *bufp = &buffer; 606 607 size = 2; /* oldtag[2] */ 608 fc = p9_create_common(bufp, size, P9_TFLUSH); 609 if (IS_ERR(fc)) 610 goto error; 611 612 p9_put_int16(bufp, oldtag, &fc->params.tflush.oldtag); 613 614 if (buf_check_overflow(bufp)) { 615 kfree(fc); 616 fc = ERR_PTR(-ENOMEM); 617 } 618error: 619 return fc; 620} 621EXPORT_SYMBOL(p9_create_tflush); 622 623struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname, 624 char **wnames) 625{ 626 int i, size; 627 struct p9_fcall *fc; 628 struct cbuf buffer; 629 struct cbuf *bufp = &buffer; 630 631 if (nwname > P9_MAXWELEM) { 632 P9_DPRINTK(P9_DEBUG_ERROR, "nwname > %d\n", P9_MAXWELEM); 633 return NULL; 634 } 635 636 size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */ 637 for (i = 0; i < nwname; i++) { 638 size += 2 + strlen(wnames[i]); /* wname[s] */ 639 } 640 641 fc = p9_create_common(bufp, size, P9_TWALK); 642 if (IS_ERR(fc)) 643 goto error; 644 645 p9_put_int32(bufp, fid, &fc->params.twalk.fid); 646 p9_put_int32(bufp, newfid, &fc->params.twalk.newfid); 647 p9_put_int16(bufp, nwname, &fc->params.twalk.nwname); 648 for (i = 0; i < nwname; i++) { 649 p9_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]); 650 } 651 652 if (buf_check_overflow(bufp)) { 653 kfree(fc); 654 fc = ERR_PTR(-ENOMEM); 655 } 656error: 657 return fc; 658} 659EXPORT_SYMBOL(p9_create_twalk); 660 661struct p9_fcall *p9_create_topen(u32 fid, u8 mode) 662{ 663 int size; 664 struct p9_fcall *fc; 665 struct cbuf buffer; 666 struct cbuf *bufp = &buffer; 667 668 size = 4 + 1; /* fid[4] mode[1] */ 669 fc = p9_create_common(bufp, size, P9_TOPEN); 670 if (IS_ERR(fc)) 671 goto error; 672 673 p9_put_int32(bufp, fid, &fc->params.topen.fid); 674 p9_put_int8(bufp, mode, &fc->params.topen.mode); 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_topen); 684 685struct p9_fcall *p9_create_tcreate(u32 fid, char *name, u32 perm, u8 mode, 686 char *extension, int dotu) 687{ 688 int size; 689 struct p9_fcall *fc; 690 struct cbuf buffer; 691 struct cbuf *bufp = &buffer; 692 693 /* fid[4] name[s] perm[4] mode[1] */ 694 size = 4 + 2 + strlen(name) + 4 + 1; 695 if (dotu) { 696 size += 2 + /* extension[s] */ 697 (extension == NULL ? 0 : strlen(extension)); 698 } 699 700 fc = p9_create_common(bufp, size, P9_TCREATE); 701 if (IS_ERR(fc)) 702 goto error; 703 704 p9_put_int32(bufp, fid, &fc->params.tcreate.fid); 705 p9_put_str(bufp, name, &fc->params.tcreate.name); 706 p9_put_int32(bufp, perm, &fc->params.tcreate.perm); 707 p9_put_int8(bufp, mode, &fc->params.tcreate.mode); 708 if (dotu) 709 p9_put_str(bufp, extension, &fc->params.tcreate.extension); 710 711 if (buf_check_overflow(bufp)) { 712 kfree(fc); 713 fc = ERR_PTR(-ENOMEM); 714 } 715error: 716 return fc; 717} 718EXPORT_SYMBOL(p9_create_tcreate); 719 720struct p9_fcall *p9_create_tread(u32 fid, u64 offset, u32 count) 721{ 722 int size; 723 struct p9_fcall *fc; 724 struct cbuf buffer; 725 struct cbuf *bufp = &buffer; 726 727 size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */ 728 fc = p9_create_common(bufp, size, P9_TREAD); 729 if (IS_ERR(fc)) 730 goto error; 731 732 p9_put_int32(bufp, fid, &fc->params.tread.fid); 733 p9_put_int64(bufp, offset, &fc->params.tread.offset); 734 p9_put_int32(bufp, count, &fc->params.tread.count); 735 736 if (buf_check_overflow(bufp)) { 737 kfree(fc); 738 fc = ERR_PTR(-ENOMEM); 739 } 740error: 741 return fc; 742} 743EXPORT_SYMBOL(p9_create_tread); 744 745struct p9_fcall *p9_create_twrite(u32 fid, u64 offset, u32 count, 746 const char *data) 747{ 748 int size, err; 749 struct p9_fcall *fc; 750 struct cbuf buffer; 751 struct cbuf *bufp = &buffer; 752 753 /* fid[4] offset[8] count[4] data[count] */ 754 size = 4 + 8 + 4 + count; 755 fc = p9_create_common(bufp, size, P9_TWRITE); 756 if (IS_ERR(fc)) 757 goto error; 758 759 p9_put_int32(bufp, fid, &fc->params.twrite.fid); 760 p9_put_int64(bufp, offset, &fc->params.twrite.offset); 761 p9_put_int32(bufp, count, &fc->params.twrite.count); 762 err = p9_put_data(bufp, data, count, &fc->params.twrite.data); 763 if (err) { 764 kfree(fc); 765 fc = ERR_PTR(err); 766 goto error; 767 } 768 769 if (buf_check_overflow(bufp)) { 770 kfree(fc); 771 fc = ERR_PTR(-ENOMEM); 772 } 773error: 774 return fc; 775} 776EXPORT_SYMBOL(p9_create_twrite); 777 778struct p9_fcall *p9_create_twrite_u(u32 fid, u64 offset, u32 count, 779 const char __user *data) 780{ 781 int size, err; 782 struct p9_fcall *fc; 783 struct cbuf buffer; 784 struct cbuf *bufp = &buffer; 785 786 /* fid[4] offset[8] count[4] data[count] */ 787 size = 4 + 8 + 4 + count; 788 fc = p9_create_common(bufp, size, P9_TWRITE); 789 if (IS_ERR(fc)) 790 goto error; 791 792 p9_put_int32(bufp, fid, &fc->params.twrite.fid); 793 p9_put_int64(bufp, offset, &fc->params.twrite.offset); 794 p9_put_int32(bufp, count, &fc->params.twrite.count); 795 err = p9_put_user_data(bufp, data, count, &fc->params.twrite.data); 796 if (err) { 797 kfree(fc); 798 fc = ERR_PTR(err); 799 } 800 801 if (buf_check_overflow(bufp)) { 802 kfree(fc); 803 fc = ERR_PTR(-ENOMEM); 804 } 805error: 806 return fc; 807} 808EXPORT_SYMBOL(p9_create_twrite_u); 809 810struct p9_fcall *p9_create_tclunk(u32 fid) 811{ 812 int size; 813 struct p9_fcall *fc; 814 struct cbuf buffer; 815 struct cbuf *bufp = &buffer; 816 817 size = 4; /* fid[4] */ 818 fc = p9_create_common(bufp, size, P9_TCLUNK); 819 if (IS_ERR(fc)) 820 goto error; 821 822 p9_put_int32(bufp, fid, &fc->params.tclunk.fid); 823 824 if (buf_check_overflow(bufp)) { 825 kfree(fc); 826 fc = ERR_PTR(-ENOMEM); 827 } 828error: 829 return fc; 830} 831EXPORT_SYMBOL(p9_create_tclunk); 832 833struct p9_fcall *p9_create_tremove(u32 fid) 834{ 835 int size; 836 struct p9_fcall *fc; 837 struct cbuf buffer; 838 struct cbuf *bufp = &buffer; 839 840 size = 4; /* fid[4] */ 841 fc = p9_create_common(bufp, size, P9_TREMOVE); 842 if (IS_ERR(fc)) 843 goto error; 844 845 p9_put_int32(bufp, fid, &fc->params.tremove.fid); 846 847 if (buf_check_overflow(bufp)) { 848 kfree(fc); 849 fc = ERR_PTR(-ENOMEM); 850 } 851error: 852 return fc; 853} 854EXPORT_SYMBOL(p9_create_tremove); 855 856struct p9_fcall *p9_create_tstat(u32 fid) 857{ 858 int size; 859 struct p9_fcall *fc; 860 struct cbuf buffer; 861 struct cbuf *bufp = &buffer; 862 863 size = 4; /* fid[4] */ 864 fc = p9_create_common(bufp, size, P9_TSTAT); 865 if (IS_ERR(fc)) 866 goto error; 867 868 p9_put_int32(bufp, fid, &fc->params.tstat.fid); 869 870 if (buf_check_overflow(bufp)) { 871 kfree(fc); 872 fc = ERR_PTR(-ENOMEM); 873 } 874error: 875 return fc; 876} 877EXPORT_SYMBOL(p9_create_tstat); 878 879struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat, 880 int dotu) 881{ 882 int size, statsz; 883 struct p9_fcall *fc; 884 struct cbuf buffer; 885 struct cbuf *bufp = &buffer; 886 887 statsz = p9_size_wstat(wstat, dotu); 888 size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */ 889 fc = p9_create_common(bufp, size, P9_TWSTAT); 890 if (IS_ERR(fc)) 891 goto error; 892 893 p9_put_int32(bufp, fid, &fc->params.twstat.fid); 894 buf_put_int16(bufp, statsz + 2); 895 p9_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, dotu); 896 897 if (buf_check_overflow(bufp)) { 898 kfree(fc); 899 fc = ERR_PTR(-ENOMEM); 900 } 901error: 902 return fc; 903} 904EXPORT_SYMBOL(p9_create_twstat);