1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * XDR support for nfsd/protocol version 3. 4 * 5 * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> 6 * 7 * 2003-08-09 Jamie Lokier: Use htonl() for nanoseconds, not htons()! 8 */ 9 10 #include <linux/namei.h> 11 #include <linux/sunrpc/svc_xprt.h> 12 #include "xdr3.h" 13 #include "auth.h" 14 #include "netns.h" 15 #include "vfs.h" 16 17 /* 18 * Force construction of an empty post-op attr 19 */ 20 static const struct svc_fh nfs3svc_null_fh = { 21 .fh_no_wcc = true, 22 }; 23 24 /* 25 * time_delta. {1, 0} means the server is accurate only 26 * to the nearest second. 27 */ 28 static const struct timespec64 nfs3svc_time_delta = { 29 .tv_sec = 1, 30 .tv_nsec = 0, 31 }; 32 33 /* 34 * Mapping of S_IF* types to NFS file types 35 */ 36 static const u32 nfs3_ftypes[] = { 37 NF3NON, NF3FIFO, NF3CHR, NF3BAD, 38 NF3DIR, NF3BAD, NF3BLK, NF3BAD, 39 NF3REG, NF3BAD, NF3LNK, NF3BAD, 40 NF3SOCK, NF3BAD, NF3LNK, NF3BAD, 41 }; 42 43 44 /* 45 * Basic NFSv3 data types (RFC 1813 Sections 2.5 and 2.6) 46 */ 47 48 static __be32 * 49 encode_nfstime3(__be32 *p, const struct timespec64 *time) 50 { 51 *p++ = cpu_to_be32((u32)time->tv_sec); 52 *p++ = cpu_to_be32(time->tv_nsec); 53 54 return p; 55 } 56 57 static bool 58 svcxdr_decode_nfstime3(struct xdr_stream *xdr, struct timespec64 *timep) 59 { 60 __be32 *p; 61 62 p = xdr_inline_decode(xdr, XDR_UNIT * 2); 63 if (!p) 64 return false; 65 timep->tv_sec = be32_to_cpup(p++); 66 timep->tv_nsec = be32_to_cpup(p); 67 68 return true; 69 } 70 71 /** 72 * svcxdr_decode_nfs_fh3 - Decode an NFSv3 file handle 73 * @xdr: XDR stream positioned at an undecoded NFSv3 FH 74 * @fhp: OUT: filled-in server file handle 75 * 76 * Return values: 77 * %false: The encoded file handle was not valid 78 * %true: @fhp has been initialized 79 */ 80 bool 81 svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp) 82 { 83 __be32 *p; 84 u32 size; 85 86 if (xdr_stream_decode_u32(xdr, &size) < 0) 87 return false; 88 if (size == 0 || size > NFS3_FHSIZE) 89 return false; 90 p = xdr_inline_decode(xdr, size); 91 if (!p) 92 return false; 93 fh_init(fhp, NFS3_FHSIZE); 94 fhp->fh_handle.fh_size = size; 95 memcpy(&fhp->fh_handle.fh_base, p, size); 96 97 return true; 98 } 99 100 /** 101 * svcxdr_encode_nfsstat3 - Encode an NFSv3 status code 102 * @xdr: XDR stream 103 * @status: status value to encode 104 * 105 * Return values: 106 * %false: Send buffer space was exhausted 107 * %true: Success 108 */ 109 bool 110 svcxdr_encode_nfsstat3(struct xdr_stream *xdr, __be32 status) 111 { 112 __be32 *p; 113 114 p = xdr_reserve_space(xdr, sizeof(status)); 115 if (!p) 116 return false; 117 *p = status; 118 119 return true; 120 } 121 122 static bool 123 svcxdr_encode_nfs_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp) 124 { 125 u32 size = fhp->fh_handle.fh_size; 126 __be32 *p; 127 128 p = xdr_reserve_space(xdr, XDR_UNIT + size); 129 if (!p) 130 return false; 131 *p++ = cpu_to_be32(size); 132 if (size) 133 p[XDR_QUADLEN(size) - 1] = 0; 134 memcpy(p, &fhp->fh_handle.fh_base, size); 135 136 return true; 137 } 138 139 static bool 140 svcxdr_encode_post_op_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp) 141 { 142 if (xdr_stream_encode_item_present(xdr) < 0) 143 return false; 144 if (!svcxdr_encode_nfs_fh3(xdr, fhp)) 145 return false; 146 147 return true; 148 } 149 150 static bool 151 svcxdr_encode_cookieverf3(struct xdr_stream *xdr, const __be32 *verf) 152 { 153 __be32 *p; 154 155 p = xdr_reserve_space(xdr, NFS3_COOKIEVERFSIZE); 156 if (!p) 157 return false; 158 memcpy(p, verf, NFS3_COOKIEVERFSIZE); 159 160 return true; 161 } 162 163 static bool 164 svcxdr_encode_writeverf3(struct xdr_stream *xdr, const __be32 *verf) 165 { 166 __be32 *p; 167 168 p = xdr_reserve_space(xdr, NFS3_WRITEVERFSIZE); 169 if (!p) 170 return false; 171 memcpy(p, verf, NFS3_WRITEVERFSIZE); 172 173 return true; 174 } 175 176 static bool 177 svcxdr_decode_filename3(struct xdr_stream *xdr, char **name, unsigned int *len) 178 { 179 u32 size, i; 180 __be32 *p; 181 char *c; 182 183 if (xdr_stream_decode_u32(xdr, &size) < 0) 184 return false; 185 if (size == 0 || size > NFS3_MAXNAMLEN) 186 return false; 187 p = xdr_inline_decode(xdr, size); 188 if (!p) 189 return false; 190 191 *len = size; 192 *name = (char *)p; 193 for (i = 0, c = *name; i < size; i++, c++) { 194 if (*c == '\0' || *c == '/') 195 return false; 196 } 197 198 return true; 199 } 200 201 static bool 202 svcxdr_decode_diropargs3(struct xdr_stream *xdr, struct svc_fh *fhp, 203 char **name, unsigned int *len) 204 { 205 return svcxdr_decode_nfs_fh3(xdr, fhp) && 206 svcxdr_decode_filename3(xdr, name, len); 207 } 208 209 static bool 210 svcxdr_decode_sattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr, 211 struct iattr *iap) 212 { 213 u32 set_it; 214 215 iap->ia_valid = 0; 216 217 if (xdr_stream_decode_bool(xdr, &set_it) < 0) 218 return false; 219 if (set_it) { 220 u32 mode; 221 222 if (xdr_stream_decode_u32(xdr, &mode) < 0) 223 return false; 224 iap->ia_valid |= ATTR_MODE; 225 iap->ia_mode = mode; 226 } 227 if (xdr_stream_decode_bool(xdr, &set_it) < 0) 228 return false; 229 if (set_it) { 230 u32 uid; 231 232 if (xdr_stream_decode_u32(xdr, &uid) < 0) 233 return false; 234 iap->ia_uid = make_kuid(nfsd_user_namespace(rqstp), uid); 235 if (uid_valid(iap->ia_uid)) 236 iap->ia_valid |= ATTR_UID; 237 } 238 if (xdr_stream_decode_bool(xdr, &set_it) < 0) 239 return false; 240 if (set_it) { 241 u32 gid; 242 243 if (xdr_stream_decode_u32(xdr, &gid) < 0) 244 return false; 245 iap->ia_gid = make_kgid(nfsd_user_namespace(rqstp), gid); 246 if (gid_valid(iap->ia_gid)) 247 iap->ia_valid |= ATTR_GID; 248 } 249 if (xdr_stream_decode_bool(xdr, &set_it) < 0) 250 return false; 251 if (set_it) { 252 u64 newsize; 253 254 if (xdr_stream_decode_u64(xdr, &newsize) < 0) 255 return false; 256 iap->ia_valid |= ATTR_SIZE; 257 iap->ia_size = min_t(u64, newsize, NFS_OFFSET_MAX); 258 } 259 if (xdr_stream_decode_u32(xdr, &set_it) < 0) 260 return false; 261 switch (set_it) { 262 case DONT_CHANGE: 263 break; 264 case SET_TO_SERVER_TIME: 265 iap->ia_valid |= ATTR_ATIME; 266 break; 267 case SET_TO_CLIENT_TIME: 268 if (!svcxdr_decode_nfstime3(xdr, &iap->ia_atime)) 269 return false; 270 iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET; 271 break; 272 default: 273 return false; 274 } 275 if (xdr_stream_decode_u32(xdr, &set_it) < 0) 276 return false; 277 switch (set_it) { 278 case DONT_CHANGE: 279 break; 280 case SET_TO_SERVER_TIME: 281 iap->ia_valid |= ATTR_MTIME; 282 break; 283 case SET_TO_CLIENT_TIME: 284 if (!svcxdr_decode_nfstime3(xdr, &iap->ia_mtime)) 285 return false; 286 iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET; 287 break; 288 default: 289 return false; 290 } 291 292 return true; 293 } 294 295 static bool 296 svcxdr_decode_sattrguard3(struct xdr_stream *xdr, struct nfsd3_sattrargs *args) 297 { 298 __be32 *p; 299 u32 check; 300 301 if (xdr_stream_decode_bool(xdr, &check) < 0) 302 return false; 303 if (check) { 304 p = xdr_inline_decode(xdr, XDR_UNIT * 2); 305 if (!p) 306 return false; 307 args->check_guard = 1; 308 args->guardtime = be32_to_cpup(p); 309 } else 310 args->check_guard = 0; 311 312 return true; 313 } 314 315 static bool 316 svcxdr_decode_specdata3(struct xdr_stream *xdr, struct nfsd3_mknodargs *args) 317 { 318 __be32 *p; 319 320 p = xdr_inline_decode(xdr, XDR_UNIT * 2); 321 if (!p) 322 return false; 323 args->major = be32_to_cpup(p++); 324 args->minor = be32_to_cpup(p); 325 326 return true; 327 } 328 329 static bool 330 svcxdr_decode_devicedata3(struct svc_rqst *rqstp, struct xdr_stream *xdr, 331 struct nfsd3_mknodargs *args) 332 { 333 return svcxdr_decode_sattr3(rqstp, xdr, &args->attrs) && 334 svcxdr_decode_specdata3(xdr, args); 335 } 336 337 static bool 338 svcxdr_encode_fattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr, 339 const struct svc_fh *fhp, const struct kstat *stat) 340 { 341 struct user_namespace *userns = nfsd_user_namespace(rqstp); 342 __be32 *p; 343 u64 fsid; 344 345 p = xdr_reserve_space(xdr, XDR_UNIT * 21); 346 if (!p) 347 return false; 348 349 *p++ = cpu_to_be32(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]); 350 *p++ = cpu_to_be32((u32)(stat->mode & S_IALLUGO)); 351 *p++ = cpu_to_be32((u32)stat->nlink); 352 *p++ = cpu_to_be32((u32)from_kuid_munged(userns, stat->uid)); 353 *p++ = cpu_to_be32((u32)from_kgid_munged(userns, stat->gid)); 354 if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) 355 p = xdr_encode_hyper(p, (u64)NFS3_MAXPATHLEN); 356 else 357 p = xdr_encode_hyper(p, (u64)stat->size); 358 359 /* used */ 360 p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9); 361 362 /* rdev */ 363 *p++ = cpu_to_be32((u32)MAJOR(stat->rdev)); 364 *p++ = cpu_to_be32((u32)MINOR(stat->rdev)); 365 366 switch(fsid_source(fhp)) { 367 case FSIDSOURCE_FSID: 368 fsid = (u64)fhp->fh_export->ex_fsid; 369 break; 370 case FSIDSOURCE_UUID: 371 fsid = ((u64 *)fhp->fh_export->ex_uuid)[0]; 372 fsid ^= ((u64 *)fhp->fh_export->ex_uuid)[1]; 373 break; 374 default: 375 fsid = (u64)huge_encode_dev(fhp->fh_dentry->d_sb->s_dev); 376 } 377 p = xdr_encode_hyper(p, fsid); 378 379 /* fileid */ 380 p = xdr_encode_hyper(p, stat->ino); 381 382 p = encode_nfstime3(p, &stat->atime); 383 p = encode_nfstime3(p, &stat->mtime); 384 encode_nfstime3(p, &stat->ctime); 385 386 return true; 387 } 388 389 static bool 390 svcxdr_encode_wcc_attr(struct xdr_stream *xdr, const struct svc_fh *fhp) 391 { 392 __be32 *p; 393 394 p = xdr_reserve_space(xdr, XDR_UNIT * 6); 395 if (!p) 396 return false; 397 p = xdr_encode_hyper(p, (u64)fhp->fh_pre_size); 398 p = encode_nfstime3(p, &fhp->fh_pre_mtime); 399 encode_nfstime3(p, &fhp->fh_pre_ctime); 400 401 return true; 402 } 403 404 static bool 405 svcxdr_encode_pre_op_attr(struct xdr_stream *xdr, const struct svc_fh *fhp) 406 { 407 if (!fhp->fh_pre_saved) { 408 if (xdr_stream_encode_item_absent(xdr) < 0) 409 return false; 410 return true; 411 } 412 413 if (xdr_stream_encode_item_present(xdr) < 0) 414 return false; 415 return svcxdr_encode_wcc_attr(xdr, fhp); 416 } 417 418 /** 419 * svcxdr_encode_post_op_attr - Encode NFSv3 post-op attributes 420 * @rqstp: Context of a completed RPC transaction 421 * @xdr: XDR stream 422 * @fhp: File handle to encode 423 * 424 * Return values: 425 * %false: Send buffer space was exhausted 426 * %true: Success 427 */ 428 bool 429 svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr, 430 const struct svc_fh *fhp) 431 { 432 struct dentry *dentry = fhp->fh_dentry; 433 struct kstat stat; 434 435 /* 436 * The inode may be NULL if the call failed because of a 437 * stale file handle. In this case, no attributes are 438 * returned. 439 */ 440 if (fhp->fh_no_wcc || !dentry || !d_really_is_positive(dentry)) 441 goto no_post_op_attrs; 442 if (fh_getattr(fhp, &stat) != nfs_ok) 443 goto no_post_op_attrs; 444 445 if (xdr_stream_encode_item_present(xdr) < 0) 446 return false; 447 lease_get_mtime(d_inode(dentry), &stat.mtime); 448 if (!svcxdr_encode_fattr3(rqstp, xdr, fhp, &stat)) 449 return false; 450 451 return true; 452 453 no_post_op_attrs: 454 return xdr_stream_encode_item_absent(xdr) > 0; 455 } 456 457 /* 458 * Encode weak cache consistency data 459 */ 460 static bool 461 svcxdr_encode_wcc_data(struct svc_rqst *rqstp, struct xdr_stream *xdr, 462 const struct svc_fh *fhp) 463 { 464 struct dentry *dentry = fhp->fh_dentry; 465 466 if (!dentry || !d_really_is_positive(dentry) || !fhp->fh_post_saved) 467 goto neither; 468 469 /* before */ 470 if (!svcxdr_encode_pre_op_attr(xdr, fhp)) 471 return false; 472 473 /* after */ 474 if (xdr_stream_encode_item_present(xdr) < 0) 475 return false; 476 if (!svcxdr_encode_fattr3(rqstp, xdr, fhp, &fhp->fh_post_attr)) 477 return false; 478 479 return true; 480 481 neither: 482 if (xdr_stream_encode_item_absent(xdr) < 0) 483 return false; 484 if (!svcxdr_encode_post_op_attr(rqstp, xdr, fhp)) 485 return false; 486 487 return true; 488 } 489 490 static bool fs_supports_change_attribute(struct super_block *sb) 491 { 492 return sb->s_flags & SB_I_VERSION || sb->s_export_op->fetch_iversion; 493 } 494 495 /* 496 * Fill in the pre_op attr for the wcc data 497 */ 498 void fill_pre_wcc(struct svc_fh *fhp) 499 { 500 struct inode *inode; 501 struct kstat stat; 502 bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); 503 504 if (fhp->fh_no_wcc || fhp->fh_pre_saved) 505 return; 506 inode = d_inode(fhp->fh_dentry); 507 if (fs_supports_change_attribute(inode->i_sb) || !v4) { 508 __be32 err = fh_getattr(fhp, &stat); 509 510 if (err) { 511 /* Grab the times from inode anyway */ 512 stat.mtime = inode->i_mtime; 513 stat.ctime = inode->i_ctime; 514 stat.size = inode->i_size; 515 } 516 fhp->fh_pre_mtime = stat.mtime; 517 fhp->fh_pre_ctime = stat.ctime; 518 fhp->fh_pre_size = stat.size; 519 } 520 if (v4) 521 fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode); 522 523 fhp->fh_pre_saved = true; 524 } 525 526 /* 527 * Fill in the post_op attr for the wcc data 528 */ 529 void fill_post_wcc(struct svc_fh *fhp) 530 { 531 bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); 532 struct inode *inode = d_inode(fhp->fh_dentry); 533 534 if (fhp->fh_no_wcc) 535 return; 536 537 if (fhp->fh_post_saved) 538 printk("nfsd: inode locked twice during operation.\n"); 539 540 fhp->fh_post_saved = true; 541 542 if (fs_supports_change_attribute(inode->i_sb) || !v4) { 543 __be32 err = fh_getattr(fhp, &fhp->fh_post_attr); 544 545 if (err) { 546 fhp->fh_post_saved = false; 547 fhp->fh_post_attr.ctime = inode->i_ctime; 548 } 549 } 550 if (v4) 551 fhp->fh_post_change = 552 nfsd4_change_attribute(&fhp->fh_post_attr, inode); 553 } 554 555 /* 556 * XDR decode functions 557 */ 558 559 int 560 nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p) 561 { 562 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 563 struct nfsd_fhandle *args = rqstp->rq_argp; 564 565 return svcxdr_decode_nfs_fh3(xdr, &args->fh); 566 } 567 568 int 569 nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p) 570 { 571 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 572 struct nfsd3_sattrargs *args = rqstp->rq_argp; 573 574 return svcxdr_decode_nfs_fh3(xdr, &args->fh) && 575 svcxdr_decode_sattr3(rqstp, xdr, &args->attrs) && 576 svcxdr_decode_sattrguard3(xdr, args); 577 } 578 579 int 580 nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p) 581 { 582 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 583 struct nfsd3_diropargs *args = rqstp->rq_argp; 584 585 return svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len); 586 } 587 588 int 589 nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p) 590 { 591 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 592 struct nfsd3_accessargs *args = rqstp->rq_argp; 593 594 if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) 595 return 0; 596 if (xdr_stream_decode_u32(xdr, &args->access) < 0) 597 return 0; 598 599 return 1; 600 } 601 602 int 603 nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p) 604 { 605 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 606 struct nfsd3_readargs *args = rqstp->rq_argp; 607 608 if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) 609 return 0; 610 if (xdr_stream_decode_u64(xdr, &args->offset) < 0) 611 return 0; 612 if (xdr_stream_decode_u32(xdr, &args->count) < 0) 613 return 0; 614 615 return 1; 616 } 617 618 int 619 nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) 620 { 621 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 622 struct nfsd3_writeargs *args = rqstp->rq_argp; 623 u32 max_blocksize = svc_max_payload(rqstp); 624 struct kvec *head = rqstp->rq_arg.head; 625 struct kvec *tail = rqstp->rq_arg.tail; 626 size_t remaining; 627 628 if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) 629 return 0; 630 if (xdr_stream_decode_u64(xdr, &args->offset) < 0) 631 return 0; 632 if (xdr_stream_decode_u32(xdr, &args->count) < 0) 633 return 0; 634 if (xdr_stream_decode_u32(xdr, &args->stable) < 0) 635 return 0; 636 637 /* opaque data */ 638 if (xdr_stream_decode_u32(xdr, &args->len) < 0) 639 return 0; 640 641 /* request sanity */ 642 if (args->count != args->len) 643 return 0; 644 remaining = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len; 645 remaining -= xdr_stream_pos(xdr); 646 if (remaining < xdr_align_size(args->len)) 647 return 0; 648 if (args->count > max_blocksize) { 649 args->count = max_blocksize; 650 args->len = max_blocksize; 651 } 652 653 args->first.iov_base = xdr->p; 654 args->first.iov_len = head->iov_len - xdr_stream_pos(xdr); 655 656 return 1; 657 } 658 659 int 660 nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p) 661 { 662 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 663 struct nfsd3_createargs *args = rqstp->rq_argp; 664 665 if (!svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len)) 666 return 0; 667 if (xdr_stream_decode_u32(xdr, &args->createmode) < 0) 668 return 0; 669 switch (args->createmode) { 670 case NFS3_CREATE_UNCHECKED: 671 case NFS3_CREATE_GUARDED: 672 return svcxdr_decode_sattr3(rqstp, xdr, &args->attrs); 673 case NFS3_CREATE_EXCLUSIVE: 674 args->verf = xdr_inline_decode(xdr, NFS3_CREATEVERFSIZE); 675 if (!args->verf) 676 return 0; 677 break; 678 default: 679 return 0; 680 } 681 return 1; 682 } 683 684 int 685 nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p) 686 { 687 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 688 struct nfsd3_createargs *args = rqstp->rq_argp; 689 690 return svcxdr_decode_diropargs3(xdr, &args->fh, 691 &args->name, &args->len) && 692 svcxdr_decode_sattr3(rqstp, xdr, &args->attrs); 693 } 694 695 int 696 nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p) 697 { 698 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 699 struct nfsd3_symlinkargs *args = rqstp->rq_argp; 700 struct kvec *head = rqstp->rq_arg.head; 701 struct kvec *tail = rqstp->rq_arg.tail; 702 size_t remaining; 703 704 if (!svcxdr_decode_diropargs3(xdr, &args->ffh, &args->fname, &args->flen)) 705 return 0; 706 if (!svcxdr_decode_sattr3(rqstp, xdr, &args->attrs)) 707 return 0; 708 if (xdr_stream_decode_u32(xdr, &args->tlen) < 0) 709 return 0; 710 711 /* request sanity */ 712 remaining = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len; 713 remaining -= xdr_stream_pos(xdr); 714 if (remaining < xdr_align_size(args->tlen)) 715 return 0; 716 717 args->first.iov_base = xdr->p; 718 args->first.iov_len = head->iov_len - xdr_stream_pos(xdr); 719 720 return 1; 721 } 722 723 int 724 nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p) 725 { 726 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 727 struct nfsd3_mknodargs *args = rqstp->rq_argp; 728 729 if (!svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len)) 730 return 0; 731 if (xdr_stream_decode_u32(xdr, &args->ftype) < 0) 732 return 0; 733 switch (args->ftype) { 734 case NF3CHR: 735 case NF3BLK: 736 return svcxdr_decode_devicedata3(rqstp, xdr, args); 737 case NF3SOCK: 738 case NF3FIFO: 739 return svcxdr_decode_sattr3(rqstp, xdr, &args->attrs); 740 case NF3REG: 741 case NF3DIR: 742 case NF3LNK: 743 /* Valid XDR but illegal file types */ 744 break; 745 default: 746 return 0; 747 } 748 749 return 1; 750 } 751 752 int 753 nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p) 754 { 755 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 756 struct nfsd3_renameargs *args = rqstp->rq_argp; 757 758 return svcxdr_decode_diropargs3(xdr, &args->ffh, 759 &args->fname, &args->flen) && 760 svcxdr_decode_diropargs3(xdr, &args->tfh, 761 &args->tname, &args->tlen); 762 } 763 764 int 765 nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p) 766 { 767 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 768 struct nfsd3_linkargs *args = rqstp->rq_argp; 769 770 return svcxdr_decode_nfs_fh3(xdr, &args->ffh) && 771 svcxdr_decode_diropargs3(xdr, &args->tfh, 772 &args->tname, &args->tlen); 773 } 774 775 int 776 nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) 777 { 778 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 779 struct nfsd3_readdirargs *args = rqstp->rq_argp; 780 781 if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) 782 return 0; 783 if (xdr_stream_decode_u64(xdr, &args->cookie) < 0) 784 return 0; 785 args->verf = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE); 786 if (!args->verf) 787 return 0; 788 if (xdr_stream_decode_u32(xdr, &args->count) < 0) 789 return 0; 790 791 return 1; 792 } 793 794 int 795 nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p) 796 { 797 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 798 struct nfsd3_readdirargs *args = rqstp->rq_argp; 799 u32 dircount; 800 801 if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) 802 return 0; 803 if (xdr_stream_decode_u64(xdr, &args->cookie) < 0) 804 return 0; 805 args->verf = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE); 806 if (!args->verf) 807 return 0; 808 /* dircount is ignored */ 809 if (xdr_stream_decode_u32(xdr, &dircount) < 0) 810 return 0; 811 if (xdr_stream_decode_u32(xdr, &args->count) < 0) 812 return 0; 813 814 return 1; 815 } 816 817 int 818 nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p) 819 { 820 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 821 struct nfsd3_commitargs *args = rqstp->rq_argp; 822 823 if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) 824 return 0; 825 if (xdr_stream_decode_u64(xdr, &args->offset) < 0) 826 return 0; 827 if (xdr_stream_decode_u32(xdr, &args->count) < 0) 828 return 0; 829 830 return 1; 831 } 832 833 /* 834 * XDR encode functions 835 */ 836 837 /* GETATTR */ 838 int 839 nfs3svc_encode_getattrres(struct svc_rqst *rqstp, __be32 *p) 840 { 841 struct xdr_stream *xdr = &rqstp->rq_res_stream; 842 struct nfsd3_attrstat *resp = rqstp->rq_resp; 843 844 if (!svcxdr_encode_nfsstat3(xdr, resp->status)) 845 return 0; 846 switch (resp->status) { 847 case nfs_ok: 848 lease_get_mtime(d_inode(resp->fh.fh_dentry), &resp->stat.mtime); 849 if (!svcxdr_encode_fattr3(rqstp, xdr, &resp->fh, &resp->stat)) 850 return 0; 851 break; 852 } 853 854 return 1; 855 } 856 857 /* SETATTR, REMOVE, RMDIR */ 858 int 859 nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p) 860 { 861 struct xdr_stream *xdr = &rqstp->rq_res_stream; 862 struct nfsd3_attrstat *resp = rqstp->rq_resp; 863 864 return svcxdr_encode_nfsstat3(xdr, resp->status) && 865 svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh); 866 } 867 868 /* LOOKUP */ 869 int nfs3svc_encode_lookupres(struct svc_rqst *rqstp, __be32 *p) 870 { 871 struct xdr_stream *xdr = &rqstp->rq_res_stream; 872 struct nfsd3_diropres *resp = rqstp->rq_resp; 873 874 if (!svcxdr_encode_nfsstat3(xdr, resp->status)) 875 return 0; 876 switch (resp->status) { 877 case nfs_ok: 878 if (!svcxdr_encode_nfs_fh3(xdr, &resp->fh)) 879 return 0; 880 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) 881 return 0; 882 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->dirfh)) 883 return 0; 884 break; 885 default: 886 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->dirfh)) 887 return 0; 888 } 889 890 return 1; 891 } 892 893 /* ACCESS */ 894 int 895 nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) 896 { 897 struct xdr_stream *xdr = &rqstp->rq_res_stream; 898 struct nfsd3_accessres *resp = rqstp->rq_resp; 899 900 if (!svcxdr_encode_nfsstat3(xdr, resp->status)) 901 return 0; 902 switch (resp->status) { 903 case nfs_ok: 904 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) 905 return 0; 906 if (xdr_stream_encode_u32(xdr, resp->access) < 0) 907 return 0; 908 break; 909 default: 910 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) 911 return 0; 912 } 913 914 return 1; 915 } 916 917 /* READLINK */ 918 int 919 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) 920 { 921 struct xdr_stream *xdr = &rqstp->rq_res_stream; 922 struct nfsd3_readlinkres *resp = rqstp->rq_resp; 923 struct kvec *head = rqstp->rq_res.head; 924 925 if (!svcxdr_encode_nfsstat3(xdr, resp->status)) 926 return 0; 927 switch (resp->status) { 928 case nfs_ok: 929 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) 930 return 0; 931 if (xdr_stream_encode_u32(xdr, resp->len) < 0) 932 return 0; 933 xdr_write_pages(xdr, resp->pages, 0, resp->len); 934 if (svc_encode_result_payload(rqstp, head->iov_len, resp->len) < 0) 935 return 0; 936 break; 937 default: 938 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) 939 return 0; 940 } 941 942 return 1; 943 } 944 945 /* READ */ 946 int 947 nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p) 948 { 949 struct xdr_stream *xdr = &rqstp->rq_res_stream; 950 struct nfsd3_readres *resp = rqstp->rq_resp; 951 struct kvec *head = rqstp->rq_res.head; 952 953 if (!svcxdr_encode_nfsstat3(xdr, resp->status)) 954 return 0; 955 switch (resp->status) { 956 case nfs_ok: 957 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) 958 return 0; 959 if (xdr_stream_encode_u32(xdr, resp->count) < 0) 960 return 0; 961 if (xdr_stream_encode_bool(xdr, resp->eof) < 0) 962 return 0; 963 if (xdr_stream_encode_u32(xdr, resp->count) < 0) 964 return 0; 965 xdr_write_pages(xdr, resp->pages, rqstp->rq_res.page_base, 966 resp->count); 967 if (svc_encode_result_payload(rqstp, head->iov_len, resp->count) < 0) 968 return 0; 969 break; 970 default: 971 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) 972 return 0; 973 } 974 975 return 1; 976 } 977 978 /* WRITE */ 979 int 980 nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p) 981 { 982 struct xdr_stream *xdr = &rqstp->rq_res_stream; 983 struct nfsd3_writeres *resp = rqstp->rq_resp; 984 985 if (!svcxdr_encode_nfsstat3(xdr, resp->status)) 986 return 0; 987 switch (resp->status) { 988 case nfs_ok: 989 if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) 990 return 0; 991 if (xdr_stream_encode_u32(xdr, resp->count) < 0) 992 return 0; 993 if (xdr_stream_encode_u32(xdr, resp->committed) < 0) 994 return 0; 995 if (!svcxdr_encode_writeverf3(xdr, resp->verf)) 996 return 0; 997 break; 998 default: 999 if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) 1000 return 0; 1001 } 1002 1003 return 1; 1004 } 1005 1006 /* CREATE, MKDIR, SYMLINK, MKNOD */ 1007 int 1008 nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p) 1009 { 1010 struct xdr_stream *xdr = &rqstp->rq_res_stream; 1011 struct nfsd3_diropres *resp = rqstp->rq_resp; 1012 1013 if (!svcxdr_encode_nfsstat3(xdr, resp->status)) 1014 return 0; 1015 switch (resp->status) { 1016 case nfs_ok: 1017 if (!svcxdr_encode_post_op_fh3(xdr, &resp->fh)) 1018 return 0; 1019 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) 1020 return 0; 1021 if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->dirfh)) 1022 return 0; 1023 break; 1024 default: 1025 if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->dirfh)) 1026 return 0; 1027 } 1028 1029 return 1; 1030 } 1031 1032 /* RENAME */ 1033 int 1034 nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p) 1035 { 1036 struct xdr_stream *xdr = &rqstp->rq_res_stream; 1037 struct nfsd3_renameres *resp = rqstp->rq_resp; 1038 1039 return svcxdr_encode_nfsstat3(xdr, resp->status) && 1040 svcxdr_encode_wcc_data(rqstp, xdr, &resp->ffh) && 1041 svcxdr_encode_wcc_data(rqstp, xdr, &resp->tfh); 1042 } 1043 1044 /* LINK */ 1045 int 1046 nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p) 1047 { 1048 struct xdr_stream *xdr = &rqstp->rq_res_stream; 1049 struct nfsd3_linkres *resp = rqstp->rq_resp; 1050 1051 return svcxdr_encode_nfsstat3(xdr, resp->status) && 1052 svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh) && 1053 svcxdr_encode_wcc_data(rqstp, xdr, &resp->tfh); 1054 } 1055 1056 /* READDIR */ 1057 int 1058 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) 1059 { 1060 struct xdr_stream *xdr = &rqstp->rq_res_stream; 1061 struct nfsd3_readdirres *resp = rqstp->rq_resp; 1062 struct xdr_buf *dirlist = &resp->dirlist; 1063 1064 if (!svcxdr_encode_nfsstat3(xdr, resp->status)) 1065 return 0; 1066 switch (resp->status) { 1067 case nfs_ok: 1068 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) 1069 return 0; 1070 if (!svcxdr_encode_cookieverf3(xdr, resp->verf)) 1071 return 0; 1072 xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len); 1073 /* no more entries */ 1074 if (xdr_stream_encode_item_absent(xdr) < 0) 1075 return 0; 1076 if (xdr_stream_encode_bool(xdr, resp->common.err == nfserr_eof) < 0) 1077 return 0; 1078 break; 1079 default: 1080 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) 1081 return 0; 1082 } 1083 1084 return 1; 1085 } 1086 1087 static __be32 1088 compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, 1089 const char *name, int namlen, u64 ino) 1090 { 1091 struct svc_export *exp; 1092 struct dentry *dparent, *dchild; 1093 __be32 rv = nfserr_noent; 1094 1095 dparent = cd->fh.fh_dentry; 1096 exp = cd->fh.fh_export; 1097 1098 if (isdotent(name, namlen)) { 1099 if (namlen == 2) { 1100 dchild = dget_parent(dparent); 1101 /* 1102 * Don't return filehandle for ".." if we're at 1103 * the filesystem or export root: 1104 */ 1105 if (dchild == dparent) 1106 goto out; 1107 if (dparent == exp->ex_path.dentry) 1108 goto out; 1109 } else 1110 dchild = dget(dparent); 1111 } else 1112 dchild = lookup_positive_unlocked(name, dparent, namlen); 1113 if (IS_ERR(dchild)) 1114 return rv; 1115 if (d_mountpoint(dchild)) 1116 goto out; 1117 if (dchild->d_inode->i_ino != ino) 1118 goto out; 1119 rv = fh_compose(fhp, exp, dchild, &cd->fh); 1120 out: 1121 dput(dchild); 1122 return rv; 1123 } 1124 1125 /** 1126 * nfs3svc_encode_cookie3 - Encode a directory offset cookie 1127 * @resp: readdir result context 1128 * @offset: offset cookie to encode 1129 * 1130 * The buffer space for the offset cookie has already been reserved 1131 * by svcxdr_encode_entry3_common(). 1132 */ 1133 void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset) 1134 { 1135 __be64 cookie = cpu_to_be64(offset); 1136 1137 if (!resp->cookie_offset) 1138 return; 1139 write_bytes_to_xdr_buf(&resp->dirlist, resp->cookie_offset, &cookie, 1140 sizeof(cookie)); 1141 resp->cookie_offset = 0; 1142 } 1143 1144 static bool 1145 svcxdr_encode_entry3_common(struct nfsd3_readdirres *resp, const char *name, 1146 int namlen, loff_t offset, u64 ino) 1147 { 1148 struct xdr_buf *dirlist = &resp->dirlist; 1149 struct xdr_stream *xdr = &resp->xdr; 1150 1151 if (xdr_stream_encode_item_present(xdr) < 0) 1152 return false; 1153 /* fileid */ 1154 if (xdr_stream_encode_u64(xdr, ino) < 0) 1155 return false; 1156 /* name */ 1157 if (xdr_stream_encode_opaque(xdr, name, min(namlen, NFS3_MAXNAMLEN)) < 0) 1158 return false; 1159 /* cookie */ 1160 resp->cookie_offset = dirlist->len; 1161 if (xdr_stream_encode_u64(xdr, NFS_OFFSET_MAX) < 0) 1162 return false; 1163 1164 return true; 1165 } 1166 1167 /** 1168 * nfs3svc_encode_entry3 - encode one NFSv3 READDIR entry 1169 * @data: directory context 1170 * @name: name of the object to be encoded 1171 * @namlen: length of that name, in bytes 1172 * @offset: the offset of the previous entry 1173 * @ino: the fileid of this entry 1174 * @d_type: unused 1175 * 1176 * Return values: 1177 * %0: Entry was successfully encoded. 1178 * %-EINVAL: An encoding problem occured, secondary status code in resp->common.err 1179 * 1180 * On exit, the following fields are updated: 1181 * - resp->xdr 1182 * - resp->common.err 1183 * - resp->cookie_offset 1184 */ 1185 int nfs3svc_encode_entry3(void *data, const char *name, int namlen, 1186 loff_t offset, u64 ino, unsigned int d_type) 1187 { 1188 struct readdir_cd *ccd = data; 1189 struct nfsd3_readdirres *resp = container_of(ccd, 1190 struct nfsd3_readdirres, 1191 common); 1192 unsigned int starting_length = resp->dirlist.len; 1193 1194 /* The offset cookie for the previous entry */ 1195 nfs3svc_encode_cookie3(resp, offset); 1196 1197 if (!svcxdr_encode_entry3_common(resp, name, namlen, offset, ino)) 1198 goto out_toosmall; 1199 1200 xdr_commit_encode(&resp->xdr); 1201 resp->common.err = nfs_ok; 1202 return 0; 1203 1204 out_toosmall: 1205 resp->cookie_offset = 0; 1206 resp->common.err = nfserr_toosmall; 1207 resp->dirlist.len = starting_length; 1208 return -EINVAL; 1209 } 1210 1211 static bool 1212 svcxdr_encode_entry3_plus(struct nfsd3_readdirres *resp, const char *name, 1213 int namlen, u64 ino) 1214 { 1215 struct xdr_stream *xdr = &resp->xdr; 1216 struct svc_fh *fhp = &resp->scratch; 1217 bool result; 1218 1219 result = false; 1220 fh_init(fhp, NFS3_FHSIZE); 1221 if (compose_entry_fh(resp, fhp, name, namlen, ino) != nfs_ok) 1222 goto out_noattrs; 1223 1224 if (!svcxdr_encode_post_op_attr(resp->rqstp, xdr, fhp)) 1225 goto out; 1226 if (!svcxdr_encode_post_op_fh3(xdr, fhp)) 1227 goto out; 1228 result = true; 1229 1230 out: 1231 fh_put(fhp); 1232 return result; 1233 1234 out_noattrs: 1235 if (xdr_stream_encode_item_absent(xdr) < 0) 1236 return false; 1237 if (xdr_stream_encode_item_absent(xdr) < 0) 1238 return false; 1239 return true; 1240 } 1241 1242 /** 1243 * nfs3svc_encode_entryplus3 - encode one NFSv3 READDIRPLUS entry 1244 * @data: directory context 1245 * @name: name of the object to be encoded 1246 * @namlen: length of that name, in bytes 1247 * @offset: the offset of the previous entry 1248 * @ino: the fileid of this entry 1249 * @d_type: unused 1250 * 1251 * Return values: 1252 * %0: Entry was successfully encoded. 1253 * %-EINVAL: An encoding problem occured, secondary status code in resp->common.err 1254 * 1255 * On exit, the following fields are updated: 1256 * - resp->xdr 1257 * - resp->common.err 1258 * - resp->cookie_offset 1259 */ 1260 int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen, 1261 loff_t offset, u64 ino, unsigned int d_type) 1262 { 1263 struct readdir_cd *ccd = data; 1264 struct nfsd3_readdirres *resp = container_of(ccd, 1265 struct nfsd3_readdirres, 1266 common); 1267 unsigned int starting_length = resp->dirlist.len; 1268 1269 /* The offset cookie for the previous entry */ 1270 nfs3svc_encode_cookie3(resp, offset); 1271 1272 if (!svcxdr_encode_entry3_common(resp, name, namlen, offset, ino)) 1273 goto out_toosmall; 1274 if (!svcxdr_encode_entry3_plus(resp, name, namlen, ino)) 1275 goto out_toosmall; 1276 1277 xdr_commit_encode(&resp->xdr); 1278 resp->common.err = nfs_ok; 1279 return 0; 1280 1281 out_toosmall: 1282 resp->cookie_offset = 0; 1283 resp->common.err = nfserr_toosmall; 1284 resp->dirlist.len = starting_length; 1285 return -EINVAL; 1286 } 1287 1288 static bool 1289 svcxdr_encode_fsstat3resok(struct xdr_stream *xdr, 1290 const struct nfsd3_fsstatres *resp) 1291 { 1292 const struct kstatfs *s = &resp->stats; 1293 u64 bs = s->f_bsize; 1294 __be32 *p; 1295 1296 p = xdr_reserve_space(xdr, XDR_UNIT * 13); 1297 if (!p) 1298 return false; 1299 p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */ 1300 p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */ 1301 p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */ 1302 p = xdr_encode_hyper(p, s->f_files); /* total inodes */ 1303 p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */ 1304 p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */ 1305 *p = cpu_to_be32(resp->invarsec); /* mean unchanged time */ 1306 1307 return true; 1308 } 1309 1310 /* FSSTAT */ 1311 int 1312 nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p) 1313 { 1314 struct xdr_stream *xdr = &rqstp->rq_res_stream; 1315 struct nfsd3_fsstatres *resp = rqstp->rq_resp; 1316 1317 if (!svcxdr_encode_nfsstat3(xdr, resp->status)) 1318 return 0; 1319 switch (resp->status) { 1320 case nfs_ok: 1321 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) 1322 return 0; 1323 if (!svcxdr_encode_fsstat3resok(xdr, resp)) 1324 return 0; 1325 break; 1326 default: 1327 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) 1328 return 0; 1329 } 1330 1331 return 1; 1332 } 1333 1334 static bool 1335 svcxdr_encode_fsinfo3resok(struct xdr_stream *xdr, 1336 const struct nfsd3_fsinfores *resp) 1337 { 1338 __be32 *p; 1339 1340 p = xdr_reserve_space(xdr, XDR_UNIT * 12); 1341 if (!p) 1342 return false; 1343 *p++ = cpu_to_be32(resp->f_rtmax); 1344 *p++ = cpu_to_be32(resp->f_rtpref); 1345 *p++ = cpu_to_be32(resp->f_rtmult); 1346 *p++ = cpu_to_be32(resp->f_wtmax); 1347 *p++ = cpu_to_be32(resp->f_wtpref); 1348 *p++ = cpu_to_be32(resp->f_wtmult); 1349 *p++ = cpu_to_be32(resp->f_dtpref); 1350 p = xdr_encode_hyper(p, resp->f_maxfilesize); 1351 p = encode_nfstime3(p, &nfs3svc_time_delta); 1352 *p = cpu_to_be32(resp->f_properties); 1353 1354 return true; 1355 } 1356 1357 /* FSINFO */ 1358 int 1359 nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p) 1360 { 1361 struct xdr_stream *xdr = &rqstp->rq_res_stream; 1362 struct nfsd3_fsinfores *resp = rqstp->rq_resp; 1363 1364 if (!svcxdr_encode_nfsstat3(xdr, resp->status)) 1365 return 0; 1366 switch (resp->status) { 1367 case nfs_ok: 1368 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) 1369 return 0; 1370 if (!svcxdr_encode_fsinfo3resok(xdr, resp)) 1371 return 0; 1372 break; 1373 default: 1374 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) 1375 return 0; 1376 } 1377 1378 return 1; 1379 } 1380 1381 static bool 1382 svcxdr_encode_pathconf3resok(struct xdr_stream *xdr, 1383 const struct nfsd3_pathconfres *resp) 1384 { 1385 __be32 *p; 1386 1387 p = xdr_reserve_space(xdr, XDR_UNIT * 6); 1388 if (!p) 1389 return false; 1390 *p++ = cpu_to_be32(resp->p_link_max); 1391 *p++ = cpu_to_be32(resp->p_name_max); 1392 p = xdr_encode_bool(p, resp->p_no_trunc); 1393 p = xdr_encode_bool(p, resp->p_chown_restricted); 1394 p = xdr_encode_bool(p, resp->p_case_insensitive); 1395 xdr_encode_bool(p, resp->p_case_preserving); 1396 1397 return true; 1398 } 1399 1400 /* PATHCONF */ 1401 int 1402 nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p) 1403 { 1404 struct xdr_stream *xdr = &rqstp->rq_res_stream; 1405 struct nfsd3_pathconfres *resp = rqstp->rq_resp; 1406 1407 if (!svcxdr_encode_nfsstat3(xdr, resp->status)) 1408 return 0; 1409 switch (resp->status) { 1410 case nfs_ok: 1411 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) 1412 return 0; 1413 if (!svcxdr_encode_pathconf3resok(xdr, resp)) 1414 return 0; 1415 break; 1416 default: 1417 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) 1418 return 0; 1419 } 1420 1421 return 1; 1422 } 1423 1424 /* COMMIT */ 1425 int 1426 nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p) 1427 { 1428 struct xdr_stream *xdr = &rqstp->rq_res_stream; 1429 struct nfsd3_commitres *resp = rqstp->rq_resp; 1430 1431 if (!svcxdr_encode_nfsstat3(xdr, resp->status)) 1432 return 0; 1433 switch (resp->status) { 1434 case nfs_ok: 1435 if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) 1436 return 0; 1437 if (!svcxdr_encode_writeverf3(xdr, resp->verf)) 1438 return 0; 1439 break; 1440 default: 1441 if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) 1442 return 0; 1443 } 1444 1445 return 1; 1446 } 1447 1448 /* 1449 * XDR release functions 1450 */ 1451 void 1452 nfs3svc_release_fhandle(struct svc_rqst *rqstp) 1453 { 1454 struct nfsd3_attrstat *resp = rqstp->rq_resp; 1455 1456 fh_put(&resp->fh); 1457 } 1458 1459 void 1460 nfs3svc_release_fhandle2(struct svc_rqst *rqstp) 1461 { 1462 struct nfsd3_fhandle_pair *resp = rqstp->rq_resp; 1463 1464 fh_put(&resp->fh1); 1465 fh_put(&resp->fh2); 1466 } 1467