1/* 2 * linux/fs/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 <asm/uaccess.h> 33#include "debug.h" 34#include "v9fs.h" 35#include "9p.h" 36#include "conv.h" 37 38/* 39 * Buffer to help with string parsing 40 */ 41struct cbuf { 42 unsigned char *sp; 43 unsigned char *p; 44 unsigned char *ep; 45}; 46 47static inline void buf_init(struct cbuf *buf, void *data, int datalen) 48{ 49 buf->sp = buf->p = data; 50 buf->ep = data + datalen; 51} 52 53static inline int buf_check_overflow(struct cbuf *buf) 54{ 55 return buf->p > buf->ep; 56} 57 58static int buf_check_size(struct cbuf *buf, int len) 59{ 60 if (buf->p + len > buf->ep) { 61 if (buf->p < buf->ep) { 62 eprintk(KERN_ERR, "buffer overflow: want %d has %d\n", 63 len, (int)(buf->ep - buf->p)); 64 dump_stack(); 65 buf->p = buf->ep + 1; 66 } 67 68 return 0; 69 } 70 71 return 1; 72} 73 74static void *buf_alloc(struct cbuf *buf, int len) 75{ 76 void *ret = NULL; 77 78 if (buf_check_size(buf, len)) { 79 ret = buf->p; 80 buf->p += len; 81 } 82 83 return ret; 84} 85 86static void buf_put_int8(struct cbuf *buf, u8 val) 87{ 88 if (buf_check_size(buf, 1)) { 89 buf->p[0] = val; 90 buf->p++; 91 } 92} 93 94static void buf_put_int16(struct cbuf *buf, u16 val) 95{ 96 if (buf_check_size(buf, 2)) { 97 *(__le16 *) buf->p = cpu_to_le16(val); 98 buf->p += 2; 99 } 100} 101 102static void buf_put_int32(struct cbuf *buf, u32 val) 103{ 104 if (buf_check_size(buf, 4)) { 105 *(__le32 *)buf->p = cpu_to_le32(val); 106 buf->p += 4; 107 } 108} 109 110static void buf_put_int64(struct cbuf *buf, u64 val) 111{ 112 if (buf_check_size(buf, 8)) { 113 *(__le64 *)buf->p = cpu_to_le64(val); 114 buf->p += 8; 115 } 116} 117 118static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen) 119{ 120 char *ret; 121 122 ret = NULL; 123 if (buf_check_size(buf, slen + 2)) { 124 buf_put_int16(buf, slen); 125 ret = buf->p; 126 memcpy(buf->p, s, slen); 127 buf->p += slen; 128 } 129 130 return ret; 131} 132 133static inline void buf_put_string(struct cbuf *buf, const char *s) 134{ 135 buf_put_stringn(buf, s, strlen(s)); 136} 137 138static u8 buf_get_int8(struct cbuf *buf) 139{ 140 u8 ret = 0; 141 142 if (buf_check_size(buf, 1)) { 143 ret = buf->p[0]; 144 buf->p++; 145 } 146 147 return ret; 148} 149 150static u16 buf_get_int16(struct cbuf *buf) 151{ 152 u16 ret = 0; 153 154 if (buf_check_size(buf, 2)) { 155 ret = le16_to_cpu(*(__le16 *)buf->p); 156 buf->p += 2; 157 } 158 159 return ret; 160} 161 162static u32 buf_get_int32(struct cbuf *buf) 163{ 164 u32 ret = 0; 165 166 if (buf_check_size(buf, 4)) { 167 ret = le32_to_cpu(*(__le32 *)buf->p); 168 buf->p += 4; 169 } 170 171 return ret; 172} 173 174static u64 buf_get_int64(struct cbuf *buf) 175{ 176 u64 ret = 0; 177 178 if (buf_check_size(buf, 8)) { 179 ret = le64_to_cpu(*(__le64 *)buf->p); 180 buf->p += 8; 181 } 182 183 return ret; 184} 185 186static void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr) 187{ 188 vstr->len = buf_get_int16(buf); 189 if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) { 190 vstr->str = buf->p; 191 buf->p += vstr->len; 192 } else { 193 vstr->len = 0; 194 vstr->str = NULL; 195 } 196} 197 198static void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid) 199{ 200 qid->type = buf_get_int8(bufp); 201 qid->version = buf_get_int32(bufp); 202 qid->path = buf_get_int64(bufp); 203} 204 205/** 206 * v9fs_size_wstat - calculate the size of a variable length stat struct 207 * @stat: metadata (stat) structure 208 * @extended: non-zero if 9P2000.u 209 * 210 */ 211 212static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended) 213{ 214 int size = 0; 215 216 if (wstat == NULL) { 217 eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n"); 218 return 0; 219 } 220 221 size = /* 2 + *//* size[2] */ 222 2 + /* type[2] */ 223 4 + /* dev[4] */ 224 1 + /* qid.type[1] */ 225 4 + /* qid.vers[4] */ 226 8 + /* qid.path[8] */ 227 4 + /* mode[4] */ 228 4 + /* atime[4] */ 229 4 + /* mtime[4] */ 230 8 + /* length[8] */ 231 8; /* minimum sum of string lengths */ 232 233 if (wstat->name) 234 size += strlen(wstat->name); 235 if (wstat->uid) 236 size += strlen(wstat->uid); 237 if (wstat->gid) 238 size += strlen(wstat->gid); 239 if (wstat->muid) 240 size += strlen(wstat->muid); 241 242 if (extended) { 243 size += 4 + /* n_uid[4] */ 244 4 + /* n_gid[4] */ 245 4 + /* n_muid[4] */ 246 2; /* string length of extension[4] */ 247 if (wstat->extension) 248 size += strlen(wstat->extension); 249 } 250 251 return size; 252} 253 254/** 255 * buf_get_stat - safely decode a recieved metadata (stat) structure 256 * @bufp: buffer to deserialize 257 * @stat: metadata (stat) structure 258 * @extended: non-zero if 9P2000.u 259 * 260 */ 261 262static void 263buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended) 264{ 265 stat->size = buf_get_int16(bufp); 266 stat->type = buf_get_int16(bufp); 267 stat->dev = buf_get_int32(bufp); 268 stat->qid.type = buf_get_int8(bufp); 269 stat->qid.version = buf_get_int32(bufp); 270 stat->qid.path = buf_get_int64(bufp); 271 stat->mode = buf_get_int32(bufp); 272 stat->atime = buf_get_int32(bufp); 273 stat->mtime = buf_get_int32(bufp); 274 stat->length = buf_get_int64(bufp); 275 buf_get_str(bufp, &stat->name); 276 buf_get_str(bufp, &stat->uid); 277 buf_get_str(bufp, &stat->gid); 278 buf_get_str(bufp, &stat->muid); 279 280 if (extended) { 281 buf_get_str(bufp, &stat->extension); 282 stat->n_uid = buf_get_int32(bufp); 283 stat->n_gid = buf_get_int32(bufp); 284 stat->n_muid = buf_get_int32(bufp); 285 } 286} 287 288/** 289 * v9fs_deserialize_stat - decode a received metadata structure 290 * @buf: buffer to deserialize 291 * @buflen: length of received buffer 292 * @stat: metadata structure to decode into 293 * @extended: non-zero if 9P2000.u 294 * 295 * Note: stat will point to the buf region. 296 */ 297 298int 299v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat, 300 int extended) 301{ 302 struct cbuf buffer; 303 struct cbuf *bufp = &buffer; 304 unsigned char *p; 305 306 buf_init(bufp, buf, buflen); 307 p = bufp->p; 308 buf_get_stat(bufp, stat, extended); 309 310 if (buf_check_overflow(bufp)) 311 return 0; 312 else 313 return bufp->p - p; 314} 315 316/** 317 * deserialize_fcall - unmarshal a response 318 * @buf: recieved buffer 319 * @buflen: length of received buffer 320 * @rcall: fcall structure to populate 321 * @rcalllen: length of fcall structure to populate 322 * @extended: non-zero if 9P2000.u 323 * 324 */ 325 326int 327v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, 328 int extended) 329{ 330 331 struct cbuf buffer; 332 struct cbuf *bufp = &buffer; 333 int i = 0; 334 335 buf_init(bufp, buf, buflen); 336 337 rcall->size = buf_get_int32(bufp); 338 rcall->id = buf_get_int8(bufp); 339 rcall->tag = buf_get_int16(bufp); 340 341 dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id, 342 rcall->tag); 343 344 switch (rcall->id) { 345 default: 346 eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id); 347 return -EPROTO; 348 case RVERSION: 349 rcall->params.rversion.msize = buf_get_int32(bufp); 350 buf_get_str(bufp, &rcall->params.rversion.version); 351 break; 352 case RFLUSH: 353 break; 354 case RATTACH: 355 rcall->params.rattach.qid.type = buf_get_int8(bufp); 356 rcall->params.rattach.qid.version = buf_get_int32(bufp); 357 rcall->params.rattach.qid.path = buf_get_int64(bufp); 358 break; 359 case RWALK: 360 rcall->params.rwalk.nwqid = buf_get_int16(bufp); 361 if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) { 362 eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n", 363 V9FS_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 ROPEN: 371 buf_get_qid(bufp, &rcall->params.ropen.qid); 372 rcall->params.ropen.iounit = buf_get_int32(bufp); 373 break; 374 case RCREATE: 375 buf_get_qid(bufp, &rcall->params.rcreate.qid); 376 rcall->params.rcreate.iounit = buf_get_int32(bufp); 377 break; 378 case 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 RWRITE: 384 rcall->params.rwrite.count = buf_get_int32(bufp); 385 break; 386 case RCLUNK: 387 break; 388 case RREMOVE: 389 break; 390 case RSTAT: 391 buf_get_int16(bufp); 392 buf_get_stat(bufp, &rcall->params.rstat.stat, extended); 393 break; 394 case RWSTAT: 395 break; 396 case RERROR: 397 buf_get_str(bufp, &rcall->params.rerror.error); 398 if (extended) 399 rcall->params.rerror.errno = buf_get_int16(bufp); 400 break; 401 } 402 403 if (buf_check_overflow(bufp)) { 404 dprintk(DEBUG_ERROR, "buffer overflow\n"); 405 return -EIO; 406 } 407 408 return bufp->p - bufp->sp; 409} 410 411static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p) 412{ 413 *p = val; 414 buf_put_int8(bufp, val); 415} 416 417static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p) 418{ 419 *p = val; 420 buf_put_int16(bufp, val); 421} 422 423static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p) 424{ 425 *p = val; 426 buf_put_int32(bufp, val); 427} 428 429static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p) 430{ 431 *p = val; 432 buf_put_int64(bufp, val); 433} 434 435static void 436v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str) 437{ 438 int len; 439 char *s; 440 441 if (data) 442 len = strlen(data); 443 else 444 len = 0; 445 446 s = buf_put_stringn(bufp, data, len); 447 if (str) { 448 str->len = len; 449 str->str = s; 450 } 451} 452 453static int 454v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count, 455 unsigned char **pdata) 456{ 457 *pdata = buf_alloc(bufp, count); 458 return copy_from_user(*pdata, data, count); 459} 460 461static void 462v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat, 463 struct v9fs_stat *stat, int statsz, int extended) 464{ 465 v9fs_put_int16(bufp, statsz, &stat->size); 466 v9fs_put_int16(bufp, wstat->type, &stat->type); 467 v9fs_put_int32(bufp, wstat->dev, &stat->dev); 468 v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type); 469 v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version); 470 v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path); 471 v9fs_put_int32(bufp, wstat->mode, &stat->mode); 472 v9fs_put_int32(bufp, wstat->atime, &stat->atime); 473 v9fs_put_int32(bufp, wstat->mtime, &stat->mtime); 474 v9fs_put_int64(bufp, wstat->length, &stat->length); 475 476 v9fs_put_str(bufp, wstat->name, &stat->name); 477 v9fs_put_str(bufp, wstat->uid, &stat->uid); 478 v9fs_put_str(bufp, wstat->gid, &stat->gid); 479 v9fs_put_str(bufp, wstat->muid, &stat->muid); 480 481 if (extended) { 482 v9fs_put_str(bufp, wstat->extension, &stat->extension); 483 v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid); 484 v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid); 485 v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid); 486 } 487} 488 489static struct v9fs_fcall * 490v9fs_create_common(struct cbuf *bufp, u32 size, u8 id) 491{ 492 struct v9fs_fcall *fc; 493 494 size += 4 + 1 + 2; /* size[4] id[1] tag[2] */ 495 fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL); 496 if (!fc) 497 return ERR_PTR(-ENOMEM); 498 499 fc->sdata = (char *)fc + sizeof(*fc); 500 501 buf_init(bufp, (char *)fc->sdata, size); 502 v9fs_put_int32(bufp, size, &fc->size); 503 v9fs_put_int8(bufp, id, &fc->id); 504 v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag); 505 506 return fc; 507} 508 509void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag) 510{ 511 fc->tag = tag; 512 *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag); 513} 514 515struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version) 516{ 517 int size; 518 struct v9fs_fcall *fc; 519 struct cbuf buffer; 520 struct cbuf *bufp = &buffer; 521 522 size = 4 + 2 + strlen(version); /* msize[4] version[s] */ 523 fc = v9fs_create_common(bufp, size, TVERSION); 524 if (IS_ERR(fc)) 525 goto error; 526 527 v9fs_put_int32(bufp, msize, &fc->params.tversion.msize); 528 v9fs_put_str(bufp, version, &fc->params.tversion.version); 529 530 if (buf_check_overflow(bufp)) { 531 kfree(fc); 532 fc = ERR_PTR(-ENOMEM); 533 } 534 error: 535 return fc; 536} 537 538 539struct v9fs_fcall * 540v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname) 541{ 542 int size; 543 struct v9fs_fcall *fc; 544 struct cbuf buffer; 545 struct cbuf *bufp = &buffer; 546 547 size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); /* fid[4] afid[4] uname[s] aname[s] */ 548 fc = v9fs_create_common(bufp, size, TATTACH); 549 if (IS_ERR(fc)) 550 goto error; 551 552 v9fs_put_int32(bufp, fid, &fc->params.tattach.fid); 553 v9fs_put_int32(bufp, afid, &fc->params.tattach.afid); 554 v9fs_put_str(bufp, uname, &fc->params.tattach.uname); 555 v9fs_put_str(bufp, aname, &fc->params.tattach.aname); 556 557 error: 558 return fc; 559} 560 561struct v9fs_fcall *v9fs_create_tflush(u16 oldtag) 562{ 563 int size; 564 struct v9fs_fcall *fc; 565 struct cbuf buffer; 566 struct cbuf *bufp = &buffer; 567 568 size = 2; /* oldtag[2] */ 569 fc = v9fs_create_common(bufp, size, TFLUSH); 570 if (IS_ERR(fc)) 571 goto error; 572 573 v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag); 574 575 if (buf_check_overflow(bufp)) { 576 kfree(fc); 577 fc = ERR_PTR(-ENOMEM); 578 } 579 error: 580 return fc; 581} 582 583struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname, 584 char **wnames) 585{ 586 int i, size; 587 struct v9fs_fcall *fc; 588 struct cbuf buffer; 589 struct cbuf *bufp = &buffer; 590 591 if (nwname > V9FS_MAXWELEM) { 592 dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM); 593 return NULL; 594 } 595 596 size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */ 597 for (i = 0; i < nwname; i++) { 598 size += 2 + strlen(wnames[i]); /* wname[s] */ 599 } 600 601 fc = v9fs_create_common(bufp, size, TWALK); 602 if (IS_ERR(fc)) 603 goto error; 604 605 v9fs_put_int32(bufp, fid, &fc->params.twalk.fid); 606 v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid); 607 v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname); 608 for (i = 0; i < nwname; i++) { 609 v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]); 610 } 611 612 if (buf_check_overflow(bufp)) { 613 kfree(fc); 614 fc = ERR_PTR(-ENOMEM); 615 } 616 error: 617 return fc; 618} 619 620struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode) 621{ 622 int size; 623 struct v9fs_fcall *fc; 624 struct cbuf buffer; 625 struct cbuf *bufp = &buffer; 626 627 size = 4 + 1; /* fid[4] mode[1] */ 628 fc = v9fs_create_common(bufp, size, TOPEN); 629 if (IS_ERR(fc)) 630 goto error; 631 632 v9fs_put_int32(bufp, fid, &fc->params.topen.fid); 633 v9fs_put_int8(bufp, mode, &fc->params.topen.mode); 634 635 if (buf_check_overflow(bufp)) { 636 kfree(fc); 637 fc = ERR_PTR(-ENOMEM); 638 } 639 error: 640 return fc; 641} 642 643struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode, 644 char *extension, int extended) 645{ 646 int size; 647 struct v9fs_fcall *fc; 648 struct cbuf buffer; 649 struct cbuf *bufp = &buffer; 650 651 size = 4 + 2 + strlen(name) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */ 652 if (extended) { 653 size += 2 + /* extension[s] */ 654 (extension == NULL ? 0 : strlen(extension)); 655 } 656 657 fc = v9fs_create_common(bufp, size, TCREATE); 658 if (IS_ERR(fc)) 659 goto error; 660 661 v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid); 662 v9fs_put_str(bufp, name, &fc->params.tcreate.name); 663 v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm); 664 v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode); 665 if (extended) 666 v9fs_put_str(bufp, extension, &fc->params.tcreate.extension); 667 668 if (buf_check_overflow(bufp)) { 669 kfree(fc); 670 fc = ERR_PTR(-ENOMEM); 671 } 672 error: 673 return fc; 674} 675 676struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count) 677{ 678 int size; 679 struct v9fs_fcall *fc; 680 struct cbuf buffer; 681 struct cbuf *bufp = &buffer; 682 683 size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */ 684 fc = v9fs_create_common(bufp, size, TREAD); 685 if (IS_ERR(fc)) 686 goto error; 687 688 v9fs_put_int32(bufp, fid, &fc->params.tread.fid); 689 v9fs_put_int64(bufp, offset, &fc->params.tread.offset); 690 v9fs_put_int32(bufp, count, &fc->params.tread.count); 691 692 if (buf_check_overflow(bufp)) { 693 kfree(fc); 694 fc = ERR_PTR(-ENOMEM); 695 } 696 error: 697 return fc; 698} 699 700struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count, 701 const char __user * data) 702{ 703 int size, err; 704 struct v9fs_fcall *fc; 705 struct cbuf buffer; 706 struct cbuf *bufp = &buffer; 707 708 size = 4 + 8 + 4 + count; /* fid[4] offset[8] count[4] data[count] */ 709 fc = v9fs_create_common(bufp, size, TWRITE); 710 if (IS_ERR(fc)) 711 goto error; 712 713 v9fs_put_int32(bufp, fid, &fc->params.twrite.fid); 714 v9fs_put_int64(bufp, offset, &fc->params.twrite.offset); 715 v9fs_put_int32(bufp, count, &fc->params.twrite.count); 716 err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data); 717 if (err) { 718 kfree(fc); 719 fc = ERR_PTR(err); 720 } 721 722 if (buf_check_overflow(bufp)) { 723 kfree(fc); 724 fc = ERR_PTR(-ENOMEM); 725 } 726 error: 727 return fc; 728} 729 730struct v9fs_fcall *v9fs_create_tclunk(u32 fid) 731{ 732 int size; 733 struct v9fs_fcall *fc; 734 struct cbuf buffer; 735 struct cbuf *bufp = &buffer; 736 737 size = 4; /* fid[4] */ 738 fc = v9fs_create_common(bufp, size, TCLUNK); 739 if (IS_ERR(fc)) 740 goto error; 741 742 v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid); 743 744 if (buf_check_overflow(bufp)) { 745 kfree(fc); 746 fc = ERR_PTR(-ENOMEM); 747 } 748 error: 749 return fc; 750} 751 752struct v9fs_fcall *v9fs_create_tremove(u32 fid) 753{ 754 int size; 755 struct v9fs_fcall *fc; 756 struct cbuf buffer; 757 struct cbuf *bufp = &buffer; 758 759 size = 4; /* fid[4] */ 760 fc = v9fs_create_common(bufp, size, TREMOVE); 761 if (IS_ERR(fc)) 762 goto error; 763 764 v9fs_put_int32(bufp, fid, &fc->params.tremove.fid); 765 766 if (buf_check_overflow(bufp)) { 767 kfree(fc); 768 fc = ERR_PTR(-ENOMEM); 769 } 770 error: 771 return fc; 772} 773 774struct v9fs_fcall *v9fs_create_tstat(u32 fid) 775{ 776 int size; 777 struct v9fs_fcall *fc; 778 struct cbuf buffer; 779 struct cbuf *bufp = &buffer; 780 781 size = 4; /* fid[4] */ 782 fc = v9fs_create_common(bufp, size, TSTAT); 783 if (IS_ERR(fc)) 784 goto error; 785 786 v9fs_put_int32(bufp, fid, &fc->params.tstat.fid); 787 788 if (buf_check_overflow(bufp)) { 789 kfree(fc); 790 fc = ERR_PTR(-ENOMEM); 791 } 792 error: 793 return fc; 794} 795 796struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat, 797 int extended) 798{ 799 int size, statsz; 800 struct v9fs_fcall *fc; 801 struct cbuf buffer; 802 struct cbuf *bufp = &buffer; 803 804 statsz = v9fs_size_wstat(wstat, extended); 805 size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */ 806 fc = v9fs_create_common(bufp, size, TWSTAT); 807 if (IS_ERR(fc)) 808 goto error; 809 810 v9fs_put_int32(bufp, fid, &fc->params.twstat.fid); 811 buf_put_int16(bufp, statsz + 2); 812 v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended); 813 814 if (buf_check_overflow(bufp)) { 815 kfree(fc); 816 fc = ERR_PTR(-ENOMEM); 817 } 818 error: 819 return fc; 820} 821