1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #include <sys/param.h> 33 #include <sys/types.h> 34 #include <sys/systm.h> 35 #include <sys/cred.h> 36 #include <sys/buf.h> 37 #include <sys/vfs.h> 38 #include <sys/vnode.h> 39 #include <sys/uio.h> 40 #include <sys/errno.h> 41 #include <sys/sysmacros.h> 42 #include <sys/statvfs.h> 43 #include <sys/kmem.h> 44 #include <sys/dirent.h> 45 #include <sys/cmn_err.h> 46 #include <sys/debug.h> 47 #include <sys/systeminfo.h> 48 #include <sys/flock.h> 49 #include <sys/nbmlock.h> 50 #include <sys/policy.h> 51 52 #include <rpc/types.h> 53 #include <rpc/auth.h> 54 #include <rpc/svc.h> 55 56 #include <nfs/nfs.h> 57 #include <nfs/export.h> 58 59 #include <sys/strsubr.h> 60 61 /* 62 * These are the interface routines for the server side of the 63 * Network File System. See the NFS version 3 protocol specification 64 * for a description of this interface. 65 */ 66 67 #ifdef DEBUG 68 int rfs3_do_pre_op_attr = 1; 69 int rfs3_do_post_op_attr = 1; 70 int rfs3_do_post_op_fh3 = 1; 71 #endif 72 73 static writeverf3 write3verf; 74 75 static int sattr3_to_vattr(sattr3 *, struct vattr *); 76 static int vattr_to_fattr3(struct vattr *, fattr3 *); 77 static int vattr_to_wcc_attr(struct vattr *, wcc_attr *); 78 static void vattr_to_pre_op_attr(struct vattr *, pre_op_attr *); 79 static void vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *); 80 81 /* ARGSUSED */ 82 void 83 rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi, 84 struct svc_req *req, cred_t *cr) 85 { 86 int error; 87 vnode_t *vp; 88 struct vattr va; 89 90 vp = nfs3_fhtovp(&args->object, exi); 91 if (vp == NULL) { 92 error = ESTALE; 93 goto out; 94 } 95 96 va.va_mask = AT_ALL; 97 error = rfs4_delegated_getattr(vp, &va, 0, cr); 98 99 VN_RELE(vp); 100 101 if (!error) { 102 /* overflow error if time or size is out of range */ 103 error = vattr_to_fattr3(&va, &resp->resok.obj_attributes); 104 if (error) 105 goto out; 106 resp->status = NFS3_OK; 107 return; 108 } 109 110 out: 111 if (curthread->t_flag & T_WOULDBLOCK) { 112 curthread->t_flag &= ~T_WOULDBLOCK; 113 resp->status = NFS3ERR_JUKEBOX; 114 } else 115 resp->status = puterrno3(error); 116 } 117 118 fhandle_t * 119 rfs3_getattr_getfh(GETATTR3args *args) 120 { 121 122 return ((fhandle_t *)&args->object.fh3_u.nfs_fh3_i.fh3_i); 123 } 124 125 void 126 rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi, 127 struct svc_req *req, cred_t *cr) 128 { 129 int error; 130 vnode_t *vp; 131 struct vattr *bvap; 132 struct vattr bva; 133 struct vattr *avap; 134 struct vattr ava; 135 int flag; 136 int in_crit = 0; 137 struct flock64 bf; 138 139 bvap = NULL; 140 avap = NULL; 141 142 vp = nfs3_fhtovp(&args->object, exi); 143 if (vp == NULL) { 144 error = ESTALE; 145 goto out; 146 } 147 148 error = sattr3_to_vattr(&args->new_attributes, &ava); 149 if (error) 150 goto out; 151 152 /* 153 * We need to specially handle size changes because of 154 * possible conflicting NBMAND locks. Get into critical 155 * region before VOP_GETATTR, so the size attribute is 156 * valid when checking conflicts. 157 * 158 * Also, check to see if the v4 side of the server has 159 * delegated this file. If so, then we return JUKEBOX to 160 * allow the client to retrasmit its request. 161 */ 162 if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) { 163 if (rfs4_check_delegated(FWRITE, vp, TRUE)) { 164 resp->status = NFS3ERR_JUKEBOX; 165 goto out1; 166 } 167 if (nbl_need_check(vp)) { 168 nbl_start_crit(vp, RW_READER); 169 in_crit = 1; 170 } 171 } 172 173 bva.va_mask = AT_ALL; 174 error = rfs4_delegated_getattr(vp, &bva, 0, cr); 175 176 /* 177 * If we can't get the attributes, then we can't do the 178 * right access checking. So, we'll fail the request. 179 */ 180 if (error) 181 goto out; 182 183 #ifdef DEBUG 184 if (rfs3_do_pre_op_attr) 185 bvap = &bva; 186 #else 187 bvap = &bva; 188 #endif 189 190 if (rdonly(exi, req) || vn_is_readonly(vp)) { 191 resp->status = NFS3ERR_ROFS; 192 goto out1; 193 } 194 195 if (args->guard.check && 196 (args->guard.obj_ctime.seconds != bva.va_ctime.tv_sec || 197 args->guard.obj_ctime.nseconds != bva.va_ctime.tv_nsec)) { 198 resp->status = NFS3ERR_NOT_SYNC; 199 goto out1; 200 } 201 202 if (args->new_attributes.mtime.set_it == SET_TO_CLIENT_TIME) 203 flag = ATTR_UTIME; 204 else 205 flag = 0; 206 207 /* 208 * If the filesystem is exported with nosuid, then mask off 209 * the setuid and setgid bits. 210 */ 211 if ((ava.va_mask & AT_MODE) && vp->v_type == VREG && 212 (exi->exi_export.ex_flags & EX_NOSUID)) 213 ava.va_mode &= ~(VSUID | VSGID); 214 215 /* 216 * We need to specially handle size changes because it is 217 * possible for the client to create a file with modes 218 * which indicate read-only, but with the file opened for 219 * writing. If the client then tries to set the size of 220 * the file, then the normal access checking done in 221 * VOP_SETATTR would prevent the client from doing so, 222 * although it should be legal for it to do so. To get 223 * around this, we do the access checking for ourselves 224 * and then use VOP_SPACE which doesn't do the access 225 * checking which VOP_SETATTR does. VOP_SPACE can only 226 * operate on VREG files, let VOP_SETATTR handle the other 227 * extremely rare cases. 228 * Also the client should not be allowed to change the 229 * size of the file if there is a conflicting non-blocking 230 * mandatory lock in the region the change. 231 */ 232 if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) { 233 if (in_crit) { 234 u_offset_t offset; 235 ssize_t length; 236 237 if (ava.va_size < bva.va_size) { 238 offset = ava.va_size; 239 length = bva.va_size - ava.va_size; 240 } else { 241 offset = bva.va_size; 242 length = ava.va_size - bva.va_size; 243 } 244 if (nbl_conflict(vp, NBL_WRITE, offset, length, 0)) { 245 error = EACCES; 246 goto out; 247 } 248 } 249 250 if (crgetuid(cr) == bva.va_uid && ava.va_size != bva.va_size) { 251 ava.va_mask &= ~AT_SIZE; 252 bf.l_type = F_WRLCK; 253 bf.l_whence = 0; 254 bf.l_start = (off64_t)ava.va_size; 255 bf.l_len = 0; 256 bf.l_sysid = 0; 257 bf.l_pid = 0; 258 error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE, 259 (offset_t)ava.va_size, cr, NULL); 260 } 261 } 262 263 if (!error && ava.va_mask) 264 error = VOP_SETATTR(vp, &ava, flag, cr, NULL); 265 266 #ifdef DEBUG 267 if (rfs3_do_post_op_attr) { 268 ava.va_mask = AT_ALL; 269 avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava; 270 } else 271 avap = NULL; 272 #else 273 ava.va_mask = AT_ALL; 274 avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava; 275 #endif 276 277 /* 278 * Force modified metadata out to stable storage. 279 */ 280 (void) VOP_FSYNC(vp, FNODSYNC, cr); 281 282 if (error) 283 goto out; 284 285 if (in_crit) 286 nbl_end_crit(vp); 287 VN_RELE(vp); 288 289 resp->status = NFS3_OK; 290 vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc); 291 return; 292 293 out: 294 if (curthread->t_flag & T_WOULDBLOCK) { 295 curthread->t_flag &= ~T_WOULDBLOCK; 296 resp->status = NFS3ERR_JUKEBOX; 297 } else 298 resp->status = puterrno3(error); 299 out1: 300 if (vp != NULL) { 301 if (in_crit) 302 nbl_end_crit(vp); 303 VN_RELE(vp); 304 } 305 vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc); 306 } 307 308 fhandle_t * 309 rfs3_setattr_getfh(SETATTR3args *args) 310 { 311 312 return ((fhandle_t *)&args->object.fh3_u.nfs_fh3_i.fh3_i); 313 } 314 315 /* ARGSUSED */ 316 void 317 rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi, 318 struct svc_req *req, cred_t *cr) 319 { 320 int error; 321 vnode_t *vp; 322 vnode_t *dvp; 323 struct vattr *vap; 324 struct vattr va; 325 struct vattr *dvap; 326 struct vattr dva; 327 nfs_fh3 *fhp; 328 struct sec_ol sec = {0, 0}; 329 bool_t publicfh_flag = FALSE, auth_weak = FALSE; 330 331 dvap = NULL; 332 333 /* 334 * Allow lookups from the root - the default 335 * location of the public filehandle. 336 */ 337 if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) { 338 dvp = rootdir; 339 VN_HOLD(dvp); 340 } else { 341 dvp = nfs3_fhtovp(args->what.dirp, exi); 342 if (dvp == NULL) { 343 error = ESTALE; 344 goto out; 345 } 346 } 347 348 #ifdef DEBUG 349 if (rfs3_do_pre_op_attr) { 350 dva.va_mask = AT_ALL; 351 dvap = VOP_GETATTR(dvp, &dva, 0, cr) ? NULL : &dva; 352 } 353 #else 354 dva.va_mask = AT_ALL; 355 dvap = VOP_GETATTR(dvp, &dva, 0, cr) ? NULL : &dva; 356 #endif 357 358 if (args->what.name == nfs3nametoolong) { 359 resp->status = NFS3ERR_NAMETOOLONG; 360 goto out1; 361 } 362 363 if (args->what.name == NULL || *(args->what.name) == '\0') { 364 resp->status = NFS3ERR_ACCES; 365 goto out1; 366 } 367 368 fhp = args->what.dirp; 369 if (strcmp(args->what.name, "..") == 0 && 370 EQFID(&exi->exi_fid, (fid_t *)&fhp->fh3_len)) { 371 resp->status = NFS3ERR_NOENT; 372 goto out1; 373 } 374 375 /* 376 * If the public filehandle is used then allow 377 * a multi-component lookup 378 */ 379 if (PUBLIC_FH3(args->what.dirp)) { 380 publicfh_flag = TRUE; 381 error = rfs_publicfh_mclookup(args->what.name, dvp, cr, &vp, 382 &exi, &sec); 383 if (error && exi != NULL) 384 exi_rele(exi); /* See the comment below */ 385 } else { 386 error = VOP_LOOKUP(dvp, args->what.name, &vp, 387 NULL, 0, NULL, cr); 388 } 389 390 #ifdef DEBUG 391 if (rfs3_do_post_op_attr) { 392 dva.va_mask = AT_ALL; 393 dvap = VOP_GETATTR(dvp, &dva, 0, cr) ? NULL : &dva; 394 } else 395 dvap = NULL; 396 #else 397 dva.va_mask = AT_ALL; 398 dvap = VOP_GETATTR(dvp, &dva, 0, cr) ? NULL : &dva; 399 #endif 400 401 if (error) 402 goto out; 403 404 if (sec.sec_flags & SEC_QUERY) { 405 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index); 406 } else { 407 error = makefh3(&resp->resok.object, vp, exi); 408 if (!error && publicfh_flag && !chk_clnt_sec(exi, req)) 409 auth_weak = TRUE; 410 } 411 412 if (error) { 413 VN_RELE(vp); 414 goto out; 415 } 416 417 /* 418 * If publicfh_flag is true then we have called rfs_publicfh_mclookup 419 * and have obtained a new exportinfo in exi which needs to be 420 * released. Note the the original exportinfo pointed to by exi 421 * will be released by the caller, common_dispatch. 422 */ 423 if (publicfh_flag) 424 exi_rele(exi); 425 426 VN_RELE(dvp); 427 428 #ifdef DEBUG 429 if (rfs3_do_post_op_attr) { 430 va.va_mask = AT_ALL; 431 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 432 } else 433 vap = NULL; 434 #else 435 va.va_mask = AT_ALL; 436 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 437 #endif 438 439 VN_RELE(vp); 440 441 resp->status = NFS3_OK; 442 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 443 vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes); 444 445 /* 446 * If it's public fh, no 0x81, and client's flavor is 447 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now. 448 * Then set RPC status to AUTH_TOOWEAK in common_dispatch. 449 */ 450 if (auth_weak) 451 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR; 452 453 return; 454 455 out: 456 if (curthread->t_flag & T_WOULDBLOCK) { 457 curthread->t_flag &= ~T_WOULDBLOCK; 458 resp->status = NFS3ERR_JUKEBOX; 459 } else 460 resp->status = puterrno3(error); 461 out1: 462 if (dvp != NULL) 463 VN_RELE(dvp); 464 vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes); 465 466 } 467 468 fhandle_t * 469 rfs3_lookup_getfh(LOOKUP3args *args) 470 { 471 472 return ((fhandle_t *)&args->what.dirp->fh3_u.nfs_fh3_i.fh3_i); 473 } 474 475 /* ARGSUSED */ 476 void 477 rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi, 478 struct svc_req *req, cred_t *cr) 479 { 480 int error; 481 vnode_t *vp; 482 struct vattr *vap; 483 struct vattr va; 484 int checkwriteperm; 485 486 vap = NULL; 487 488 vp = nfs3_fhtovp(&args->object, exi); 489 if (vp == NULL) { 490 error = ESTALE; 491 goto out; 492 } 493 494 /* 495 * If the file system is exported read only, it is not appropriate 496 * to check write permissions for regular files and directories. 497 * Special files are interpreted by the client, so the underlying 498 * permissions are sent back to the client for interpretation. 499 */ 500 if (rdonly(exi, req) && (vp->v_type == VREG || vp->v_type == VDIR)) 501 checkwriteperm = 0; 502 else 503 checkwriteperm = 1; 504 505 /* 506 * We need the mode so that we can correctly determine access 507 * permissions relative to a mandatory lock file. Access to 508 * mandatory lock files is denied on the server, so it might 509 * as well be reflected to the server during the open. 510 */ 511 va.va_mask = AT_MODE; 512 error = VOP_GETATTR(vp, &va, 0, cr); 513 if (error) 514 goto out; 515 516 #ifdef DEBUG 517 if (rfs3_do_post_op_attr) 518 vap = &va; 519 #else 520 vap = &va; 521 #endif 522 523 resp->resok.access = 0; 524 525 if (args->access & ACCESS3_READ) { 526 error = VOP_ACCESS(vp, VREAD, 0, cr); 527 if (error) { 528 if (curthread->t_flag & T_WOULDBLOCK) 529 goto out; 530 } else if (!MANDLOCK(vp, va.va_mode)) 531 resp->resok.access |= ACCESS3_READ; 532 } 533 if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) { 534 error = VOP_ACCESS(vp, VEXEC, 0, cr); 535 if (error) { 536 if (curthread->t_flag & T_WOULDBLOCK) 537 goto out; 538 } else 539 resp->resok.access |= ACCESS3_LOOKUP; 540 } 541 if (checkwriteperm && 542 (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND))) { 543 error = VOP_ACCESS(vp, VWRITE, 0, cr); 544 if (error) { 545 if (curthread->t_flag & T_WOULDBLOCK) 546 goto out; 547 } else if (!MANDLOCK(vp, va.va_mode)) { 548 resp->resok.access |= 549 (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND)); 550 } 551 } 552 if (checkwriteperm && 553 (args->access & ACCESS3_DELETE) && vp->v_type == VDIR) { 554 error = VOP_ACCESS(vp, VWRITE, 0, cr); 555 if (error) { 556 if (curthread->t_flag & T_WOULDBLOCK) 557 goto out; 558 } else 559 resp->resok.access |= ACCESS3_DELETE; 560 } 561 if (args->access & ACCESS3_EXECUTE) { 562 error = VOP_ACCESS(vp, VEXEC, 0, cr); 563 if (error) { 564 if (curthread->t_flag & T_WOULDBLOCK) 565 goto out; 566 } else if (!MANDLOCK(vp, va.va_mode)) 567 resp->resok.access |= ACCESS3_EXECUTE; 568 } 569 570 #ifdef DEBUG 571 if (rfs3_do_post_op_attr) { 572 va.va_mask = AT_ALL; 573 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 574 } else 575 vap = NULL; 576 #else 577 va.va_mask = AT_ALL; 578 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 579 #endif 580 581 VN_RELE(vp); 582 583 resp->status = NFS3_OK; 584 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 585 return; 586 587 out: 588 if (curthread->t_flag & T_WOULDBLOCK) { 589 curthread->t_flag &= ~T_WOULDBLOCK; 590 resp->status = NFS3ERR_JUKEBOX; 591 } else 592 resp->status = puterrno3(error); 593 if (vp != NULL) 594 VN_RELE(vp); 595 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); 596 } 597 598 fhandle_t * 599 rfs3_access_getfh(ACCESS3args *args) 600 { 601 602 return ((fhandle_t *)&args->object.fh3_u.nfs_fh3_i.fh3_i); 603 } 604 605 /* ARGSUSED */ 606 void 607 rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi, 608 struct svc_req *req, cred_t *cr) 609 { 610 int error; 611 vnode_t *vp; 612 struct vattr *vap; 613 struct vattr va; 614 struct iovec iov; 615 struct uio uio; 616 char *data; 617 618 vap = NULL; 619 620 vp = nfs3_fhtovp(&args->symlink, exi); 621 if (vp == NULL) { 622 error = ESTALE; 623 goto out; 624 } 625 626 va.va_mask = AT_ALL; 627 error = VOP_GETATTR(vp, &va, 0, cr); 628 if (error) 629 goto out; 630 631 #ifdef DEBUG 632 if (rfs3_do_post_op_attr) 633 vap = &va; 634 #else 635 vap = &va; 636 #endif 637 638 if (vp->v_type != VLNK) { 639 resp->status = NFS3ERR_INVAL; 640 goto out1; 641 } 642 643 if (MANDLOCK(vp, va.va_mode)) { 644 resp->status = NFS3ERR_ACCES; 645 goto out1; 646 } 647 648 data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP); 649 650 iov.iov_base = data; 651 iov.iov_len = MAXPATHLEN; 652 uio.uio_iov = &iov; 653 uio.uio_iovcnt = 1; 654 uio.uio_segflg = UIO_SYSSPACE; 655 uio.uio_extflg = UIO_COPY_CACHED; 656 uio.uio_loffset = 0; 657 uio.uio_resid = MAXPATHLEN; 658 659 error = VOP_READLINK(vp, &uio, cr); 660 661 #ifdef DEBUG 662 if (rfs3_do_post_op_attr) { 663 va.va_mask = AT_ALL; 664 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 665 } else 666 vap = NULL; 667 #else 668 va.va_mask = AT_ALL; 669 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 670 #endif 671 672 #if 0 /* notyet */ 673 /* 674 * Don't do this. It causes local disk writes when just 675 * reading the file and the overhead is deemed larger 676 * than the benefit. 677 */ 678 /* 679 * Force modified metadata out to stable storage. 680 */ 681 (void) VOP_FSYNC(vp, FNODSYNC, cr); 682 #endif 683 684 if (error) { 685 kmem_free(data, MAXPATHLEN + 1); 686 goto out; 687 } 688 689 VN_RELE(vp); 690 691 resp->status = NFS3_OK; 692 vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes); 693 resp->resok.data = data; 694 *(data + MAXPATHLEN - uio.uio_resid) = '\0'; 695 return; 696 697 out: 698 if (curthread->t_flag & T_WOULDBLOCK) { 699 curthread->t_flag &= ~T_WOULDBLOCK; 700 resp->status = NFS3ERR_JUKEBOX; 701 } else 702 resp->status = puterrno3(error); 703 out1: 704 if (vp != NULL) 705 VN_RELE(vp); 706 vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes); 707 } 708 709 fhandle_t * 710 rfs3_readlink_getfh(READLINK3args *args) 711 { 712 713 return ((fhandle_t *)&args->symlink.fh3_u.nfs_fh3_i.fh3_i); 714 } 715 716 void 717 rfs3_readlink_free(READLINK3res *resp) 718 { 719 720 if (resp->status == NFS3_OK) 721 kmem_free(resp->resok.data, MAXPATHLEN + 1); 722 } 723 724 /* ARGSUSED */ 725 void 726 rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi, 727 struct svc_req *req, cred_t *cr) 728 { 729 int error; 730 vnode_t *vp; 731 struct vattr *vap; 732 struct vattr va; 733 struct iovec iov; 734 struct uio uio; 735 u_offset_t offset; 736 mblk_t *mp; 737 int alloc_err = 0; 738 int in_crit = 0; 739 int need_rwunlock = 0; 740 741 vap = NULL; 742 743 vp = nfs3_fhtovp(&args->file, exi); 744 if (vp == NULL) { 745 error = ESTALE; 746 goto out; 747 } 748 749 /* 750 * Check to see if the v4 side of the server has delegated 751 * this file. If so, then we return JUKEBOX to allow the 752 * client to retrasmit its request. 753 */ 754 if (rfs4_check_delegated(FREAD, vp, FALSE)) { 755 resp->status = NFS3ERR_JUKEBOX; 756 goto out1; 757 } 758 759 /* 760 * Enter the critical region before calling VOP_RWLOCK 761 * to avoid a deadlock with write requests. 762 */ 763 if (nbl_need_check(vp)) { 764 nbl_start_crit(vp, RW_READER); 765 in_crit = 1; 766 if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0)) { 767 error = EACCES; 768 goto out; 769 } 770 } 771 772 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 773 need_rwunlock = 1; 774 775 va.va_mask = AT_ALL; 776 error = VOP_GETATTR(vp, &va, 0, cr); 777 778 /* 779 * If we can't get the attributes, then we can't do the 780 * right access checking. So, we'll fail the request. 781 */ 782 if (error) 783 goto out; 784 785 #ifdef DEBUG 786 if (rfs3_do_post_op_attr) 787 vap = &va; 788 #else 789 vap = &va; 790 #endif 791 792 if (vp->v_type != VREG) { 793 resp->status = NFS3ERR_INVAL; 794 goto out1; 795 } 796 797 if (crgetuid(cr) != va.va_uid) { 798 error = VOP_ACCESS(vp, VREAD, 0, cr); 799 if (error) { 800 if (curthread->t_flag & T_WOULDBLOCK) 801 goto out; 802 error = VOP_ACCESS(vp, VEXEC, 0, cr); 803 if (error) 804 goto out; 805 } 806 } 807 808 if (MANDLOCK(vp, va.va_mode)) { 809 resp->status = NFS3ERR_ACCES; 810 goto out1; 811 } 812 813 offset = args->offset; 814 if (offset >= va.va_size) { 815 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 816 if (in_crit) 817 nbl_end_crit(vp); 818 VN_RELE(vp); 819 resp->status = NFS3_OK; 820 vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 821 resp->resok.count = 0; 822 resp->resok.eof = TRUE; 823 resp->resok.data.data_len = 0; 824 resp->resok.data.data_val = NULL; 825 resp->resok.data.mp = NULL; 826 return; 827 } 828 829 if (args->count == 0) { 830 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 831 if (in_crit) 832 nbl_end_crit(vp); 833 VN_RELE(vp); 834 resp->status = NFS3_OK; 835 vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 836 resp->resok.count = 0; 837 resp->resok.eof = FALSE; 838 resp->resok.data.data_len = 0; 839 resp->resok.data.data_val = NULL; 840 resp->resok.data.mp = NULL; 841 return; 842 } 843 844 /* 845 * do not allocate memory more the max. allowed 846 * transfer size 847 */ 848 if (args->count > rfs3_tsize(req)) 849 args->count = rfs3_tsize(req); 850 851 /* 852 * mp will contain the data to be sent out in the read reply. 853 * This will be freed after the reply has been sent out (by the 854 * driver). 855 * Let's roundup the data to a BYTES_PER_XDR_UNIT multiple, so 856 * that the call to xdrmblk_putmblk() never fails. 857 */ 858 mp = allocb_wait(RNDUP(args->count), BPRI_MED, STR_NOSIG, &alloc_err); 859 ASSERT(mp != NULL); 860 ASSERT(alloc_err == 0); 861 862 iov.iov_base = (caddr_t)mp->b_datap->db_base; 863 iov.iov_len = args->count; 864 uio.uio_iov = &iov; 865 uio.uio_iovcnt = 1; 866 uio.uio_segflg = UIO_SYSSPACE; 867 uio.uio_extflg = UIO_COPY_CACHED; 868 uio.uio_loffset = args->offset; 869 uio.uio_resid = args->count; 870 871 error = VOP_READ(vp, &uio, 0, cr, NULL); 872 873 if (error) { 874 freeb(mp); 875 goto out; 876 } 877 878 va.va_mask = AT_ALL; 879 error = VOP_GETATTR(vp, &va, 0, cr); 880 881 #ifdef DEBUG 882 if (rfs3_do_post_op_attr) { 883 if (error) 884 vap = NULL; 885 else 886 vap = &va; 887 } else 888 vap = NULL; 889 #else 890 if (error) 891 vap = NULL; 892 else 893 vap = &va; 894 #endif 895 896 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 897 898 #if 0 /* notyet */ 899 /* 900 * Don't do this. It causes local disk writes when just 901 * reading the file and the overhead is deemed larger 902 * than the benefit. 903 */ 904 /* 905 * Force modified metadata out to stable storage. 906 */ 907 (void) VOP_FSYNC(vp, FNODSYNC, cr); 908 #endif 909 910 if (in_crit) 911 nbl_end_crit(vp); 912 VN_RELE(vp); 913 914 resp->status = NFS3_OK; 915 vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 916 resp->resok.count = args->count - uio.uio_resid; 917 if (!error && offset + resp->resok.count == va.va_size) 918 resp->resok.eof = TRUE; 919 else 920 resp->resok.eof = FALSE; 921 resp->resok.data.data_len = resp->resok.count; 922 resp->resok.data.data_val = (char *)mp->b_datap->db_base; 923 924 resp->resok.data.mp = mp; 925 926 resp->resok.size = (uint_t)args->count; 927 return; 928 929 out: 930 if (curthread->t_flag & T_WOULDBLOCK) { 931 curthread->t_flag &= ~T_WOULDBLOCK; 932 resp->status = NFS3ERR_JUKEBOX; 933 } else 934 resp->status = puterrno3(error); 935 out1: 936 if (vp != NULL) { 937 if (need_rwunlock) 938 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 939 if (in_crit) 940 nbl_end_crit(vp); 941 VN_RELE(vp); 942 } 943 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes); 944 } 945 946 void 947 rfs3_read_free(READ3res *resp) 948 { 949 mblk_t *mp; 950 951 if (resp->status == NFS3_OK) { 952 mp = resp->resok.data.mp; 953 if (mp != NULL) 954 freeb(mp); 955 } 956 } 957 958 fhandle_t * 959 rfs3_read_getfh(READ3args *args) 960 { 961 962 return ((fhandle_t *)&args->file.fh3_u.nfs_fh3_i.fh3_i); 963 } 964 965 #define MAX_IOVECS 12 966 967 #ifdef DEBUG 968 static int rfs3_write_hits = 0; 969 static int rfs3_write_misses = 0; 970 #endif 971 972 void 973 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi, 974 struct svc_req *req, cred_t *cr) 975 { 976 int error; 977 vnode_t *vp; 978 struct vattr *bvap = NULL; 979 struct vattr bva; 980 struct vattr *avap = NULL; 981 struct vattr ava; 982 u_offset_t rlimit; 983 struct uio uio; 984 struct iovec iov[MAX_IOVECS]; 985 mblk_t *m; 986 struct iovec *iovp; 987 int iovcnt; 988 int ioflag; 989 cred_t *savecred; 990 int in_crit = 0; 991 int rwlock_ret = -1; 992 993 vp = nfs3_fhtovp(&args->file, exi); 994 if (vp == NULL) { 995 error = ESTALE; 996 goto out; 997 } 998 999 /* 1000 * Check to see if the v4 side of the server has delegated 1001 * this file. If so, then we return JUKEBOX to allow the 1002 * client to retrasmit its request. 1003 */ 1004 if (rfs4_check_delegated(FWRITE, vp, FALSE)) { 1005 resp->status = NFS3ERR_JUKEBOX; 1006 goto out1; 1007 } 1008 1009 /* 1010 * We have to enter the critical region before calling VOP_RWLOCK 1011 * to avoid a deadlock with ufs. 1012 */ 1013 if (nbl_need_check(vp)) { 1014 nbl_start_crit(vp, RW_READER); 1015 in_crit = 1; 1016 if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0)) { 1017 error = EACCES; 1018 goto out; 1019 } 1020 } 1021 1022 rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 1023 1024 bva.va_mask = AT_ALL; 1025 error = VOP_GETATTR(vp, &bva, 0, cr); 1026 1027 /* 1028 * If we can't get the attributes, then we can't do the 1029 * right access checking. So, we'll fail the request. 1030 */ 1031 if (error) 1032 goto out; 1033 1034 bvap = &bva; 1035 #ifdef DEBUG 1036 if (!rfs3_do_pre_op_attr) 1037 bvap = NULL; 1038 #endif 1039 avap = bvap; 1040 1041 if (args->count != args->data.data_len) { 1042 resp->status = NFS3ERR_INVAL; 1043 goto out1; 1044 } 1045 1046 if (rdonly(exi, req)) { 1047 resp->status = NFS3ERR_ROFS; 1048 goto out1; 1049 } 1050 1051 if (vp->v_type != VREG) { 1052 resp->status = NFS3ERR_INVAL; 1053 goto out1; 1054 } 1055 1056 if (crgetuid(cr) != bva.va_uid && 1057 (error = VOP_ACCESS(vp, VWRITE, 0, cr))) 1058 goto out; 1059 1060 if (MANDLOCK(vp, bva.va_mode)) { 1061 resp->status = NFS3ERR_ACCES; 1062 goto out1; 1063 } 1064 1065 if (args->count == 0) { 1066 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 1067 VN_RELE(vp); 1068 resp->status = NFS3_OK; 1069 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); 1070 resp->resok.count = 0; 1071 resp->resok.committed = args->stable; 1072 resp->resok.verf = write3verf; 1073 return; 1074 } 1075 1076 if (args->mblk != NULL) { 1077 iovcnt = 0; 1078 for (m = args->mblk; m != NULL; m = m->b_cont) 1079 iovcnt++; 1080 if (iovcnt <= MAX_IOVECS) { 1081 #ifdef DEBUG 1082 rfs3_write_hits++; 1083 #endif 1084 iovp = iov; 1085 } else { 1086 #ifdef DEBUG 1087 rfs3_write_misses++; 1088 #endif 1089 iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP); 1090 } 1091 mblk_to_iov(args->mblk, iovcnt, iovp); 1092 } else { 1093 iovcnt = 1; 1094 iovp = iov; 1095 iovp->iov_base = args->data.data_val; 1096 iovp->iov_len = args->count; 1097 } 1098 1099 uio.uio_iov = iovp; 1100 uio.uio_iovcnt = iovcnt; 1101 1102 uio.uio_segflg = UIO_SYSSPACE; 1103 uio.uio_extflg = UIO_COPY_DEFAULT; 1104 uio.uio_loffset = args->offset; 1105 uio.uio_resid = args->count; 1106 uio.uio_llimit = curproc->p_fsz_ctl; 1107 rlimit = uio.uio_llimit - args->offset; 1108 if (rlimit < (u_offset_t)uio.uio_resid) 1109 uio.uio_resid = (int)rlimit; 1110 1111 if (args->stable == UNSTABLE) 1112 ioflag = 0; 1113 else if (args->stable == FILE_SYNC) 1114 ioflag = FSYNC; 1115 else if (args->stable == DATA_SYNC) 1116 ioflag = FDSYNC; 1117 else { 1118 if (iovp != iov) 1119 kmem_free(iovp, sizeof (*iovp) * iovcnt); 1120 resp->status = NFS3ERR_INVAL; 1121 goto out1; 1122 } 1123 1124 /* 1125 * We're changing creds because VM may fault and we need 1126 * the cred of the current thread to be used if quota 1127 * checking is enabled. 1128 */ 1129 savecred = curthread->t_cred; 1130 curthread->t_cred = cr; 1131 error = VOP_WRITE(vp, &uio, ioflag, cr, NULL); 1132 curthread->t_cred = savecred; 1133 1134 if (iovp != iov) 1135 kmem_free(iovp, sizeof (*iovp) * iovcnt); 1136 1137 ava.va_mask = AT_ALL; 1138 avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava; 1139 1140 #ifdef DEBUG 1141 if (!rfs3_do_post_op_attr) 1142 avap = NULL; 1143 #endif 1144 1145 if (error) 1146 goto out; 1147 1148 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 1149 if (in_crit) 1150 nbl_end_crit(vp); 1151 VN_RELE(vp); 1152 1153 /* 1154 * If we were unable to get the V_WRITELOCK_TRUE, then we 1155 * may not have accurate after attrs, so check if 1156 * we have both attributes, they have a non-zero va_seq, and 1157 * va_seq has changed by exactly one, 1158 * if not, turn off the before attr. 1159 */ 1160 if (rwlock_ret != V_WRITELOCK_TRUE) { 1161 if (bvap == NULL || avap == NULL || 1162 bvap->va_seq == 0 || avap->va_seq == 0 || 1163 avap->va_seq != (bvap->va_seq + 1)) { 1164 bvap = NULL; 1165 } 1166 } 1167 1168 resp->status = NFS3_OK; 1169 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); 1170 resp->resok.count = args->count - uio.uio_resid; 1171 resp->resok.committed = args->stable; 1172 resp->resok.verf = write3verf; 1173 return; 1174 1175 out: 1176 if (curthread->t_flag & T_WOULDBLOCK) { 1177 curthread->t_flag &= ~T_WOULDBLOCK; 1178 resp->status = NFS3ERR_JUKEBOX; 1179 } else 1180 resp->status = puterrno3(error); 1181 out1: 1182 if (vp != NULL) { 1183 if (rwlock_ret != -1) 1184 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 1185 if (in_crit) 1186 nbl_end_crit(vp); 1187 VN_RELE(vp); 1188 } 1189 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc); 1190 } 1191 1192 fhandle_t * 1193 rfs3_write_getfh(WRITE3args *args) 1194 { 1195 1196 return ((fhandle_t *)&args->file.fh3_u.nfs_fh3_i.fh3_i); 1197 } 1198 1199 void 1200 rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi, 1201 struct svc_req *req, cred_t *cr) 1202 { 1203 int error; 1204 int in_crit = 0; 1205 vnode_t *vp; 1206 vnode_t *tvp = NULL; 1207 vnode_t *dvp; 1208 struct vattr *vap; 1209 struct vattr va; 1210 struct vattr *dbvap; 1211 struct vattr dbva; 1212 struct vattr *davap; 1213 struct vattr dava; 1214 enum vcexcl excl; 1215 nfstime3 *mtime; 1216 len_t reqsize; 1217 bool_t trunc; 1218 1219 dbvap = NULL; 1220 davap = NULL; 1221 1222 dvp = nfs3_fhtovp(args->where.dirp, exi); 1223 if (dvp == NULL) { 1224 error = ESTALE; 1225 goto out; 1226 } 1227 1228 #ifdef DEBUG 1229 if (rfs3_do_pre_op_attr) { 1230 dbva.va_mask = AT_ALL; 1231 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva; 1232 } else 1233 dbvap = NULL; 1234 #else 1235 dbva.va_mask = AT_ALL; 1236 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva; 1237 #endif 1238 davap = dbvap; 1239 1240 if (args->where.name == nfs3nametoolong) { 1241 resp->status = NFS3ERR_NAMETOOLONG; 1242 goto out1; 1243 } 1244 1245 if (args->where.name == NULL || *(args->where.name) == '\0') { 1246 resp->status = NFS3ERR_ACCES; 1247 goto out1; 1248 } 1249 1250 if (rdonly(exi, req)) { 1251 resp->status = NFS3ERR_ROFS; 1252 goto out1; 1253 } 1254 1255 if (args->how.mode == EXCLUSIVE) { 1256 va.va_mask = AT_TYPE | AT_MODE | AT_MTIME; 1257 va.va_type = VREG; 1258 va.va_mode = (mode_t)0; 1259 /* 1260 * Ensure no time overflows and that types match 1261 */ 1262 mtime = (nfstime3 *)&args->how.createhow3_u.verf; 1263 va.va_mtime.tv_sec = mtime->seconds % INT32_MAX; 1264 va.va_mtime.tv_nsec = mtime->nseconds; 1265 excl = EXCL; 1266 } else { 1267 error = sattr3_to_vattr(&args->how.createhow3_u.obj_attributes, 1268 &va); 1269 if (error) 1270 goto out; 1271 va.va_mask |= AT_TYPE; 1272 va.va_type = VREG; 1273 if (args->how.mode == GUARDED) 1274 excl = EXCL; 1275 else { 1276 excl = NONEXCL; 1277 1278 /* 1279 * During creation of file in non-exclusive mode 1280 * if size of file is being set then make sure 1281 * that if the file already exists that no conflicting 1282 * non-blocking mandatory locks exists in the region 1283 * being modified. If there are conflicting locks fail 1284 * the operation with EACCES. 1285 */ 1286 if (va.va_mask & AT_SIZE) { 1287 struct vattr tva; 1288 1289 /* 1290 * Does file already exist? 1291 */ 1292 error = VOP_LOOKUP(dvp, args->where.name, &tvp, 1293 NULL, 0, NULL, cr); 1294 1295 /* 1296 * Check to see if the file has been delegated 1297 * to a v4 client. If so, then begin recall of 1298 * the delegation and return JUKEBOX to allow 1299 * the client to retrasmit its request. 1300 */ 1301 1302 trunc = va.va_size == 0; 1303 if (!error && 1304 rfs4_check_delegated(FWRITE, tvp, trunc)) { 1305 resp->status = NFS3ERR_JUKEBOX; 1306 goto out1; 1307 } 1308 1309 /* 1310 * Check for NBMAND lock conflicts 1311 */ 1312 if (!error && nbl_need_check(tvp)) { 1313 u_offset_t offset; 1314 ssize_t len; 1315 1316 nbl_start_crit(tvp, RW_READER); 1317 in_crit = 1; 1318 1319 tva.va_mask = AT_SIZE; 1320 error = VOP_GETATTR(tvp, &tva, 0, cr); 1321 /* 1322 * Can't check for conflicts, so return 1323 * error. 1324 */ 1325 if (error) 1326 goto out; 1327 1328 offset = tva.va_size < va.va_size ? 1329 tva.va_size : va.va_size; 1330 len = tva.va_size < va.va_size ? 1331 va.va_size - tva.va_size : 1332 tva.va_size - va.va_size; 1333 if (nbl_conflict(tvp, NBL_WRITE, 1334 offset, len, 0)) { 1335 error = EACCES; 1336 goto out; 1337 } 1338 } else if (tvp) { 1339 VN_RELE(tvp); 1340 tvp = NULL; 1341 } 1342 } 1343 } 1344 if (va.va_mask & AT_SIZE) 1345 reqsize = va.va_size; 1346 } 1347 1348 /* 1349 * Must specify the mode. 1350 */ 1351 if (!(va.va_mask & AT_MODE)) { 1352 resp->status = NFS3ERR_INVAL; 1353 goto out1; 1354 } 1355 1356 /* 1357 * If the filesystem is exported with nosuid, then mask off 1358 * the setuid and setgid bits. 1359 */ 1360 if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID)) 1361 va.va_mode &= ~(VSUID | VSGID); 1362 1363 tryagain: 1364 /* 1365 * The file open mode used is VWRITE. If the client needs 1366 * some other semantic, then it should do the access checking 1367 * itself. It would have been nice to have the file open mode 1368 * passed as part of the arguments. 1369 */ 1370 error = VOP_CREATE(dvp, args->where.name, &va, excl, VWRITE, 1371 &vp, cr, 0); 1372 1373 #ifdef DEBUG 1374 if (rfs3_do_post_op_attr) { 1375 dava.va_mask = AT_ALL; 1376 davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava; 1377 } else 1378 davap = NULL; 1379 #else 1380 dava.va_mask = AT_ALL; 1381 davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava; 1382 #endif 1383 1384 if (error) { 1385 /* 1386 * If we got something other than file already exists 1387 * then just return this error. Otherwise, we got 1388 * EEXIST. If we were doing a GUARDED create, then 1389 * just return this error. Otherwise, we need to 1390 * make sure that this wasn't a duplicate of an 1391 * exclusive create request. 1392 * 1393 * The assumption is made that a non-exclusive create 1394 * request will never return EEXIST. 1395 */ 1396 if (error != EEXIST || args->how.mode == GUARDED) 1397 goto out; 1398 /* 1399 * Lookup the file so that we can get a vnode for it. 1400 */ 1401 error = VOP_LOOKUP(dvp, args->where.name, &vp, NULL, 0, 1402 NULL, cr); 1403 if (error) { 1404 /* 1405 * We couldn't find the file that we thought that 1406 * we just created. So, we'll just try creating 1407 * it again. 1408 */ 1409 if (error == ENOENT) 1410 goto tryagain; 1411 goto out; 1412 } 1413 1414 /* 1415 * If the file is delegated to a v4 client, go ahead 1416 * and initiate recall, this create is a hint that a 1417 * conflicting v3 open has occurred. 1418 */ 1419 1420 if (rfs4_check_delegated(FWRITE, vp, FALSE)) { 1421 VN_RELE(vp); 1422 resp->status = NFS3ERR_JUKEBOX; 1423 goto out1; 1424 } 1425 1426 va.va_mask = AT_ALL; 1427 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 1428 1429 mtime = (nfstime3 *)&args->how.createhow3_u.verf; 1430 /* % with INT32_MAX to prevent overflows */ 1431 if (args->how.mode == EXCLUSIVE && (vap == NULL || 1432 vap->va_mtime.tv_sec != 1433 (mtime->seconds % INT32_MAX) || 1434 vap->va_mtime.tv_nsec != mtime->nseconds)) { 1435 VN_RELE(vp); 1436 error = EEXIST; 1437 goto out; 1438 } 1439 } else { 1440 1441 if ((args->how.mode == UNCHECKED || 1442 args->how.mode == GUARDED) && 1443 args->how.createhow3_u.obj_attributes.size.set_it && 1444 va.va_size == 0) 1445 trunc = TRUE; 1446 else 1447 trunc = FALSE; 1448 1449 if (rfs4_check_delegated(FWRITE, vp, trunc)) { 1450 VN_RELE(vp); 1451 resp->status = NFS3ERR_JUKEBOX; 1452 goto out1; 1453 } 1454 1455 va.va_mask = AT_ALL; 1456 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 1457 1458 /* 1459 * We need to check to make sure that the file got 1460 * created to the indicated size. If not, we do a 1461 * setattr to try to change the size, but we don't 1462 * try too hard. This shouldn't a problem as most 1463 * clients will only specifiy a size of zero which 1464 * local file systems handle. However, even if 1465 * the client does specify a non-zero size, it can 1466 * still recover by checking the size of the file 1467 * after it has created it and then issue a setattr 1468 * request of its own to set the size of the file. 1469 */ 1470 if (vap != NULL && 1471 (args->how.mode == UNCHECKED || 1472 args->how.mode == GUARDED) && 1473 args->how.createhow3_u.obj_attributes.size.set_it && 1474 vap->va_size != reqsize) { 1475 va.va_mask = AT_SIZE; 1476 va.va_size = reqsize; 1477 (void) VOP_SETATTR(vp, &va, 0, cr, NULL); 1478 va.va_mask = AT_ALL; 1479 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 1480 } 1481 } 1482 1483 #ifdef DEBUG 1484 if (!rfs3_do_post_op_attr) 1485 vap = NULL; 1486 #endif 1487 1488 #ifdef DEBUG 1489 if (!rfs3_do_post_op_fh3) 1490 resp->resok.obj.handle_follows = FALSE; 1491 else { 1492 #endif 1493 error = makefh3(&resp->resok.obj.handle, vp, exi); 1494 if (error) 1495 resp->resok.obj.handle_follows = FALSE; 1496 else 1497 resp->resok.obj.handle_follows = TRUE; 1498 #ifdef DEBUG 1499 } 1500 #endif 1501 1502 /* 1503 * Force modified data and metadata out to stable storage. 1504 */ 1505 (void) VOP_FSYNC(vp, FNODSYNC, cr); 1506 (void) VOP_FSYNC(dvp, 0, cr); 1507 1508 VN_RELE(vp); 1509 VN_RELE(dvp); 1510 if (tvp != NULL) { 1511 if (in_crit) 1512 nbl_end_crit(tvp); 1513 VN_RELE(tvp); 1514 } 1515 1516 resp->status = NFS3_OK; 1517 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 1518 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 1519 return; 1520 1521 out: 1522 if (curthread->t_flag & T_WOULDBLOCK) { 1523 curthread->t_flag &= ~T_WOULDBLOCK; 1524 resp->status = NFS3ERR_JUKEBOX; 1525 } else 1526 resp->status = puterrno3(error); 1527 out1: 1528 if (tvp != NULL) { 1529 if (in_crit) 1530 nbl_end_crit(tvp); 1531 VN_RELE(tvp); 1532 } 1533 if (dvp != NULL) 1534 VN_RELE(dvp); 1535 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 1536 } 1537 1538 fhandle_t * 1539 rfs3_create_getfh(CREATE3args *args) 1540 { 1541 1542 return ((fhandle_t *)&args->where.dir.fh3_u.nfs_fh3_i.fh3_i); 1543 } 1544 1545 void 1546 rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi, 1547 struct svc_req *req, cred_t *cr) 1548 { 1549 int error; 1550 vnode_t *vp = NULL; 1551 vnode_t *dvp; 1552 struct vattr *vap; 1553 struct vattr va; 1554 struct vattr *dbvap; 1555 struct vattr dbva; 1556 struct vattr *davap; 1557 struct vattr dava; 1558 1559 dbvap = NULL; 1560 davap = NULL; 1561 1562 dvp = nfs3_fhtovp(args->where.dirp, exi); 1563 if (dvp == NULL) { 1564 error = ESTALE; 1565 goto out; 1566 } 1567 1568 #ifdef DEBUG 1569 if (rfs3_do_pre_op_attr) { 1570 dbva.va_mask = AT_ALL; 1571 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva; 1572 } else 1573 dbvap = NULL; 1574 #else 1575 dbva.va_mask = AT_ALL; 1576 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva; 1577 #endif 1578 davap = dbvap; 1579 1580 if (args->where.name == nfs3nametoolong) { 1581 resp->status = NFS3ERR_NAMETOOLONG; 1582 goto out1; 1583 } 1584 1585 if (args->where.name == NULL || *(args->where.name) == '\0') { 1586 resp->status = NFS3ERR_ACCES; 1587 goto out1; 1588 } 1589 1590 if (rdonly(exi, req)) { 1591 resp->status = NFS3ERR_ROFS; 1592 goto out1; 1593 } 1594 1595 error = sattr3_to_vattr(&args->attributes, &va); 1596 if (error) 1597 goto out; 1598 1599 if (!(va.va_mask & AT_MODE)) { 1600 resp->status = NFS3ERR_INVAL; 1601 goto out1; 1602 } 1603 1604 va.va_mask |= AT_TYPE; 1605 va.va_type = VDIR; 1606 1607 error = VOP_MKDIR(dvp, args->where.name, &va, &vp, cr); 1608 1609 #ifdef DEBUG 1610 if (rfs3_do_post_op_attr) { 1611 dava.va_mask = AT_ALL; 1612 davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava; 1613 } else 1614 davap = NULL; 1615 #else 1616 dava.va_mask = AT_ALL; 1617 davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava; 1618 #endif 1619 1620 /* 1621 * Force modified data and metadata out to stable storage. 1622 */ 1623 (void) VOP_FSYNC(dvp, 0, cr); 1624 1625 if (error) 1626 goto out; 1627 1628 VN_RELE(dvp); 1629 1630 #ifdef DEBUG 1631 if (!rfs3_do_post_op_fh3) 1632 resp->resok.obj.handle_follows = FALSE; 1633 else { 1634 #endif 1635 error = makefh3(&resp->resok.obj.handle, vp, exi); 1636 if (error) 1637 resp->resok.obj.handle_follows = FALSE; 1638 else 1639 resp->resok.obj.handle_follows = TRUE; 1640 #ifdef DEBUG 1641 } 1642 #endif 1643 1644 #ifdef DEBUG 1645 if (rfs3_do_post_op_attr) { 1646 va.va_mask = AT_ALL; 1647 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 1648 } else 1649 vap = NULL; 1650 #else 1651 va.va_mask = AT_ALL; 1652 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 1653 #endif 1654 1655 /* 1656 * Force modified data and metadata out to stable storage. 1657 */ 1658 (void) VOP_FSYNC(vp, 0, cr); 1659 1660 VN_RELE(vp); 1661 1662 resp->status = NFS3_OK; 1663 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 1664 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 1665 return; 1666 1667 out: 1668 if (curthread->t_flag & T_WOULDBLOCK) { 1669 curthread->t_flag &= ~T_WOULDBLOCK; 1670 resp->status = NFS3ERR_JUKEBOX; 1671 } else 1672 resp->status = puterrno3(error); 1673 out1: 1674 if (dvp != NULL) 1675 VN_RELE(dvp); 1676 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 1677 } 1678 1679 fhandle_t * 1680 rfs3_mkdir_getfh(MKDIR3args *args) 1681 { 1682 1683 return ((fhandle_t *)&args->where.dir.fh3_u.nfs_fh3_i.fh3_i); 1684 } 1685 1686 void 1687 rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi, 1688 struct svc_req *req, cred_t *cr) 1689 { 1690 int error; 1691 vnode_t *vp; 1692 vnode_t *dvp; 1693 struct vattr *vap; 1694 struct vattr va; 1695 struct vattr *dbvap; 1696 struct vattr dbva; 1697 struct vattr *davap; 1698 struct vattr dava; 1699 1700 dbvap = NULL; 1701 davap = NULL; 1702 1703 dvp = nfs3_fhtovp(args->where.dirp, exi); 1704 if (dvp == NULL) { 1705 error = ESTALE; 1706 goto out; 1707 } 1708 1709 #ifdef DEBUG 1710 if (rfs3_do_pre_op_attr) { 1711 dbva.va_mask = AT_ALL; 1712 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva; 1713 } else 1714 dbvap = NULL; 1715 #else 1716 dbva.va_mask = AT_ALL; 1717 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva; 1718 #endif 1719 davap = dbvap; 1720 1721 if (args->where.name == nfs3nametoolong) { 1722 resp->status = NFS3ERR_NAMETOOLONG; 1723 goto out1; 1724 } 1725 1726 if (args->where.name == NULL || *(args->where.name) == '\0') { 1727 resp->status = NFS3ERR_ACCES; 1728 goto out1; 1729 } 1730 1731 if (rdonly(exi, req)) { 1732 resp->status = NFS3ERR_ROFS; 1733 goto out1; 1734 } 1735 1736 error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va); 1737 if (error) 1738 goto out; 1739 1740 if (!(va.va_mask & AT_MODE)) { 1741 resp->status = NFS3ERR_INVAL; 1742 goto out1; 1743 } 1744 1745 if (args->symlink.symlink_data == nfs3nametoolong) { 1746 resp->status = NFS3ERR_NAMETOOLONG; 1747 goto out1; 1748 } 1749 1750 va.va_mask |= AT_TYPE; 1751 va.va_type = VLNK; 1752 1753 error = VOP_SYMLINK(dvp, args->where.name, &va, 1754 args->symlink.symlink_data, cr); 1755 1756 #ifdef DEBUG 1757 if (rfs3_do_post_op_attr) { 1758 dava.va_mask = AT_ALL; 1759 davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava; 1760 } else 1761 davap = NULL; 1762 #else 1763 dava.va_mask = AT_ALL; 1764 davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava; 1765 #endif 1766 1767 if (error) 1768 goto out; 1769 1770 error = VOP_LOOKUP(dvp, args->where.name, &vp, NULL, 0, NULL, cr); 1771 1772 /* 1773 * Force modified data and metadata out to stable storage. 1774 */ 1775 (void) VOP_FSYNC(dvp, 0, cr); 1776 1777 VN_RELE(dvp); 1778 1779 resp->status = NFS3_OK; 1780 if (error) { 1781 resp->resok.obj.handle_follows = FALSE; 1782 vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes); 1783 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 1784 return; 1785 } 1786 1787 #ifdef DEBUG 1788 if (!rfs3_do_post_op_fh3) 1789 resp->resok.obj.handle_follows = FALSE; 1790 else { 1791 #endif 1792 error = makefh3(&resp->resok.obj.handle, vp, exi); 1793 if (error) 1794 resp->resok.obj.handle_follows = FALSE; 1795 else 1796 resp->resok.obj.handle_follows = TRUE; 1797 #ifdef DEBUG 1798 } 1799 #endif 1800 1801 #ifdef DEBUG 1802 if (rfs3_do_post_op_attr) { 1803 va.va_mask = AT_ALL; 1804 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 1805 } else 1806 vap = NULL; 1807 #else 1808 va.va_mask = AT_ALL; 1809 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 1810 #endif 1811 1812 /* 1813 * Force modified data and metadata out to stable storage. 1814 */ 1815 (void) VOP_FSYNC(vp, 0, cr); 1816 1817 VN_RELE(vp); 1818 1819 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 1820 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 1821 return; 1822 1823 out: 1824 if (curthread->t_flag & T_WOULDBLOCK) { 1825 curthread->t_flag &= ~T_WOULDBLOCK; 1826 resp->status = NFS3ERR_JUKEBOX; 1827 } else 1828 resp->status = puterrno3(error); 1829 out1: 1830 if (dvp != NULL) 1831 VN_RELE(dvp); 1832 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 1833 } 1834 1835 fhandle_t * 1836 rfs3_symlink_getfh(SYMLINK3args *args) 1837 { 1838 1839 return ((fhandle_t *)&args->where.dirp->fh3_u.nfs_fh3_i.fh3_i); 1840 } 1841 1842 void 1843 rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi, 1844 struct svc_req *req, cred_t *cr) 1845 { 1846 int error; 1847 vnode_t *vp; 1848 vnode_t *dvp; 1849 struct vattr *vap; 1850 struct vattr va; 1851 struct vattr *dbvap; 1852 struct vattr dbva; 1853 struct vattr *davap; 1854 struct vattr dava; 1855 int mode; 1856 enum vcexcl excl; 1857 1858 dbvap = NULL; 1859 davap = NULL; 1860 1861 dvp = nfs3_fhtovp(args->where.dirp, exi); 1862 if (dvp == NULL) { 1863 error = ESTALE; 1864 goto out; 1865 } 1866 1867 #ifdef DEBUG 1868 if (rfs3_do_pre_op_attr) { 1869 dbva.va_mask = AT_ALL; 1870 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva; 1871 } else 1872 dbvap = NULL; 1873 #else 1874 dbva.va_mask = AT_ALL; 1875 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva; 1876 #endif 1877 davap = dbvap; 1878 1879 if (args->where.name == nfs3nametoolong) { 1880 resp->status = NFS3ERR_NAMETOOLONG; 1881 goto out1; 1882 } 1883 1884 if (args->where.name == NULL || *(args->where.name) == '\0') { 1885 resp->status = NFS3ERR_ACCES; 1886 goto out1; 1887 } 1888 1889 if (rdonly(exi, req)) { 1890 resp->status = NFS3ERR_ROFS; 1891 goto out1; 1892 } 1893 1894 switch (args->what.type) { 1895 case NF3CHR: 1896 case NF3BLK: 1897 error = sattr3_to_vattr( 1898 &args->what.mknoddata3_u.device.dev_attributes, &va); 1899 if (error) 1900 goto out; 1901 if (secpolicy_sys_devices(cr) != 0) { 1902 resp->status = NFS3ERR_PERM; 1903 goto out1; 1904 } 1905 if (args->what.type == NF3CHR) 1906 va.va_type = VCHR; 1907 else 1908 va.va_type = VBLK; 1909 va.va_rdev = makedevice( 1910 args->what.mknoddata3_u.device.spec.specdata1, 1911 args->what.mknoddata3_u.device.spec.specdata2); 1912 va.va_mask |= AT_TYPE | AT_RDEV; 1913 break; 1914 case NF3SOCK: 1915 error = sattr3_to_vattr( 1916 &args->what.mknoddata3_u.pipe_attributes, &va); 1917 if (error) 1918 goto out; 1919 va.va_type = VSOCK; 1920 va.va_mask |= AT_TYPE; 1921 break; 1922 case NF3FIFO: 1923 error = sattr3_to_vattr( 1924 &args->what.mknoddata3_u.pipe_attributes, &va); 1925 if (error) 1926 goto out; 1927 va.va_type = VFIFO; 1928 va.va_mask |= AT_TYPE; 1929 break; 1930 default: 1931 resp->status = NFS3ERR_BADTYPE; 1932 goto out1; 1933 } 1934 1935 /* 1936 * Must specify the mode. 1937 */ 1938 if (!(va.va_mask & AT_MODE)) { 1939 resp->status = NFS3ERR_INVAL; 1940 goto out1; 1941 } 1942 1943 excl = EXCL; 1944 1945 mode = 0; 1946 1947 error = VOP_CREATE(dvp, args->where.name, &va, excl, mode, 1948 &vp, cr, 0); 1949 1950 #ifdef DEBUG 1951 if (rfs3_do_post_op_attr) { 1952 dava.va_mask = AT_ALL; 1953 davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava; 1954 } else 1955 davap = NULL; 1956 #else 1957 dava.va_mask = AT_ALL; 1958 davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava; 1959 #endif 1960 1961 /* 1962 * Force modified data and metadata out to stable storage. 1963 */ 1964 (void) VOP_FSYNC(dvp, 0, cr); 1965 1966 if (error) 1967 goto out; 1968 1969 VN_RELE(dvp); 1970 1971 resp->status = NFS3_OK; 1972 1973 #ifdef DEBUG 1974 if (!rfs3_do_post_op_fh3) 1975 resp->resok.obj.handle_follows = FALSE; 1976 else { 1977 #endif 1978 error = makefh3(&resp->resok.obj.handle, vp, exi); 1979 if (error) 1980 resp->resok.obj.handle_follows = FALSE; 1981 else 1982 resp->resok.obj.handle_follows = TRUE; 1983 #ifdef DEBUG 1984 } 1985 #endif 1986 1987 #ifdef DEBUG 1988 if (rfs3_do_post_op_attr) { 1989 va.va_mask = AT_ALL; 1990 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 1991 } else 1992 vap = NULL; 1993 #else 1994 va.va_mask = AT_ALL; 1995 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 1996 #endif 1997 1998 /* 1999 * Force modified metadata out to stable storage. 2000 */ 2001 (void) VOP_FSYNC(vp, FNODSYNC, cr); 2002 2003 VN_RELE(vp); 2004 2005 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 2006 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 2007 return; 2008 2009 out: 2010 if (curthread->t_flag & T_WOULDBLOCK) { 2011 curthread->t_flag &= ~T_WOULDBLOCK; 2012 resp->status = NFS3ERR_JUKEBOX; 2013 } else 2014 resp->status = puterrno3(error); 2015 out1: 2016 if (dvp != NULL) 2017 VN_RELE(dvp); 2018 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 2019 } 2020 2021 fhandle_t * 2022 rfs3_mknod_getfh(MKNOD3args *args) 2023 { 2024 2025 return ((fhandle_t *)&args->where.dirp->fh3_u.nfs_fh3_i.fh3_i); 2026 } 2027 2028 void 2029 rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi, 2030 struct svc_req *req, cred_t *cr) 2031 { 2032 int error = 0; 2033 vnode_t *vp; 2034 struct vattr *bvap; 2035 struct vattr bva; 2036 struct vattr *avap; 2037 struct vattr ava; 2038 vnode_t *targvp = NULL; 2039 2040 bvap = NULL; 2041 avap = NULL; 2042 2043 vp = nfs3_fhtovp(args->object.dirp, exi); 2044 if (vp == NULL) { 2045 error = ESTALE; 2046 goto out; 2047 } 2048 2049 #ifdef DEBUG 2050 if (rfs3_do_pre_op_attr) { 2051 bva.va_mask = AT_ALL; 2052 bvap = VOP_GETATTR(vp, &bva, 0, cr) ? NULL : &bva; 2053 } else 2054 bvap = NULL; 2055 #else 2056 bva.va_mask = AT_ALL; 2057 bvap = VOP_GETATTR(vp, &bva, 0, cr) ? NULL : &bva; 2058 #endif 2059 avap = bvap; 2060 2061 if (vp->v_type != VDIR) { 2062 resp->status = NFS3ERR_NOTDIR; 2063 goto out1; 2064 } 2065 2066 if (args->object.name == nfs3nametoolong) { 2067 resp->status = NFS3ERR_NAMETOOLONG; 2068 goto out1; 2069 } 2070 2071 if (args->object.name == NULL || *(args->object.name) == '\0') { 2072 resp->status = NFS3ERR_ACCES; 2073 goto out1; 2074 } 2075 2076 if (rdonly(exi, req)) { 2077 resp->status = NFS3ERR_ROFS; 2078 goto out1; 2079 } 2080 2081 /* 2082 * Check for a conflict with a non-blocking mandatory share 2083 * reservation and V4 delegations 2084 */ 2085 error = VOP_LOOKUP(vp, args->object.name, &targvp, NULL, 0, 2086 NULL, cr); 2087 if (error != 0) 2088 goto out; 2089 2090 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) { 2091 resp->status = NFS3ERR_JUKEBOX; 2092 goto out1; 2093 } 2094 2095 if (!nbl_need_check(targvp)) { 2096 error = VOP_REMOVE(vp, args->object.name, cr); 2097 } else { 2098 nbl_start_crit(targvp, RW_READER); 2099 if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0)) { 2100 error = EACCES; 2101 } else { 2102 error = VOP_REMOVE(vp, args->object.name, cr); 2103 } 2104 nbl_end_crit(targvp); 2105 } 2106 VN_RELE(targvp); 2107 targvp = NULL; 2108 2109 #ifdef DEBUG 2110 if (rfs3_do_post_op_attr) { 2111 ava.va_mask = AT_ALL; 2112 avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava; 2113 } else 2114 avap = NULL; 2115 #else 2116 ava.va_mask = AT_ALL; 2117 avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava; 2118 #endif 2119 2120 /* 2121 * Force modified data and metadata out to stable storage. 2122 */ 2123 (void) VOP_FSYNC(vp, 0, cr); 2124 2125 if (error) 2126 goto out; 2127 2128 VN_RELE(vp); 2129 2130 resp->status = NFS3_OK; 2131 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc); 2132 return; 2133 2134 out: 2135 if (curthread->t_flag & T_WOULDBLOCK) { 2136 curthread->t_flag &= ~T_WOULDBLOCK; 2137 resp->status = NFS3ERR_JUKEBOX; 2138 } else 2139 resp->status = puterrno3(error); 2140 out1: 2141 if (vp != NULL) 2142 VN_RELE(vp); 2143 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc); 2144 } 2145 2146 fhandle_t * 2147 rfs3_remove_getfh(REMOVE3args *args) 2148 { 2149 2150 return ((fhandle_t *)&args->object.dirp->fh3_u.nfs_fh3_i.fh3_i); 2151 } 2152 2153 void 2154 rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi, 2155 struct svc_req *req, cred_t *cr) 2156 { 2157 int error; 2158 vnode_t *vp; 2159 struct vattr *bvap; 2160 struct vattr bva; 2161 struct vattr *avap; 2162 struct vattr ava; 2163 2164 bvap = NULL; 2165 avap = NULL; 2166 2167 vp = nfs3_fhtovp(args->object.dirp, exi); 2168 if (vp == NULL) { 2169 error = ESTALE; 2170 goto out; 2171 } 2172 2173 #ifdef DEBUG 2174 if (rfs3_do_pre_op_attr) { 2175 bva.va_mask = AT_ALL; 2176 bvap = VOP_GETATTR(vp, &bva, 0, cr) ? NULL : &bva; 2177 } else 2178 bvap = NULL; 2179 #else 2180 bva.va_mask = AT_ALL; 2181 bvap = VOP_GETATTR(vp, &bva, 0, cr) ? NULL : &bva; 2182 #endif 2183 avap = bvap; 2184 2185 if (vp->v_type != VDIR) { 2186 resp->status = NFS3ERR_NOTDIR; 2187 goto out1; 2188 } 2189 2190 if (args->object.name == nfs3nametoolong) { 2191 resp->status = NFS3ERR_NAMETOOLONG; 2192 goto out1; 2193 } 2194 2195 if (args->object.name == NULL || *(args->object.name) == '\0') { 2196 resp->status = NFS3ERR_ACCES; 2197 goto out1; 2198 } 2199 2200 if (rdonly(exi, req)) { 2201 resp->status = NFS3ERR_ROFS; 2202 goto out1; 2203 } 2204 2205 error = VOP_RMDIR(vp, args->object.name, rootdir, cr); 2206 2207 #ifdef DEBUG 2208 if (rfs3_do_post_op_attr) { 2209 ava.va_mask = AT_ALL; 2210 avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava; 2211 } else 2212 avap = NULL; 2213 #else 2214 ava.va_mask = AT_ALL; 2215 avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava; 2216 #endif 2217 2218 /* 2219 * Force modified data and metadata out to stable storage. 2220 */ 2221 (void) VOP_FSYNC(vp, 0, cr); 2222 2223 if (error) { 2224 /* 2225 * System V defines rmdir to return EEXIST, not ENOTEMPTY, 2226 * if the directory is not empty. A System V NFS server 2227 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit 2228 * over the wire. 2229 */ 2230 if (error == EEXIST) 2231 error = ENOTEMPTY; 2232 goto out; 2233 } 2234 2235 VN_RELE(vp); 2236 2237 resp->status = NFS3_OK; 2238 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc); 2239 return; 2240 2241 out: 2242 if (curthread->t_flag & T_WOULDBLOCK) { 2243 curthread->t_flag &= ~T_WOULDBLOCK; 2244 resp->status = NFS3ERR_JUKEBOX; 2245 } else 2246 resp->status = puterrno3(error); 2247 out1: 2248 if (vp != NULL) 2249 VN_RELE(vp); 2250 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc); 2251 } 2252 2253 fhandle_t * 2254 rfs3_rmdir_getfh(RMDIR3args *args) 2255 { 2256 2257 return ((fhandle_t *)&args->object.dirp->fh3_u.nfs_fh3_i.fh3_i); 2258 } 2259 2260 void 2261 rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi, 2262 struct svc_req *req, cred_t *cr) 2263 { 2264 int error = 0; 2265 vnode_t *fvp; 2266 vnode_t *tvp; 2267 vnode_t *targvp; 2268 struct vattr *fbvap; 2269 struct vattr fbva; 2270 struct vattr *favap; 2271 struct vattr fava; 2272 struct vattr *tbvap; 2273 struct vattr tbva; 2274 struct vattr *tavap; 2275 struct vattr tava; 2276 nfs_fh3 *fh3; 2277 struct exportinfo *to_exi; 2278 vnode_t *srcvp = NULL; 2279 2280 fbvap = NULL; 2281 favap = NULL; 2282 tbvap = NULL; 2283 tavap = NULL; 2284 tvp = NULL; 2285 2286 fvp = nfs3_fhtovp(args->from.dirp, exi); 2287 if (fvp == NULL) { 2288 error = ESTALE; 2289 goto out; 2290 } 2291 2292 #ifdef DEBUG 2293 if (rfs3_do_pre_op_attr) { 2294 fbva.va_mask = AT_ALL; 2295 fbvap = VOP_GETATTR(fvp, &fbva, 0, cr) ? NULL : &fbva; 2296 } else 2297 fbvap = NULL; 2298 #else 2299 fbva.va_mask = AT_ALL; 2300 fbvap = VOP_GETATTR(fvp, &fbva, 0, cr) ? NULL : &fbva; 2301 #endif 2302 favap = fbvap; 2303 2304 fh3 = args->to.dirp; 2305 to_exi = checkexport(&fh3->fh3_fsid, (fid_t *)&fh3->fh3_xlen); 2306 if (to_exi == NULL) { 2307 resp->status = NFS3ERR_ACCES; 2308 goto out1; 2309 } 2310 exi_rele(to_exi); 2311 2312 if (to_exi != exi) { 2313 resp->status = NFS3ERR_XDEV; 2314 goto out1; 2315 } 2316 2317 tvp = nfs3_fhtovp(args->to.dirp, exi); 2318 if (tvp == NULL) { 2319 error = ESTALE; 2320 goto out; 2321 } 2322 2323 #ifdef DEBUG 2324 if (rfs3_do_pre_op_attr) { 2325 tbva.va_mask = AT_ALL; 2326 tbvap = VOP_GETATTR(tvp, &tbva, 0, cr) ? NULL : &tbva; 2327 } else 2328 tbvap = NULL; 2329 #else 2330 tbva.va_mask = AT_ALL; 2331 tbvap = VOP_GETATTR(tvp, &tbva, 0, cr) ? NULL : &tbva; 2332 #endif 2333 tavap = tbvap; 2334 2335 if (fvp->v_type != VDIR || tvp->v_type != VDIR) { 2336 resp->status = NFS3ERR_NOTDIR; 2337 goto out1; 2338 } 2339 2340 if (args->from.name == nfs3nametoolong || 2341 args->to.name == nfs3nametoolong) { 2342 resp->status = NFS3ERR_NAMETOOLONG; 2343 goto out1; 2344 } 2345 if (args->from.name == NULL || *(args->from.name) == '\0' || 2346 args->to.name == NULL || *(args->to.name) == '\0') { 2347 resp->status = NFS3ERR_ACCES; 2348 goto out1; 2349 } 2350 2351 if (rdonly(exi, req)) { 2352 resp->status = NFS3ERR_ROFS; 2353 goto out1; 2354 } 2355 2356 /* 2357 * Check for a conflict with a non-blocking mandatory share 2358 * reservation or V4 delegations. 2359 */ 2360 error = VOP_LOOKUP(fvp, args->from.name, &srcvp, NULL, 0, 2361 NULL, cr); 2362 if (error != 0) 2363 goto out; 2364 2365 /* 2366 * If we rename a delegated file we should recall the 2367 * delegation, since future opens should fail or would 2368 * refer to a new file. 2369 */ 2370 if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) { 2371 resp->status = NFS3ERR_JUKEBOX; 2372 goto out1; 2373 } 2374 2375 /* 2376 * Check for renaming over a delegated file. Check rfs4_deleg_policy 2377 * first to avoid VOP_LOOKUP if possible. 2378 */ 2379 if (rfs4_deleg_policy != SRV_NEVER_DELEGATE && 2380 VOP_LOOKUP(tvp, args->to.name, &targvp, NULL, 0, NULL, cr) == 0) { 2381 2382 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) { 2383 VN_RELE(targvp); 2384 resp->status = NFS3ERR_JUKEBOX; 2385 goto out1; 2386 } 2387 VN_RELE(targvp); 2388 } 2389 2390 if (!nbl_need_check(srcvp)) { 2391 error = VOP_RENAME(fvp, args->from.name, tvp, 2392 args->to.name, cr); 2393 } else { 2394 nbl_start_crit(srcvp, RW_READER); 2395 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0)) { 2396 error = EACCES; 2397 } else { 2398 error = VOP_RENAME(fvp, args->from.name, tvp, 2399 args->to.name, cr); 2400 } 2401 nbl_end_crit(srcvp); 2402 } 2403 VN_RELE(srcvp); 2404 srcvp = NULL; 2405 2406 #ifdef DEBUG 2407 if (rfs3_do_post_op_attr) { 2408 fava.va_mask = AT_ALL; 2409 favap = VOP_GETATTR(fvp, &fava, 0, cr) ? NULL : &fava; 2410 tava.va_mask = AT_ALL; 2411 tavap = VOP_GETATTR(tvp, &tava, 0, cr) ? NULL : &tava; 2412 } else { 2413 favap = NULL; 2414 tavap = NULL; 2415 } 2416 #else 2417 fava.va_mask = AT_ALL; 2418 favap = VOP_GETATTR(fvp, &fava, 0, cr) ? NULL : &fava; 2419 tava.va_mask = AT_ALL; 2420 tavap = VOP_GETATTR(tvp, &tava, 0, cr) ? NULL : &tava; 2421 #endif 2422 2423 /* 2424 * Force modified data and metadata out to stable storage. 2425 */ 2426 (void) VOP_FSYNC(fvp, 0, cr); 2427 (void) VOP_FSYNC(tvp, 0, cr); 2428 2429 if (error) 2430 goto out; 2431 2432 VN_RELE(tvp); 2433 VN_RELE(fvp); 2434 2435 resp->status = NFS3_OK; 2436 vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc); 2437 vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc); 2438 return; 2439 2440 out: 2441 if (curthread->t_flag & T_WOULDBLOCK) { 2442 curthread->t_flag &= ~T_WOULDBLOCK; 2443 resp->status = NFS3ERR_JUKEBOX; 2444 } else 2445 resp->status = puterrno3(error); 2446 out1: 2447 if (fvp != NULL) 2448 VN_RELE(fvp); 2449 if (tvp != NULL) 2450 VN_RELE(tvp); 2451 vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc); 2452 vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc); 2453 } 2454 2455 fhandle_t * 2456 rfs3_rename_getfh(RENAME3args *args) 2457 { 2458 2459 return ((fhandle_t *)&args->from.dirp->fh3_u.nfs_fh3_i.fh3_i); 2460 } 2461 2462 void 2463 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi, 2464 struct svc_req *req, cred_t *cr) 2465 { 2466 int error; 2467 vnode_t *vp; 2468 vnode_t *dvp; 2469 struct vattr *vap; 2470 struct vattr va; 2471 struct vattr *bvap; 2472 struct vattr bva; 2473 struct vattr *avap; 2474 struct vattr ava; 2475 nfs_fh3 *fh3; 2476 struct exportinfo *to_exi; 2477 2478 vap = NULL; 2479 bvap = NULL; 2480 avap = NULL; 2481 dvp = NULL; 2482 2483 vp = nfs3_fhtovp(&args->file, exi); 2484 if (vp == NULL) { 2485 error = ESTALE; 2486 goto out; 2487 } 2488 2489 #ifdef DEBUG 2490 if (rfs3_do_pre_op_attr) { 2491 va.va_mask = AT_ALL; 2492 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2493 } else 2494 vap = NULL; 2495 #else 2496 va.va_mask = AT_ALL; 2497 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2498 #endif 2499 2500 fh3 = args->link.dirp; 2501 to_exi = checkexport(&fh3->fh3_fsid, (fid_t *)&fh3->fh3_xlen); 2502 if (to_exi == NULL) { 2503 resp->status = NFS3ERR_ACCES; 2504 goto out1; 2505 } 2506 exi_rele(to_exi); 2507 2508 if (to_exi != exi) { 2509 resp->status = NFS3ERR_XDEV; 2510 goto out1; 2511 } 2512 2513 dvp = nfs3_fhtovp(args->link.dirp, exi); 2514 if (dvp == NULL) { 2515 error = ESTALE; 2516 goto out; 2517 } 2518 2519 #ifdef DEBUG 2520 if (rfs3_do_pre_op_attr) { 2521 bva.va_mask = AT_ALL; 2522 bvap = VOP_GETATTR(dvp, &bva, 0, cr) ? NULL : &bva; 2523 } else 2524 bvap = NULL; 2525 #else 2526 bva.va_mask = AT_ALL; 2527 bvap = VOP_GETATTR(dvp, &bva, 0, cr) ? NULL : &bva; 2528 #endif 2529 2530 if (dvp->v_type != VDIR) { 2531 resp->status = NFS3ERR_NOTDIR; 2532 goto out1; 2533 } 2534 2535 if (args->link.name == nfs3nametoolong) { 2536 resp->status = NFS3ERR_NAMETOOLONG; 2537 goto out1; 2538 } 2539 2540 if (args->link.name == NULL || *(args->link.name) == '\0') { 2541 resp->status = NFS3ERR_ACCES; 2542 goto out1; 2543 } 2544 2545 if (rdonly(exi, req)) { 2546 resp->status = NFS3ERR_ROFS; 2547 goto out1; 2548 } 2549 2550 error = VOP_LINK(dvp, vp, args->link.name, cr); 2551 2552 #ifdef DEBUG 2553 if (rfs3_do_post_op_attr) { 2554 va.va_mask = AT_ALL; 2555 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2556 ava.va_mask = AT_ALL; 2557 avap = VOP_GETATTR(dvp, &ava, 0, cr) ? NULL : &ava; 2558 } else { 2559 vap = NULL; 2560 avap = NULL; 2561 } 2562 #else 2563 va.va_mask = AT_ALL; 2564 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2565 ava.va_mask = AT_ALL; 2566 avap = VOP_GETATTR(dvp, &ava, 0, cr) ? NULL : &ava; 2567 #endif 2568 2569 /* 2570 * Force modified data and metadata out to stable storage. 2571 */ 2572 (void) VOP_FSYNC(vp, FNODSYNC, cr); 2573 (void) VOP_FSYNC(dvp, 0, cr); 2574 2575 if (error) 2576 goto out; 2577 2578 VN_RELE(dvp); 2579 VN_RELE(vp); 2580 2581 resp->status = NFS3_OK; 2582 vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 2583 vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc); 2584 return; 2585 2586 out: 2587 if (curthread->t_flag & T_WOULDBLOCK) { 2588 curthread->t_flag &= ~T_WOULDBLOCK; 2589 resp->status = NFS3ERR_JUKEBOX; 2590 } else 2591 resp->status = puterrno3(error); 2592 out1: 2593 if (vp != NULL) 2594 VN_RELE(vp); 2595 if (dvp != NULL) 2596 VN_RELE(dvp); 2597 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes); 2598 vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc); 2599 } 2600 2601 fhandle_t * 2602 rfs3_link_getfh(LINK3args *args) 2603 { 2604 2605 return ((fhandle_t *)&args->file.fh3_u.nfs_fh3_i.fh3_i); 2606 } 2607 2608 /* 2609 * This macro defines the size of a response which contains attribute 2610 * information and one directory entry (whose length is specified by 2611 * the macro parameter). If the incoming request is larger than this, 2612 * then we are guaranteed to be able to return at one directory entry 2613 * if one exists. Therefore, we do not need to check for 2614 * NFS3ERR_TOOSMALL if the requested size is larger then this. If it 2615 * is not, then we need to check to make sure that this error does not 2616 * need to be returned. 2617 * 2618 * NFS3_READDIR_MIN_COUNT is comprised of following : 2619 * 2620 * status - 1 * BYTES_PER_XDR_UNIT 2621 * attr. flag - 1 * BYTES_PER_XDR_UNIT 2622 * cookie verifier - 2 * BYTES_PER_XDR_UNIT 2623 * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT 2624 * boolean - 1 * BYTES_PER_XDR_UNIT 2625 * file id - 2 * BYTES_PER_XDR_UNIT 2626 * direcotory name length - 1 * BYTES_PER_XDR_UNIT 2627 * cookie - 2 * BYTES_PER_XDR_UNIT 2628 * end of list - 1 * BYTES_PER_XDR_UNIT 2629 * end of file - 1 * BYTES_PER_XDR_UNIT 2630 * Name length of directory to the nearest byte 2631 */ 2632 2633 #define NFS3_READDIR_MIN_COUNT(length) \ 2634 ((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \ 2635 BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT)) 2636 2637 /* ARGSUSED */ 2638 void 2639 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi, 2640 struct svc_req *req, cred_t *cr) 2641 { 2642 int error; 2643 vnode_t *vp; 2644 struct vattr *vap; 2645 struct vattr va; 2646 struct iovec iov; 2647 struct uio uio; 2648 char *data; 2649 int iseof; 2650 int bufsize; 2651 int namlen; 2652 uint_t count; 2653 2654 vap = NULL; 2655 2656 vp = nfs3_fhtovp(&args->dir, exi); 2657 if (vp == NULL) { 2658 error = ESTALE; 2659 goto out; 2660 } 2661 2662 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 2663 2664 #ifdef DEBUG 2665 if (rfs3_do_pre_op_attr) { 2666 va.va_mask = AT_ALL; 2667 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2668 } else 2669 vap = NULL; 2670 #else 2671 va.va_mask = AT_ALL; 2672 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2673 #endif 2674 2675 if (vp->v_type != VDIR) { 2676 resp->status = NFS3ERR_NOTDIR; 2677 goto out1; 2678 } 2679 2680 error = VOP_ACCESS(vp, VREAD, 0, cr); 2681 if (error) 2682 goto out; 2683 2684 /* 2685 * Now don't allow arbitrary count to alloc; 2686 * allow the maximum not to exceed rfs3_tsize() 2687 */ 2688 if (args->count > rfs3_tsize(req)) 2689 args->count = rfs3_tsize(req); 2690 2691 /* 2692 * Make sure that there is room to read at least one entry 2693 * if any are available. 2694 */ 2695 if (args->count < DIRENT64_RECLEN(MAXNAMELEN)) 2696 count = DIRENT64_RECLEN(MAXNAMELEN); 2697 else 2698 count = args->count; 2699 2700 data = kmem_alloc(count, KM_SLEEP); 2701 2702 iov.iov_base = data; 2703 iov.iov_len = count; 2704 uio.uio_iov = &iov; 2705 uio.uio_iovcnt = 1; 2706 uio.uio_segflg = UIO_SYSSPACE; 2707 uio.uio_extflg = UIO_COPY_CACHED; 2708 uio.uio_loffset = (offset_t)args->cookie; 2709 uio.uio_resid = count; 2710 2711 error = VOP_READDIR(vp, &uio, cr, &iseof); 2712 2713 #ifdef DEBUG 2714 if (rfs3_do_post_op_attr) { 2715 va.va_mask = AT_ALL; 2716 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2717 } else 2718 vap = NULL; 2719 #else 2720 va.va_mask = AT_ALL; 2721 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2722 #endif 2723 2724 if (error) { 2725 kmem_free(data, count); 2726 goto out; 2727 } 2728 2729 /* 2730 * If the count was not large enough to be able to guarantee 2731 * to be able to return at least one entry, then need to 2732 * check to see if NFS3ERR_TOOSMALL should be returned. 2733 */ 2734 if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) { 2735 /* 2736 * bufsize is used to keep track of the size of the response. 2737 * It is primed with: 2738 * 1 for the status + 2739 * 1 for the dir_attributes.attributes boolean + 2740 * 2 for the cookie verifier 2741 * all times BYTES_PER_XDR_UNIT to convert from XDR units 2742 * to bytes. If there are directory attributes to be 2743 * returned, then: 2744 * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3 2745 * time BYTES_PER_XDR_UNIT is added to account for them. 2746 */ 2747 bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT; 2748 if (vap != NULL) 2749 bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT; 2750 /* 2751 * An entry is composed of: 2752 * 1 for the true/false list indicator + 2753 * 2 for the fileid + 2754 * 1 for the length of the name + 2755 * 2 for the cookie + 2756 * all times BYTES_PER_XDR_UNIT to convert from 2757 * XDR units to bytes, plus the length of the name 2758 * rounded up to the nearest BYTES_PER_XDR_UNIT. 2759 */ 2760 if (count != uio.uio_resid) { 2761 namlen = strlen(((struct dirent64 *)data)->d_name); 2762 bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT + 2763 roundup(namlen, BYTES_PER_XDR_UNIT); 2764 } 2765 /* 2766 * We need to check to see if the number of bytes left 2767 * to go into the buffer will actually fit into the 2768 * buffer. This is calculated as the size of this 2769 * entry plus: 2770 * 1 for the true/false list indicator + 2771 * 1 for the eof indicator 2772 * times BYTES_PER_XDR_UNIT to convert from from 2773 * XDR units to bytes. 2774 */ 2775 bufsize += (1 + 1) * BYTES_PER_XDR_UNIT; 2776 if (bufsize > args->count) { 2777 kmem_free(data, count); 2778 resp->status = NFS3ERR_TOOSMALL; 2779 goto out1; 2780 } 2781 } 2782 2783 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 2784 2785 #if 0 /* notyet */ 2786 /* 2787 * Don't do this. It causes local disk writes when just 2788 * reading the file and the overhead is deemed larger 2789 * than the benefit. 2790 */ 2791 /* 2792 * Force modified metadata out to stable storage. 2793 */ 2794 (void) VOP_FSYNC(vp, FNODSYNC, cr); 2795 #endif 2796 2797 VN_RELE(vp); 2798 2799 resp->status = NFS3_OK; 2800 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes); 2801 resp->resok.cookieverf = 0; 2802 resp->resok.reply.entries = (entry3 *)data; 2803 resp->resok.reply.eof = iseof; 2804 resp->resok.size = count - uio.uio_resid; 2805 resp->resok.count = args->count; 2806 resp->resok.freecount = count; 2807 return; 2808 2809 out: 2810 if (curthread->t_flag & T_WOULDBLOCK) { 2811 curthread->t_flag &= ~T_WOULDBLOCK; 2812 resp->status = NFS3ERR_JUKEBOX; 2813 } else 2814 resp->status = puterrno3(error); 2815 out1: 2816 if (vp != NULL) { 2817 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 2818 VN_RELE(vp); 2819 } 2820 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes); 2821 } 2822 2823 fhandle_t * 2824 rfs3_readdir_getfh(READDIR3args *args) 2825 { 2826 2827 return ((fhandle_t *)&args->dir.fh3_u.nfs_fh3_i.fh3_i); 2828 } 2829 2830 void 2831 rfs3_readdir_free(READDIR3res *resp) 2832 { 2833 2834 if (resp->status == NFS3_OK) 2835 kmem_free(resp->resok.reply.entries, resp->resok.freecount); 2836 } 2837 2838 #ifdef nextdp 2839 #undef nextdp 2840 #endif 2841 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) 2842 2843 /* 2844 * This macro computes the size of a response which contains 2845 * one directory entry including the attributes as well as file handle. 2846 * If the incoming request is larger than this, then we are guaranteed to be 2847 * able to return at least one more directory entry if one exists. 2848 * 2849 * NFS3_READDIRPLUS_ENTRY is made up of the following: 2850 * 2851 * boolean - 1 * BYTES_PER_XDR_UNIT 2852 * file id - 2 * BYTES_PER_XDR_UNIT 2853 * directory name length - 1 * BYTES_PER_XDR_UNIT 2854 * cookie - 2 * BYTES_PER_XDR_UNIT 2855 * attribute flag - 1 * BYTES_PER_XDR_UNIT 2856 * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT 2857 * status byte for file handle - 1 * BYTES_PER_XDR_UNIT 2858 * length of a file handle - 1 * BYTES_PER_XDR_UNIT 2859 * Maxmum length of a file handle (NFS3_CURFHSIZE) 2860 * name length of the entry to the nearest bytes 2861 */ 2862 #define NFS3_READDIRPLUS_ENTRY(namelen) \ 2863 ((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \ 2864 BYTES_PER_XDR_UNIT + \ 2865 NFS3_CURFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT)) 2866 2867 static int rfs3_readdir_unit = MAXBSIZE; 2868 2869 /* ARGSUSED */ 2870 void 2871 rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp, 2872 struct exportinfo *exi, struct svc_req *req, cred_t *cr) 2873 { 2874 int error; 2875 vnode_t *vp; 2876 struct vattr *vap; 2877 struct vattr va; 2878 struct iovec iov; 2879 struct uio uio; 2880 char *data; 2881 int iseof; 2882 struct dirent64 *dp; 2883 vnode_t *nvp; 2884 struct vattr *nvap; 2885 struct vattr nva; 2886 entryplus3_info *infop = NULL; 2887 int size = 0; 2888 int nents = 0; 2889 int bufsize = 0; 2890 int entrysize = 0; 2891 int tofit = 0; 2892 int rd_unit = rfs3_readdir_unit; 2893 int prev_len; 2894 int space_left; 2895 int i; 2896 uint_t *namlen = NULL; 2897 2898 vap = NULL; 2899 2900 vp = nfs3_fhtovp(&args->dir, exi); 2901 if (vp == NULL) { 2902 error = ESTALE; 2903 goto out; 2904 } 2905 2906 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 2907 2908 #ifdef DEBUG 2909 if (rfs3_do_pre_op_attr) { 2910 va.va_mask = AT_ALL; 2911 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2912 } else 2913 vap = NULL; 2914 #else 2915 va.va_mask = AT_ALL; 2916 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2917 #endif 2918 2919 if (vp->v_type != VDIR) { 2920 error = ENOTDIR; 2921 goto out; 2922 } 2923 2924 error = VOP_ACCESS(vp, VREAD, 0, cr); 2925 if (error) 2926 goto out; 2927 2928 /* 2929 * Don't allow arbitrary counts for allocation 2930 */ 2931 if (args->maxcount > rfs3_tsize(req)) 2932 args->maxcount = rfs3_tsize(req); 2933 2934 /* 2935 * Make sure that there is room to read at least one entry 2936 * if any are available 2937 */ 2938 args->dircount = MIN(args->dircount, args->maxcount); 2939 2940 if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN)) 2941 args->dircount = DIRENT64_RECLEN(MAXNAMELEN); 2942 2943 /* 2944 * This allocation relies on a minimum directory entry 2945 * being roughly 24 bytes. Therefore, the namlen array 2946 * will have enough space based on the maximum number of 2947 * entries to read. 2948 */ 2949 namlen = kmem_alloc(args->dircount, KM_SLEEP); 2950 2951 space_left = args->dircount; 2952 data = kmem_alloc(args->dircount, KM_SLEEP); 2953 dp = (struct dirent64 *)data; 2954 uio.uio_iov = &iov; 2955 uio.uio_iovcnt = 1; 2956 uio.uio_segflg = UIO_SYSSPACE; 2957 uio.uio_extflg = UIO_COPY_CACHED; 2958 uio.uio_loffset = (offset_t)args->cookie; 2959 2960 /* 2961 * bufsize is used to keep track of the size of the response as we 2962 * get post op attributes and filehandles for each entry. This is 2963 * an optimization as the server may have read more entries than will 2964 * fit in the buffer specified by maxcount. We stop calculating 2965 * post op attributes and filehandles once we have exceeded maxcount. 2966 * This will minimize the effect of truncation. 2967 * 2968 * It is primed with: 2969 * 1 for the status + 2970 * 1 for the dir_attributes.attributes boolean + 2971 * 2 for the cookie verifier 2972 * all times BYTES_PER_XDR_UNIT to convert from XDR units 2973 * to bytes. If there are directory attributes to be 2974 * returned, then: 2975 * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3 2976 * time BYTES_PER_XDR_UNIT is added to account for them. 2977 */ 2978 bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT; 2979 if (vap != NULL) 2980 bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT; 2981 2982 getmoredents: 2983 /* 2984 * Here we make a check so that our read unit is not larger than 2985 * the space left in the buffer. 2986 */ 2987 rd_unit = MIN(rd_unit, space_left); 2988 iov.iov_base = (char *)dp; 2989 iov.iov_len = rd_unit; 2990 uio.uio_resid = rd_unit; 2991 prev_len = rd_unit; 2992 2993 error = VOP_READDIR(vp, &uio, cr, &iseof); 2994 2995 if (error) { 2996 kmem_free(data, args->dircount); 2997 goto out; 2998 } 2999 3000 if (uio.uio_resid == prev_len && !iseof) { 3001 if (nents == 0) { 3002 kmem_free(data, args->dircount); 3003 resp->status = NFS3ERR_TOOSMALL; 3004 goto out1; 3005 } 3006 3007 /* 3008 * We could not get any more entries, so get the attributes 3009 * and filehandle for the entries already obtained. 3010 */ 3011 goto good; 3012 } 3013 3014 /* 3015 * We estimate the size of the response by assuming the 3016 * entry exists and attributes and filehandle are also valid 3017 */ 3018 for (size = prev_len - uio.uio_resid; 3019 size > 0; 3020 size -= dp->d_reclen, dp = nextdp(dp)) { 3021 3022 if (dp->d_ino == 0) { 3023 nents++; 3024 continue; 3025 } 3026 3027 namlen[nents] = strlen(dp->d_name); 3028 entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]); 3029 3030 /* 3031 * We need to check to see if the number of bytes left 3032 * to go into the buffer will actually fit into the 3033 * buffer. This is calculated as the size of this 3034 * entry plus: 3035 * 1 for the true/false list indicator + 3036 * 1 for the eof indicator 3037 * times BYTES_PER_XDR_UNIT to convert from XDR units 3038 * to bytes. 3039 * 3040 * Also check the dircount limit against the first entry read 3041 * 3042 */ 3043 tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT; 3044 if (bufsize + tofit > args->maxcount) { 3045 /* 3046 * We make a check here to see if this was the 3047 * first entry being measured. If so, then maxcount 3048 * was too small to begin with and so we need to 3049 * return with NFS3ERR_TOOSMALL. 3050 */ 3051 if (nents == 0) { 3052 kmem_free(data, args->dircount); 3053 resp->status = NFS3ERR_TOOSMALL; 3054 goto out1; 3055 } 3056 iseof = FALSE; 3057 goto good; 3058 } 3059 bufsize += entrysize; 3060 nents++; 3061 } 3062 3063 /* 3064 * If there is enough room to fit at least 1 more entry including 3065 * post op attributes and filehandle in the buffer AND that we haven't 3066 * exceeded dircount then go back and get some more. 3067 */ 3068 if (!iseof && 3069 (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) { 3070 space_left -= (prev_len - uio.uio_resid); 3071 if (space_left >= DIRENT64_RECLEN(MAXNAMELEN)) 3072 goto getmoredents; 3073 3074 /* else, fall through */ 3075 } 3076 3077 good: 3078 3079 #ifdef DEBUG 3080 if (rfs3_do_post_op_attr) { 3081 va.va_mask = AT_ALL; 3082 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3083 } else 3084 vap = NULL; 3085 #else 3086 va.va_mask = AT_ALL; 3087 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3088 #endif 3089 3090 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 3091 3092 infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP); 3093 resp->resok.infop = infop; 3094 3095 dp = (struct dirent64 *)data; 3096 for (i = 0; i < nents; i++) { 3097 3098 if (dp->d_ino == 0) { 3099 infop[i].attr.attributes = FALSE; 3100 infop[i].fh.handle_follows = FALSE; 3101 dp = nextdp(dp); 3102 continue; 3103 } 3104 3105 infop[i].namelen = namlen[i]; 3106 3107 error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr); 3108 if (error) { 3109 infop[i].attr.attributes = FALSE; 3110 infop[i].fh.handle_follows = FALSE; 3111 dp = nextdp(dp); 3112 continue; 3113 } 3114 3115 #ifdef DEBUG 3116 if (rfs3_do_post_op_attr) { 3117 nva.va_mask = AT_ALL; 3118 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? 3119 NULL : &nva; 3120 } else 3121 nvap = NULL; 3122 #else 3123 nva.va_mask = AT_ALL; 3124 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva; 3125 #endif 3126 vattr_to_post_op_attr(nvap, &infop[i].attr); 3127 3128 #ifdef DEBUG 3129 if (!rfs3_do_post_op_fh3) 3130 infop[i].fh.handle_follows = FALSE; 3131 else { 3132 #endif 3133 error = makefh3(&infop[i].fh.handle, nvp, exi); 3134 if (!error) 3135 infop[i].fh.handle_follows = TRUE; 3136 else 3137 infop[i].fh.handle_follows = FALSE; 3138 #ifdef DEBUG 3139 } 3140 #endif 3141 3142 VN_RELE(nvp); 3143 dp = nextdp(dp); 3144 } 3145 3146 #if 0 /* notyet */ 3147 /* 3148 * Don't do this. It causes local disk writes when just 3149 * reading the file and the overhead is deemed larger 3150 * than the benefit. 3151 */ 3152 /* 3153 * Force modified metadata out to stable storage. 3154 */ 3155 (void) VOP_FSYNC(vp, FNODSYNC, cr); 3156 #endif 3157 3158 VN_RELE(vp); 3159 3160 kmem_free(namlen, args->dircount); 3161 3162 resp->status = NFS3_OK; 3163 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes); 3164 resp->resok.cookieverf = 0; 3165 resp->resok.reply.entries = (entryplus3 *)data; 3166 resp->resok.reply.eof = iseof; 3167 resp->resok.size = nents; 3168 resp->resok.count = args->dircount; 3169 resp->resok.maxcount = args->maxcount; 3170 return; 3171 3172 out: 3173 if (curthread->t_flag & T_WOULDBLOCK) { 3174 curthread->t_flag &= ~T_WOULDBLOCK; 3175 resp->status = NFS3ERR_JUKEBOX; 3176 } else 3177 resp->status = puterrno3(error); 3178 out1: 3179 if (vp != NULL) { 3180 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 3181 VN_RELE(vp); 3182 } 3183 3184 if (namlen != NULL) 3185 kmem_free(namlen, args->dircount); 3186 3187 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes); 3188 } 3189 3190 fhandle_t * 3191 rfs3_readdirplus_getfh(READDIRPLUS3args *args) 3192 { 3193 3194 return ((fhandle_t *)&args->dir.fh3_u.nfs_fh3_i.fh3_i); 3195 } 3196 3197 void 3198 rfs3_readdirplus_free(READDIRPLUS3res *resp) 3199 { 3200 3201 if (resp->status == NFS3_OK) { 3202 kmem_free(resp->resok.reply.entries, resp->resok.count); 3203 kmem_free(resp->resok.infop, 3204 resp->resok.size * sizeof (struct entryplus3_info)); 3205 } 3206 } 3207 3208 /* ARGSUSED */ 3209 void 3210 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi, 3211 struct svc_req *req, cred_t *cr) 3212 { 3213 int error; 3214 vnode_t *vp; 3215 struct vattr *vap; 3216 struct vattr va; 3217 struct statvfs64 sb; 3218 3219 vap = NULL; 3220 3221 vp = nfs3_fhtovp(&args->fsroot, exi); 3222 if (vp == NULL) { 3223 error = ESTALE; 3224 goto out; 3225 } 3226 3227 error = VFS_STATVFS(vp->v_vfsp, &sb); 3228 3229 #ifdef DEBUG 3230 if (rfs3_do_post_op_attr) { 3231 va.va_mask = AT_ALL; 3232 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3233 } else 3234 vap = NULL; 3235 #else 3236 va.va_mask = AT_ALL; 3237 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3238 #endif 3239 3240 VN_RELE(vp); 3241 3242 if (error) 3243 goto out; 3244 3245 resp->status = NFS3_OK; 3246 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 3247 if (sb.f_blocks != (fsblkcnt64_t)-1) 3248 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks; 3249 else 3250 resp->resok.tbytes = (size3)sb.f_blocks; 3251 if (sb.f_bfree != (fsblkcnt64_t)-1) 3252 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree; 3253 else 3254 resp->resok.fbytes = (size3)sb.f_bfree; 3255 if (sb.f_bavail != (fsblkcnt64_t)-1) 3256 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail; 3257 else 3258 resp->resok.abytes = (size3)sb.f_bavail; 3259 resp->resok.tfiles = (size3)sb.f_files; 3260 resp->resok.ffiles = (size3)sb.f_ffree; 3261 resp->resok.afiles = (size3)sb.f_favail; 3262 resp->resok.invarsec = 0; 3263 return; 3264 3265 out: 3266 if (curthread->t_flag & T_WOULDBLOCK) { 3267 curthread->t_flag &= ~T_WOULDBLOCK; 3268 resp->status = NFS3ERR_JUKEBOX; 3269 } else 3270 resp->status = puterrno3(error); 3271 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); 3272 } 3273 3274 fhandle_t * 3275 rfs3_fsstat_getfh(FSSTAT3args *args) 3276 { 3277 3278 return ((fhandle_t *)&args->fsroot.fh3_u.nfs_fh3_i.fh3_i); 3279 } 3280 3281 /* ARGSUSED */ 3282 void 3283 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi, 3284 struct svc_req *req, cred_t *cr) 3285 { 3286 vnode_t *vp; 3287 struct vattr *vap; 3288 struct vattr va; 3289 uint32_t xfer_size; 3290 ulong_t l = 0; 3291 int error; 3292 3293 vp = nfs3_fhtovp(&args->fsroot, exi); 3294 if (vp == NULL) { 3295 if (curthread->t_flag & T_WOULDBLOCK) { 3296 curthread->t_flag &= ~T_WOULDBLOCK; 3297 resp->status = NFS3ERR_JUKEBOX; 3298 } else 3299 resp->status = NFS3ERR_STALE; 3300 vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes); 3301 return; 3302 } 3303 3304 #ifdef DEBUG 3305 if (rfs3_do_post_op_attr) { 3306 va.va_mask = AT_ALL; 3307 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3308 } else 3309 vap = NULL; 3310 #else 3311 va.va_mask = AT_ALL; 3312 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3313 #endif 3314 3315 resp->status = NFS3_OK; 3316 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 3317 xfer_size = rfs3_tsize(req); 3318 resp->resok.rtmax = xfer_size; 3319 resp->resok.rtpref = xfer_size; 3320 resp->resok.rtmult = DEV_BSIZE; 3321 resp->resok.wtmax = xfer_size; 3322 resp->resok.wtpref = xfer_size; 3323 resp->resok.wtmult = DEV_BSIZE; 3324 resp->resok.dtpref = MAXBSIZE; 3325 3326 /* 3327 * Large file spec: want maxfilesize based on limit of 3328 * underlying filesystem. We can guess 2^31-1 if need be. 3329 */ 3330 error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr); 3331 3332 VN_RELE(vp); 3333 3334 if (!error && l != 0 && l <= 64) 3335 resp->resok.maxfilesize = (1LL << (l-1)) - 1; 3336 else 3337 resp->resok.maxfilesize = MAXOFF32_T; 3338 3339 resp->resok.time_delta.seconds = 0; 3340 resp->resok.time_delta.nseconds = 1000; 3341 resp->resok.properties = FSF3_LINK | FSF3_SYMLINK | 3342 FSF3_HOMOGENEOUS | FSF3_CANSETTIME; 3343 } 3344 3345 fhandle_t * 3346 rfs3_fsinfo_getfh(FSINFO3args *args) 3347 { 3348 3349 return ((fhandle_t *)&args->fsroot.fh3_u.nfs_fh3_i.fh3_i); 3350 } 3351 3352 /* ARGSUSED */ 3353 void 3354 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi, 3355 struct svc_req *req, cred_t *cr) 3356 { 3357 int error; 3358 vnode_t *vp; 3359 struct vattr *vap; 3360 struct vattr va; 3361 ulong_t val; 3362 3363 vap = NULL; 3364 3365 vp = nfs3_fhtovp(&args->object, exi); 3366 if (vp == NULL) { 3367 error = ESTALE; 3368 goto out; 3369 } 3370 3371 #ifdef DEBUG 3372 if (rfs3_do_post_op_attr) { 3373 va.va_mask = AT_ALL; 3374 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3375 } else 3376 vap = NULL; 3377 #else 3378 va.va_mask = AT_ALL; 3379 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3380 #endif 3381 3382 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr); 3383 if (error) 3384 goto out; 3385 resp->resok.info.link_max = (uint32)val; 3386 3387 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr); 3388 if (error) 3389 goto out; 3390 resp->resok.info.name_max = (uint32)val; 3391 3392 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr); 3393 if (error) 3394 goto out; 3395 if (val == 1) 3396 resp->resok.info.no_trunc = TRUE; 3397 else 3398 resp->resok.info.no_trunc = FALSE; 3399 3400 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr); 3401 if (error) 3402 goto out; 3403 if (val == 1) 3404 resp->resok.info.chown_restricted = TRUE; 3405 else 3406 resp->resok.info.chown_restricted = FALSE; 3407 3408 VN_RELE(vp); 3409 3410 resp->status = NFS3_OK; 3411 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 3412 resp->resok.info.case_insensitive = FALSE; 3413 resp->resok.info.case_preserving = TRUE; 3414 return; 3415 3416 out: 3417 if (curthread->t_flag & T_WOULDBLOCK) { 3418 curthread->t_flag &= ~T_WOULDBLOCK; 3419 resp->status = NFS3ERR_JUKEBOX; 3420 } else 3421 resp->status = puterrno3(error); 3422 if (vp != NULL) 3423 VN_RELE(vp); 3424 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); 3425 } 3426 3427 fhandle_t * 3428 rfs3_pathconf_getfh(PATHCONF3args *args) 3429 { 3430 3431 return ((fhandle_t *)&args->object.fh3_u.nfs_fh3_i.fh3_i); 3432 } 3433 3434 void 3435 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi, 3436 struct svc_req *req, cred_t *cr) 3437 { 3438 int error; 3439 vnode_t *vp; 3440 struct vattr *bvap; 3441 struct vattr bva; 3442 struct vattr *avap; 3443 struct vattr ava; 3444 3445 bvap = NULL; 3446 avap = NULL; 3447 3448 vp = nfs3_fhtovp(&args->file, exi); 3449 if (vp == NULL) { 3450 error = ESTALE; 3451 goto out; 3452 } 3453 3454 bva.va_mask = AT_ALL; 3455 error = VOP_GETATTR(vp, &bva, 0, cr); 3456 3457 /* 3458 * If we can't get the attributes, then we can't do the 3459 * right access checking. So, we'll fail the request. 3460 */ 3461 if (error) 3462 goto out; 3463 3464 #ifdef DEBUG 3465 if (rfs3_do_pre_op_attr) 3466 bvap = &bva; 3467 else 3468 bvap = NULL; 3469 #else 3470 bvap = &bva; 3471 #endif 3472 3473 if (rdonly(exi, req)) { 3474 resp->status = NFS3ERR_ROFS; 3475 goto out1; 3476 } 3477 3478 if (vp->v_type != VREG) { 3479 resp->status = NFS3ERR_INVAL; 3480 goto out1; 3481 } 3482 3483 if (crgetuid(cr) != bva.va_uid && 3484 (error = VOP_ACCESS(vp, VWRITE, 0, cr))) 3485 goto out; 3486 3487 error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr); 3488 if (!error) 3489 error = VOP_FSYNC(vp, FNODSYNC, cr); 3490 3491 #ifdef DEBUG 3492 if (rfs3_do_post_op_attr) { 3493 ava.va_mask = AT_ALL; 3494 avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava; 3495 } else 3496 avap = NULL; 3497 #else 3498 ava.va_mask = AT_ALL; 3499 avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava; 3500 #endif 3501 3502 if (error) 3503 goto out; 3504 3505 VN_RELE(vp); 3506 3507 resp->status = NFS3_OK; 3508 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); 3509 resp->resok.verf = write3verf; 3510 return; 3511 3512 out: 3513 if (curthread->t_flag & T_WOULDBLOCK) { 3514 curthread->t_flag &= ~T_WOULDBLOCK; 3515 resp->status = NFS3ERR_JUKEBOX; 3516 } else 3517 resp->status = puterrno3(error); 3518 out1: 3519 if (vp != NULL) 3520 VN_RELE(vp); 3521 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc); 3522 } 3523 3524 fhandle_t * 3525 rfs3_commit_getfh(COMMIT3args *args) 3526 { 3527 3528 return ((fhandle_t *)&args->file.fh3_u.nfs_fh3_i.fh3_i); 3529 } 3530 3531 static int 3532 sattr3_to_vattr(sattr3 *sap, struct vattr *vap) 3533 { 3534 3535 vap->va_mask = 0; 3536 3537 if (sap->mode.set_it) { 3538 vap->va_mode = (mode_t)sap->mode.mode; 3539 vap->va_mask |= AT_MODE; 3540 } 3541 if (sap->uid.set_it) { 3542 vap->va_uid = (uid_t)sap->uid.uid; 3543 vap->va_mask |= AT_UID; 3544 } 3545 if (sap->gid.set_it) { 3546 vap->va_gid = (gid_t)sap->gid.gid; 3547 vap->va_mask |= AT_GID; 3548 } 3549 if (sap->size.set_it) { 3550 if (sap->size.size > (size3)((u_longlong_t)-1)) 3551 return (EINVAL); 3552 vap->va_size = sap->size.size; 3553 vap->va_mask |= AT_SIZE; 3554 } 3555 if (sap->atime.set_it == SET_TO_CLIENT_TIME) { 3556 #ifndef _LP64 3557 /* check time validity */ 3558 if (!NFS3_TIME_OK(sap->atime.atime.seconds)) 3559 return (EOVERFLOW); 3560 #endif 3561 /* 3562 * nfs protocol defines times as unsigned so don't extend sign, 3563 * unless sysadmin set nfs_allow_preepoch_time. 3564 */ 3565 NFS_TIME_T_CONVERT(vap->va_atime.tv_sec, 3566 sap->atime.atime.seconds); 3567 vap->va_atime.tv_nsec = (uint32_t)sap->atime.atime.nseconds; 3568 vap->va_mask |= AT_ATIME; 3569 } else if (sap->atime.set_it == SET_TO_SERVER_TIME) { 3570 gethrestime(&vap->va_atime); 3571 vap->va_mask |= AT_ATIME; 3572 } 3573 if (sap->mtime.set_it == SET_TO_CLIENT_TIME) { 3574 #ifndef _LP64 3575 /* check time validity */ 3576 if (!NFS3_TIME_OK(sap->mtime.mtime.seconds)) 3577 return (EOVERFLOW); 3578 #endif 3579 /* 3580 * nfs protocol defines times as unsigned so don't extend sign, 3581 * unless sysadmin set nfs_allow_preepoch_time. 3582 */ 3583 NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec, 3584 sap->mtime.mtime.seconds); 3585 vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds; 3586 vap->va_mask |= AT_MTIME; 3587 } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) { 3588 gethrestime(&vap->va_mtime); 3589 vap->va_mask |= AT_MTIME; 3590 } 3591 3592 return (0); 3593 } 3594 3595 static ftype3 vt_to_nf3[] = { 3596 0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0 3597 }; 3598 3599 static int 3600 vattr_to_fattr3(struct vattr *vap, fattr3 *fap) 3601 { 3602 3603 ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD); 3604 /* Return error if time or size overflow */ 3605 if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) { 3606 return (EOVERFLOW); 3607 } 3608 fap->type = vt_to_nf3[vap->va_type]; 3609 fap->mode = (mode3)(vap->va_mode & MODEMASK); 3610 fap->nlink = (uint32)vap->va_nlink; 3611 if (vap->va_uid == UID_NOBODY) 3612 fap->uid = (uid3)NFS_UID_NOBODY; 3613 else 3614 fap->uid = (uid3)vap->va_uid; 3615 if (vap->va_gid == GID_NOBODY) 3616 fap->gid = (gid3)NFS_GID_NOBODY; 3617 else 3618 fap->gid = (gid3)vap->va_gid; 3619 fap->size = (size3)vap->va_size; 3620 fap->used = (size3)DEV_BSIZE * (size3)vap->va_nblocks; 3621 fap->rdev.specdata1 = (uint32)getmajor(vap->va_rdev); 3622 fap->rdev.specdata2 = (uint32)getminor(vap->va_rdev); 3623 fap->fsid = (uint64)vap->va_fsid; 3624 fap->fileid = (fileid3)vap->va_nodeid; 3625 fap->atime.seconds = vap->va_atime.tv_sec; 3626 fap->atime.nseconds = vap->va_atime.tv_nsec; 3627 fap->mtime.seconds = vap->va_mtime.tv_sec; 3628 fap->mtime.nseconds = vap->va_mtime.tv_nsec; 3629 fap->ctime.seconds = vap->va_ctime.tv_sec; 3630 fap->ctime.nseconds = vap->va_ctime.tv_nsec; 3631 return (0); 3632 } 3633 3634 static int 3635 vattr_to_wcc_attr(struct vattr *vap, wcc_attr *wccap) 3636 { 3637 3638 /* Return error if time or size overflow */ 3639 if (! (NFS_TIME_T_OK(vap->va_mtime.tv_sec) && 3640 NFS_TIME_T_OK(vap->va_ctime.tv_sec) && 3641 NFS3_SIZE_OK(vap->va_size))) { 3642 return (EOVERFLOW); 3643 } 3644 wccap->size = (size3)vap->va_size; 3645 wccap->mtime.seconds = vap->va_mtime.tv_sec; 3646 wccap->mtime.nseconds = vap->va_mtime.tv_nsec; 3647 wccap->ctime.seconds = vap->va_ctime.tv_sec; 3648 wccap->ctime.nseconds = vap->va_ctime.tv_nsec; 3649 return (0); 3650 } 3651 3652 static void 3653 vattr_to_pre_op_attr(struct vattr *vap, pre_op_attr *poap) 3654 { 3655 3656 /* don't return attrs if time overflow */ 3657 if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) { 3658 poap->attributes = TRUE; 3659 } else 3660 poap->attributes = FALSE; 3661 } 3662 3663 void 3664 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap) 3665 { 3666 3667 /* don't return attrs if time overflow */ 3668 if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) { 3669 poap->attributes = TRUE; 3670 } else 3671 poap->attributes = FALSE; 3672 } 3673 3674 static void 3675 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp) 3676 { 3677 3678 vattr_to_pre_op_attr(bvap, &wccp->before); 3679 vattr_to_post_op_attr(avap, &wccp->after); 3680 } 3681 3682 void 3683 rfs3_srvrinit(void) 3684 { 3685 struct rfs3_verf_overlay { 3686 uint_t id; /* a "unique" identifier */ 3687 int ts; /* a unique timestamp */ 3688 } *verfp; 3689 timestruc_t now; 3690 3691 /* 3692 * The following algorithm attempts to find a unique verifier 3693 * to be used as the write verifier returned from the server 3694 * to the client. It is important that this verifier change 3695 * whenever the server reboots. Of secondary importance, it 3696 * is important for the verifier to be unique between two 3697 * different servers. 3698 * 3699 * Thus, an attempt is made to use the system hostid and the 3700 * current time in seconds when the nfssrv kernel module is 3701 * loaded. It is assumed that an NFS server will not be able 3702 * to boot and then to reboot in less than a second. If the 3703 * hostid has not been set, then the current high resolution 3704 * time is used. This will ensure different verifiers each 3705 * time the server reboots and minimize the chances that two 3706 * different servers will have the same verifier. 3707 */ 3708 3709 #ifndef lint 3710 /* 3711 * We ASSERT that this constant logic expression is 3712 * always true because in the past, it wasn't. 3713 */ 3714 ASSERT(sizeof (*verfp) <= sizeof (write3verf)); 3715 #endif 3716 3717 gethrestime(&now); 3718 verfp = (struct rfs3_verf_overlay *)&write3verf; 3719 verfp->ts = (int)now.tv_sec; 3720 verfp->id = (uint_t)nfs_atoi(hw_serial); 3721 3722 if (verfp->id == 0) 3723 verfp->id = (uint_t)now.tv_nsec; 3724 3725 } 3726 3727 void 3728 rfs3_srvrfini(void) 3729 { 3730 /* Nothing to do */ 3731 } 3732