at v2.6.27 1054 lines 24 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 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