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 if (error == 0) { 2404 char *tmp; 2405 2406 /* fix the path name for the renamed file */ 2407 mutex_enter(&srcvp->v_lock); 2408 tmp = srcvp->v_path; 2409 srcvp->v_path = NULL; 2410 mutex_exit(&srcvp->v_lock); 2411 vn_setpath(rootdir, tvp, srcvp, args->to.name, 2412 strlen(args->to.name)); 2413 if (tmp != NULL) 2414 kmem_free(tmp, strlen(tmp) + 1); 2415 } 2416 VN_RELE(srcvp); 2417 srcvp = NULL; 2418 2419 #ifdef DEBUG 2420 if (rfs3_do_post_op_attr) { 2421 fava.va_mask = AT_ALL; 2422 favap = VOP_GETATTR(fvp, &fava, 0, cr) ? NULL : &fava; 2423 tava.va_mask = AT_ALL; 2424 tavap = VOP_GETATTR(tvp, &tava, 0, cr) ? NULL : &tava; 2425 } else { 2426 favap = NULL; 2427 tavap = NULL; 2428 } 2429 #else 2430 fava.va_mask = AT_ALL; 2431 favap = VOP_GETATTR(fvp, &fava, 0, cr) ? NULL : &fava; 2432 tava.va_mask = AT_ALL; 2433 tavap = VOP_GETATTR(tvp, &tava, 0, cr) ? NULL : &tava; 2434 #endif 2435 2436 /* 2437 * Force modified data and metadata out to stable storage. 2438 */ 2439 (void) VOP_FSYNC(fvp, 0, cr); 2440 (void) VOP_FSYNC(tvp, 0, cr); 2441 2442 if (error) 2443 goto out; 2444 2445 VN_RELE(tvp); 2446 VN_RELE(fvp); 2447 2448 resp->status = NFS3_OK; 2449 vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc); 2450 vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc); 2451 return; 2452 2453 out: 2454 if (curthread->t_flag & T_WOULDBLOCK) { 2455 curthread->t_flag &= ~T_WOULDBLOCK; 2456 resp->status = NFS3ERR_JUKEBOX; 2457 } else 2458 resp->status = puterrno3(error); 2459 out1: 2460 if (fvp != NULL) 2461 VN_RELE(fvp); 2462 if (tvp != NULL) 2463 VN_RELE(tvp); 2464 vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc); 2465 vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc); 2466 } 2467 2468 fhandle_t * 2469 rfs3_rename_getfh(RENAME3args *args) 2470 { 2471 2472 return ((fhandle_t *)&args->from.dirp->fh3_u.nfs_fh3_i.fh3_i); 2473 } 2474 2475 void 2476 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi, 2477 struct svc_req *req, cred_t *cr) 2478 { 2479 int error; 2480 vnode_t *vp; 2481 vnode_t *dvp; 2482 struct vattr *vap; 2483 struct vattr va; 2484 struct vattr *bvap; 2485 struct vattr bva; 2486 struct vattr *avap; 2487 struct vattr ava; 2488 nfs_fh3 *fh3; 2489 struct exportinfo *to_exi; 2490 2491 vap = NULL; 2492 bvap = NULL; 2493 avap = NULL; 2494 dvp = NULL; 2495 2496 vp = nfs3_fhtovp(&args->file, exi); 2497 if (vp == NULL) { 2498 error = ESTALE; 2499 goto out; 2500 } 2501 2502 #ifdef DEBUG 2503 if (rfs3_do_pre_op_attr) { 2504 va.va_mask = AT_ALL; 2505 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2506 } else 2507 vap = NULL; 2508 #else 2509 va.va_mask = AT_ALL; 2510 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2511 #endif 2512 2513 fh3 = args->link.dirp; 2514 to_exi = checkexport(&fh3->fh3_fsid, (fid_t *)&fh3->fh3_xlen); 2515 if (to_exi == NULL) { 2516 resp->status = NFS3ERR_ACCES; 2517 goto out1; 2518 } 2519 exi_rele(to_exi); 2520 2521 if (to_exi != exi) { 2522 resp->status = NFS3ERR_XDEV; 2523 goto out1; 2524 } 2525 2526 dvp = nfs3_fhtovp(args->link.dirp, exi); 2527 if (dvp == NULL) { 2528 error = ESTALE; 2529 goto out; 2530 } 2531 2532 #ifdef DEBUG 2533 if (rfs3_do_pre_op_attr) { 2534 bva.va_mask = AT_ALL; 2535 bvap = VOP_GETATTR(dvp, &bva, 0, cr) ? NULL : &bva; 2536 } else 2537 bvap = NULL; 2538 #else 2539 bva.va_mask = AT_ALL; 2540 bvap = VOP_GETATTR(dvp, &bva, 0, cr) ? NULL : &bva; 2541 #endif 2542 2543 if (dvp->v_type != VDIR) { 2544 resp->status = NFS3ERR_NOTDIR; 2545 goto out1; 2546 } 2547 2548 if (args->link.name == nfs3nametoolong) { 2549 resp->status = NFS3ERR_NAMETOOLONG; 2550 goto out1; 2551 } 2552 2553 if (args->link.name == NULL || *(args->link.name) == '\0') { 2554 resp->status = NFS3ERR_ACCES; 2555 goto out1; 2556 } 2557 2558 if (rdonly(exi, req)) { 2559 resp->status = NFS3ERR_ROFS; 2560 goto out1; 2561 } 2562 2563 error = VOP_LINK(dvp, vp, args->link.name, cr); 2564 2565 #ifdef DEBUG 2566 if (rfs3_do_post_op_attr) { 2567 va.va_mask = AT_ALL; 2568 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2569 ava.va_mask = AT_ALL; 2570 avap = VOP_GETATTR(dvp, &ava, 0, cr) ? NULL : &ava; 2571 } else { 2572 vap = NULL; 2573 avap = NULL; 2574 } 2575 #else 2576 va.va_mask = AT_ALL; 2577 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2578 ava.va_mask = AT_ALL; 2579 avap = VOP_GETATTR(dvp, &ava, 0, cr) ? NULL : &ava; 2580 #endif 2581 2582 /* 2583 * Force modified data and metadata out to stable storage. 2584 */ 2585 (void) VOP_FSYNC(vp, FNODSYNC, cr); 2586 (void) VOP_FSYNC(dvp, 0, cr); 2587 2588 if (error) 2589 goto out; 2590 2591 VN_RELE(dvp); 2592 VN_RELE(vp); 2593 2594 resp->status = NFS3_OK; 2595 vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 2596 vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc); 2597 return; 2598 2599 out: 2600 if (curthread->t_flag & T_WOULDBLOCK) { 2601 curthread->t_flag &= ~T_WOULDBLOCK; 2602 resp->status = NFS3ERR_JUKEBOX; 2603 } else 2604 resp->status = puterrno3(error); 2605 out1: 2606 if (vp != NULL) 2607 VN_RELE(vp); 2608 if (dvp != NULL) 2609 VN_RELE(dvp); 2610 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes); 2611 vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc); 2612 } 2613 2614 fhandle_t * 2615 rfs3_link_getfh(LINK3args *args) 2616 { 2617 2618 return ((fhandle_t *)&args->file.fh3_u.nfs_fh3_i.fh3_i); 2619 } 2620 2621 /* 2622 * This macro defines the size of a response which contains attribute 2623 * information and one directory entry (whose length is specified by 2624 * the macro parameter). If the incoming request is larger than this, 2625 * then we are guaranteed to be able to return at one directory entry 2626 * if one exists. Therefore, we do not need to check for 2627 * NFS3ERR_TOOSMALL if the requested size is larger then this. If it 2628 * is not, then we need to check to make sure that this error does not 2629 * need to be returned. 2630 * 2631 * NFS3_READDIR_MIN_COUNT is comprised of following : 2632 * 2633 * status - 1 * BYTES_PER_XDR_UNIT 2634 * attr. flag - 1 * BYTES_PER_XDR_UNIT 2635 * cookie verifier - 2 * BYTES_PER_XDR_UNIT 2636 * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT 2637 * boolean - 1 * BYTES_PER_XDR_UNIT 2638 * file id - 2 * BYTES_PER_XDR_UNIT 2639 * direcotory name length - 1 * BYTES_PER_XDR_UNIT 2640 * cookie - 2 * BYTES_PER_XDR_UNIT 2641 * end of list - 1 * BYTES_PER_XDR_UNIT 2642 * end of file - 1 * BYTES_PER_XDR_UNIT 2643 * Name length of directory to the nearest byte 2644 */ 2645 2646 #define NFS3_READDIR_MIN_COUNT(length) \ 2647 ((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \ 2648 BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT)) 2649 2650 /* ARGSUSED */ 2651 void 2652 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi, 2653 struct svc_req *req, cred_t *cr) 2654 { 2655 int error; 2656 vnode_t *vp; 2657 struct vattr *vap; 2658 struct vattr va; 2659 struct iovec iov; 2660 struct uio uio; 2661 char *data; 2662 int iseof; 2663 int bufsize; 2664 int namlen; 2665 uint_t count; 2666 2667 vap = NULL; 2668 2669 vp = nfs3_fhtovp(&args->dir, exi); 2670 if (vp == NULL) { 2671 error = ESTALE; 2672 goto out; 2673 } 2674 2675 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 2676 2677 #ifdef DEBUG 2678 if (rfs3_do_pre_op_attr) { 2679 va.va_mask = AT_ALL; 2680 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2681 } else 2682 vap = NULL; 2683 #else 2684 va.va_mask = AT_ALL; 2685 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2686 #endif 2687 2688 if (vp->v_type != VDIR) { 2689 resp->status = NFS3ERR_NOTDIR; 2690 goto out1; 2691 } 2692 2693 error = VOP_ACCESS(vp, VREAD, 0, cr); 2694 if (error) 2695 goto out; 2696 2697 /* 2698 * Now don't allow arbitrary count to alloc; 2699 * allow the maximum not to exceed rfs3_tsize() 2700 */ 2701 if (args->count > rfs3_tsize(req)) 2702 args->count = rfs3_tsize(req); 2703 2704 /* 2705 * Make sure that there is room to read at least one entry 2706 * if any are available. 2707 */ 2708 if (args->count < DIRENT64_RECLEN(MAXNAMELEN)) 2709 count = DIRENT64_RECLEN(MAXNAMELEN); 2710 else 2711 count = args->count; 2712 2713 data = kmem_alloc(count, KM_SLEEP); 2714 2715 iov.iov_base = data; 2716 iov.iov_len = count; 2717 uio.uio_iov = &iov; 2718 uio.uio_iovcnt = 1; 2719 uio.uio_segflg = UIO_SYSSPACE; 2720 uio.uio_extflg = UIO_COPY_CACHED; 2721 uio.uio_loffset = (offset_t)args->cookie; 2722 uio.uio_resid = count; 2723 2724 error = VOP_READDIR(vp, &uio, cr, &iseof); 2725 2726 #ifdef DEBUG 2727 if (rfs3_do_post_op_attr) { 2728 va.va_mask = AT_ALL; 2729 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2730 } else 2731 vap = NULL; 2732 #else 2733 va.va_mask = AT_ALL; 2734 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2735 #endif 2736 2737 if (error) { 2738 kmem_free(data, count); 2739 goto out; 2740 } 2741 2742 /* 2743 * If the count was not large enough to be able to guarantee 2744 * to be able to return at least one entry, then need to 2745 * check to see if NFS3ERR_TOOSMALL should be returned. 2746 */ 2747 if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) { 2748 /* 2749 * bufsize is used to keep track of the size of the response. 2750 * It is primed with: 2751 * 1 for the status + 2752 * 1 for the dir_attributes.attributes boolean + 2753 * 2 for the cookie verifier 2754 * all times BYTES_PER_XDR_UNIT to convert from XDR units 2755 * to bytes. If there are directory attributes to be 2756 * returned, then: 2757 * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3 2758 * time BYTES_PER_XDR_UNIT is added to account for them. 2759 */ 2760 bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT; 2761 if (vap != NULL) 2762 bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT; 2763 /* 2764 * An entry is composed of: 2765 * 1 for the true/false list indicator + 2766 * 2 for the fileid + 2767 * 1 for the length of the name + 2768 * 2 for the cookie + 2769 * all times BYTES_PER_XDR_UNIT to convert from 2770 * XDR units to bytes, plus the length of the name 2771 * rounded up to the nearest BYTES_PER_XDR_UNIT. 2772 */ 2773 if (count != uio.uio_resid) { 2774 namlen = strlen(((struct dirent64 *)data)->d_name); 2775 bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT + 2776 roundup(namlen, BYTES_PER_XDR_UNIT); 2777 } 2778 /* 2779 * We need to check to see if the number of bytes left 2780 * to go into the buffer will actually fit into the 2781 * buffer. This is calculated as the size of this 2782 * entry plus: 2783 * 1 for the true/false list indicator + 2784 * 1 for the eof indicator 2785 * times BYTES_PER_XDR_UNIT to convert from from 2786 * XDR units to bytes. 2787 */ 2788 bufsize += (1 + 1) * BYTES_PER_XDR_UNIT; 2789 if (bufsize > args->count) { 2790 kmem_free(data, count); 2791 resp->status = NFS3ERR_TOOSMALL; 2792 goto out1; 2793 } 2794 } 2795 2796 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 2797 2798 #if 0 /* notyet */ 2799 /* 2800 * Don't do this. It causes local disk writes when just 2801 * reading the file and the overhead is deemed larger 2802 * than the benefit. 2803 */ 2804 /* 2805 * Force modified metadata out to stable storage. 2806 */ 2807 (void) VOP_FSYNC(vp, FNODSYNC, cr); 2808 #endif 2809 2810 VN_RELE(vp); 2811 2812 resp->status = NFS3_OK; 2813 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes); 2814 resp->resok.cookieverf = 0; 2815 resp->resok.reply.entries = (entry3 *)data; 2816 resp->resok.reply.eof = iseof; 2817 resp->resok.size = count - uio.uio_resid; 2818 resp->resok.count = args->count; 2819 resp->resok.freecount = count; 2820 return; 2821 2822 out: 2823 if (curthread->t_flag & T_WOULDBLOCK) { 2824 curthread->t_flag &= ~T_WOULDBLOCK; 2825 resp->status = NFS3ERR_JUKEBOX; 2826 } else 2827 resp->status = puterrno3(error); 2828 out1: 2829 if (vp != NULL) { 2830 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 2831 VN_RELE(vp); 2832 } 2833 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes); 2834 } 2835 2836 fhandle_t * 2837 rfs3_readdir_getfh(READDIR3args *args) 2838 { 2839 2840 return ((fhandle_t *)&args->dir.fh3_u.nfs_fh3_i.fh3_i); 2841 } 2842 2843 void 2844 rfs3_readdir_free(READDIR3res *resp) 2845 { 2846 2847 if (resp->status == NFS3_OK) 2848 kmem_free(resp->resok.reply.entries, resp->resok.freecount); 2849 } 2850 2851 #ifdef nextdp 2852 #undef nextdp 2853 #endif 2854 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) 2855 2856 /* 2857 * This macro computes the size of a response which contains 2858 * one directory entry including the attributes as well as file handle. 2859 * If the incoming request is larger than this, then we are guaranteed to be 2860 * able to return at least one more directory entry if one exists. 2861 * 2862 * NFS3_READDIRPLUS_ENTRY is made up of the following: 2863 * 2864 * boolean - 1 * BYTES_PER_XDR_UNIT 2865 * file id - 2 * BYTES_PER_XDR_UNIT 2866 * directory name length - 1 * BYTES_PER_XDR_UNIT 2867 * cookie - 2 * BYTES_PER_XDR_UNIT 2868 * attribute flag - 1 * BYTES_PER_XDR_UNIT 2869 * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT 2870 * status byte for file handle - 1 * BYTES_PER_XDR_UNIT 2871 * length of a file handle - 1 * BYTES_PER_XDR_UNIT 2872 * Maxmum length of a file handle (NFS3_CURFHSIZE) 2873 * name length of the entry to the nearest bytes 2874 */ 2875 #define NFS3_READDIRPLUS_ENTRY(namelen) \ 2876 ((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \ 2877 BYTES_PER_XDR_UNIT + \ 2878 NFS3_CURFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT)) 2879 2880 static int rfs3_readdir_unit = MAXBSIZE; 2881 2882 /* ARGSUSED */ 2883 void 2884 rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp, 2885 struct exportinfo *exi, struct svc_req *req, cred_t *cr) 2886 { 2887 int error; 2888 vnode_t *vp; 2889 struct vattr *vap; 2890 struct vattr va; 2891 struct iovec iov; 2892 struct uio uio; 2893 char *data; 2894 int iseof; 2895 struct dirent64 *dp; 2896 vnode_t *nvp; 2897 struct vattr *nvap; 2898 struct vattr nva; 2899 entryplus3_info *infop = NULL; 2900 int size = 0; 2901 int nents = 0; 2902 int bufsize = 0; 2903 int entrysize = 0; 2904 int tofit = 0; 2905 int rd_unit = rfs3_readdir_unit; 2906 int prev_len; 2907 int space_left; 2908 int i; 2909 uint_t *namlen = NULL; 2910 2911 vap = NULL; 2912 2913 vp = nfs3_fhtovp(&args->dir, exi); 2914 if (vp == NULL) { 2915 error = ESTALE; 2916 goto out; 2917 } 2918 2919 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 2920 2921 #ifdef DEBUG 2922 if (rfs3_do_pre_op_attr) { 2923 va.va_mask = AT_ALL; 2924 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2925 } else 2926 vap = NULL; 2927 #else 2928 va.va_mask = AT_ALL; 2929 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 2930 #endif 2931 2932 if (vp->v_type != VDIR) { 2933 error = ENOTDIR; 2934 goto out; 2935 } 2936 2937 error = VOP_ACCESS(vp, VREAD, 0, cr); 2938 if (error) 2939 goto out; 2940 2941 /* 2942 * Don't allow arbitrary counts for allocation 2943 */ 2944 if (args->maxcount > rfs3_tsize(req)) 2945 args->maxcount = rfs3_tsize(req); 2946 2947 /* 2948 * Make sure that there is room to read at least one entry 2949 * if any are available 2950 */ 2951 args->dircount = MIN(args->dircount, args->maxcount); 2952 2953 if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN)) 2954 args->dircount = DIRENT64_RECLEN(MAXNAMELEN); 2955 2956 /* 2957 * This allocation relies on a minimum directory entry 2958 * being roughly 24 bytes. Therefore, the namlen array 2959 * will have enough space based on the maximum number of 2960 * entries to read. 2961 */ 2962 namlen = kmem_alloc(args->dircount, KM_SLEEP); 2963 2964 space_left = args->dircount; 2965 data = kmem_alloc(args->dircount, KM_SLEEP); 2966 dp = (struct dirent64 *)data; 2967 uio.uio_iov = &iov; 2968 uio.uio_iovcnt = 1; 2969 uio.uio_segflg = UIO_SYSSPACE; 2970 uio.uio_extflg = UIO_COPY_CACHED; 2971 uio.uio_loffset = (offset_t)args->cookie; 2972 2973 /* 2974 * bufsize is used to keep track of the size of the response as we 2975 * get post op attributes and filehandles for each entry. This is 2976 * an optimization as the server may have read more entries than will 2977 * fit in the buffer specified by maxcount. We stop calculating 2978 * post op attributes and filehandles once we have exceeded maxcount. 2979 * This will minimize the effect of truncation. 2980 * 2981 * It is primed with: 2982 * 1 for the status + 2983 * 1 for the dir_attributes.attributes boolean + 2984 * 2 for the cookie verifier 2985 * all times BYTES_PER_XDR_UNIT to convert from XDR units 2986 * to bytes. If there are directory attributes to be 2987 * returned, then: 2988 * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3 2989 * time BYTES_PER_XDR_UNIT is added to account for them. 2990 */ 2991 bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT; 2992 if (vap != NULL) 2993 bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT; 2994 2995 getmoredents: 2996 /* 2997 * Here we make a check so that our read unit is not larger than 2998 * the space left in the buffer. 2999 */ 3000 rd_unit = MIN(rd_unit, space_left); 3001 iov.iov_base = (char *)dp; 3002 iov.iov_len = rd_unit; 3003 uio.uio_resid = rd_unit; 3004 prev_len = rd_unit; 3005 3006 error = VOP_READDIR(vp, &uio, cr, &iseof); 3007 3008 if (error) { 3009 kmem_free(data, args->dircount); 3010 goto out; 3011 } 3012 3013 if (uio.uio_resid == prev_len && !iseof) { 3014 if (nents == 0) { 3015 kmem_free(data, args->dircount); 3016 resp->status = NFS3ERR_TOOSMALL; 3017 goto out1; 3018 } 3019 3020 /* 3021 * We could not get any more entries, so get the attributes 3022 * and filehandle for the entries already obtained. 3023 */ 3024 goto good; 3025 } 3026 3027 /* 3028 * We estimate the size of the response by assuming the 3029 * entry exists and attributes and filehandle are also valid 3030 */ 3031 for (size = prev_len - uio.uio_resid; 3032 size > 0; 3033 size -= dp->d_reclen, dp = nextdp(dp)) { 3034 3035 if (dp->d_ino == 0) { 3036 nents++; 3037 continue; 3038 } 3039 3040 namlen[nents] = strlen(dp->d_name); 3041 entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]); 3042 3043 /* 3044 * We need to check to see if the number of bytes left 3045 * to go into the buffer will actually fit into the 3046 * buffer. This is calculated as the size of this 3047 * entry plus: 3048 * 1 for the true/false list indicator + 3049 * 1 for the eof indicator 3050 * times BYTES_PER_XDR_UNIT to convert from XDR units 3051 * to bytes. 3052 * 3053 * Also check the dircount limit against the first entry read 3054 * 3055 */ 3056 tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT; 3057 if (bufsize + tofit > args->maxcount) { 3058 /* 3059 * We make a check here to see if this was the 3060 * first entry being measured. If so, then maxcount 3061 * was too small to begin with and so we need to 3062 * return with NFS3ERR_TOOSMALL. 3063 */ 3064 if (nents == 0) { 3065 kmem_free(data, args->dircount); 3066 resp->status = NFS3ERR_TOOSMALL; 3067 goto out1; 3068 } 3069 iseof = FALSE; 3070 goto good; 3071 } 3072 bufsize += entrysize; 3073 nents++; 3074 } 3075 3076 /* 3077 * If there is enough room to fit at least 1 more entry including 3078 * post op attributes and filehandle in the buffer AND that we haven't 3079 * exceeded dircount then go back and get some more. 3080 */ 3081 if (!iseof && 3082 (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) { 3083 space_left -= (prev_len - uio.uio_resid); 3084 if (space_left >= DIRENT64_RECLEN(MAXNAMELEN)) 3085 goto getmoredents; 3086 3087 /* else, fall through */ 3088 } 3089 3090 good: 3091 3092 #ifdef DEBUG 3093 if (rfs3_do_post_op_attr) { 3094 va.va_mask = AT_ALL; 3095 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3096 } else 3097 vap = NULL; 3098 #else 3099 va.va_mask = AT_ALL; 3100 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3101 #endif 3102 3103 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 3104 3105 infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP); 3106 resp->resok.infop = infop; 3107 3108 dp = (struct dirent64 *)data; 3109 for (i = 0; i < nents; i++) { 3110 3111 if (dp->d_ino == 0) { 3112 infop[i].attr.attributes = FALSE; 3113 infop[i].fh.handle_follows = FALSE; 3114 dp = nextdp(dp); 3115 continue; 3116 } 3117 3118 infop[i].namelen = namlen[i]; 3119 3120 error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr); 3121 if (error) { 3122 infop[i].attr.attributes = FALSE; 3123 infop[i].fh.handle_follows = FALSE; 3124 dp = nextdp(dp); 3125 continue; 3126 } 3127 3128 #ifdef DEBUG 3129 if (rfs3_do_post_op_attr) { 3130 nva.va_mask = AT_ALL; 3131 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? 3132 NULL : &nva; 3133 } else 3134 nvap = NULL; 3135 #else 3136 nva.va_mask = AT_ALL; 3137 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva; 3138 #endif 3139 vattr_to_post_op_attr(nvap, &infop[i].attr); 3140 3141 #ifdef DEBUG 3142 if (!rfs3_do_post_op_fh3) 3143 infop[i].fh.handle_follows = FALSE; 3144 else { 3145 #endif 3146 error = makefh3(&infop[i].fh.handle, nvp, exi); 3147 if (!error) 3148 infop[i].fh.handle_follows = TRUE; 3149 else 3150 infop[i].fh.handle_follows = FALSE; 3151 #ifdef DEBUG 3152 } 3153 #endif 3154 3155 VN_RELE(nvp); 3156 dp = nextdp(dp); 3157 } 3158 3159 #if 0 /* notyet */ 3160 /* 3161 * Don't do this. It causes local disk writes when just 3162 * reading the file and the overhead is deemed larger 3163 * than the benefit. 3164 */ 3165 /* 3166 * Force modified metadata out to stable storage. 3167 */ 3168 (void) VOP_FSYNC(vp, FNODSYNC, cr); 3169 #endif 3170 3171 VN_RELE(vp); 3172 3173 kmem_free(namlen, args->dircount); 3174 3175 resp->status = NFS3_OK; 3176 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes); 3177 resp->resok.cookieverf = 0; 3178 resp->resok.reply.entries = (entryplus3 *)data; 3179 resp->resok.reply.eof = iseof; 3180 resp->resok.size = nents; 3181 resp->resok.count = args->dircount; 3182 resp->resok.maxcount = args->maxcount; 3183 return; 3184 3185 out: 3186 if (curthread->t_flag & T_WOULDBLOCK) { 3187 curthread->t_flag &= ~T_WOULDBLOCK; 3188 resp->status = NFS3ERR_JUKEBOX; 3189 } else 3190 resp->status = puterrno3(error); 3191 out1: 3192 if (vp != NULL) { 3193 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 3194 VN_RELE(vp); 3195 } 3196 3197 if (namlen != NULL) 3198 kmem_free(namlen, args->dircount); 3199 3200 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes); 3201 } 3202 3203 fhandle_t * 3204 rfs3_readdirplus_getfh(READDIRPLUS3args *args) 3205 { 3206 3207 return ((fhandle_t *)&args->dir.fh3_u.nfs_fh3_i.fh3_i); 3208 } 3209 3210 void 3211 rfs3_readdirplus_free(READDIRPLUS3res *resp) 3212 { 3213 3214 if (resp->status == NFS3_OK) { 3215 kmem_free(resp->resok.reply.entries, resp->resok.count); 3216 kmem_free(resp->resok.infop, 3217 resp->resok.size * sizeof (struct entryplus3_info)); 3218 } 3219 } 3220 3221 /* ARGSUSED */ 3222 void 3223 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi, 3224 struct svc_req *req, cred_t *cr) 3225 { 3226 int error; 3227 vnode_t *vp; 3228 struct vattr *vap; 3229 struct vattr va; 3230 struct statvfs64 sb; 3231 3232 vap = NULL; 3233 3234 vp = nfs3_fhtovp(&args->fsroot, exi); 3235 if (vp == NULL) { 3236 error = ESTALE; 3237 goto out; 3238 } 3239 3240 error = VFS_STATVFS(vp->v_vfsp, &sb); 3241 3242 #ifdef DEBUG 3243 if (rfs3_do_post_op_attr) { 3244 va.va_mask = AT_ALL; 3245 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3246 } else 3247 vap = NULL; 3248 #else 3249 va.va_mask = AT_ALL; 3250 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3251 #endif 3252 3253 VN_RELE(vp); 3254 3255 if (error) 3256 goto out; 3257 3258 resp->status = NFS3_OK; 3259 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 3260 if (sb.f_blocks != (fsblkcnt64_t)-1) 3261 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks; 3262 else 3263 resp->resok.tbytes = (size3)sb.f_blocks; 3264 if (sb.f_bfree != (fsblkcnt64_t)-1) 3265 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree; 3266 else 3267 resp->resok.fbytes = (size3)sb.f_bfree; 3268 if (sb.f_bavail != (fsblkcnt64_t)-1) 3269 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail; 3270 else 3271 resp->resok.abytes = (size3)sb.f_bavail; 3272 resp->resok.tfiles = (size3)sb.f_files; 3273 resp->resok.ffiles = (size3)sb.f_ffree; 3274 resp->resok.afiles = (size3)sb.f_favail; 3275 resp->resok.invarsec = 0; 3276 return; 3277 3278 out: 3279 if (curthread->t_flag & T_WOULDBLOCK) { 3280 curthread->t_flag &= ~T_WOULDBLOCK; 3281 resp->status = NFS3ERR_JUKEBOX; 3282 } else 3283 resp->status = puterrno3(error); 3284 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); 3285 } 3286 3287 fhandle_t * 3288 rfs3_fsstat_getfh(FSSTAT3args *args) 3289 { 3290 3291 return ((fhandle_t *)&args->fsroot.fh3_u.nfs_fh3_i.fh3_i); 3292 } 3293 3294 /* ARGSUSED */ 3295 void 3296 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi, 3297 struct svc_req *req, cred_t *cr) 3298 { 3299 vnode_t *vp; 3300 struct vattr *vap; 3301 struct vattr va; 3302 uint32_t xfer_size; 3303 ulong_t l = 0; 3304 int error; 3305 3306 vp = nfs3_fhtovp(&args->fsroot, exi); 3307 if (vp == NULL) { 3308 if (curthread->t_flag & T_WOULDBLOCK) { 3309 curthread->t_flag &= ~T_WOULDBLOCK; 3310 resp->status = NFS3ERR_JUKEBOX; 3311 } else 3312 resp->status = NFS3ERR_STALE; 3313 vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes); 3314 return; 3315 } 3316 3317 #ifdef DEBUG 3318 if (rfs3_do_post_op_attr) { 3319 va.va_mask = AT_ALL; 3320 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3321 } else 3322 vap = NULL; 3323 #else 3324 va.va_mask = AT_ALL; 3325 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3326 #endif 3327 3328 resp->status = NFS3_OK; 3329 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 3330 xfer_size = rfs3_tsize(req); 3331 resp->resok.rtmax = xfer_size; 3332 resp->resok.rtpref = xfer_size; 3333 resp->resok.rtmult = DEV_BSIZE; 3334 resp->resok.wtmax = xfer_size; 3335 resp->resok.wtpref = xfer_size; 3336 resp->resok.wtmult = DEV_BSIZE; 3337 resp->resok.dtpref = MAXBSIZE; 3338 3339 /* 3340 * Large file spec: want maxfilesize based on limit of 3341 * underlying filesystem. We can guess 2^31-1 if need be. 3342 */ 3343 error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr); 3344 3345 VN_RELE(vp); 3346 3347 if (!error && l != 0 && l <= 64) 3348 resp->resok.maxfilesize = (1LL << (l-1)) - 1; 3349 else 3350 resp->resok.maxfilesize = MAXOFF32_T; 3351 3352 resp->resok.time_delta.seconds = 0; 3353 resp->resok.time_delta.nseconds = 1000; 3354 resp->resok.properties = FSF3_LINK | FSF3_SYMLINK | 3355 FSF3_HOMOGENEOUS | FSF3_CANSETTIME; 3356 } 3357 3358 fhandle_t * 3359 rfs3_fsinfo_getfh(FSINFO3args *args) 3360 { 3361 3362 return ((fhandle_t *)&args->fsroot.fh3_u.nfs_fh3_i.fh3_i); 3363 } 3364 3365 /* ARGSUSED */ 3366 void 3367 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi, 3368 struct svc_req *req, cred_t *cr) 3369 { 3370 int error; 3371 vnode_t *vp; 3372 struct vattr *vap; 3373 struct vattr va; 3374 ulong_t val; 3375 3376 vap = NULL; 3377 3378 vp = nfs3_fhtovp(&args->object, exi); 3379 if (vp == NULL) { 3380 error = ESTALE; 3381 goto out; 3382 } 3383 3384 #ifdef DEBUG 3385 if (rfs3_do_post_op_attr) { 3386 va.va_mask = AT_ALL; 3387 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3388 } else 3389 vap = NULL; 3390 #else 3391 va.va_mask = AT_ALL; 3392 vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va; 3393 #endif 3394 3395 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr); 3396 if (error) 3397 goto out; 3398 resp->resok.info.link_max = (uint32)val; 3399 3400 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr); 3401 if (error) 3402 goto out; 3403 resp->resok.info.name_max = (uint32)val; 3404 3405 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr); 3406 if (error) 3407 goto out; 3408 if (val == 1) 3409 resp->resok.info.no_trunc = TRUE; 3410 else 3411 resp->resok.info.no_trunc = FALSE; 3412 3413 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr); 3414 if (error) 3415 goto out; 3416 if (val == 1) 3417 resp->resok.info.chown_restricted = TRUE; 3418 else 3419 resp->resok.info.chown_restricted = FALSE; 3420 3421 VN_RELE(vp); 3422 3423 resp->status = NFS3_OK; 3424 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 3425 resp->resok.info.case_insensitive = FALSE; 3426 resp->resok.info.case_preserving = TRUE; 3427 return; 3428 3429 out: 3430 if (curthread->t_flag & T_WOULDBLOCK) { 3431 curthread->t_flag &= ~T_WOULDBLOCK; 3432 resp->status = NFS3ERR_JUKEBOX; 3433 } else 3434 resp->status = puterrno3(error); 3435 if (vp != NULL) 3436 VN_RELE(vp); 3437 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); 3438 } 3439 3440 fhandle_t * 3441 rfs3_pathconf_getfh(PATHCONF3args *args) 3442 { 3443 3444 return ((fhandle_t *)&args->object.fh3_u.nfs_fh3_i.fh3_i); 3445 } 3446 3447 void 3448 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi, 3449 struct svc_req *req, cred_t *cr) 3450 { 3451 int error; 3452 vnode_t *vp; 3453 struct vattr *bvap; 3454 struct vattr bva; 3455 struct vattr *avap; 3456 struct vattr ava; 3457 3458 bvap = NULL; 3459 avap = NULL; 3460 3461 vp = nfs3_fhtovp(&args->file, exi); 3462 if (vp == NULL) { 3463 error = ESTALE; 3464 goto out; 3465 } 3466 3467 bva.va_mask = AT_ALL; 3468 error = VOP_GETATTR(vp, &bva, 0, cr); 3469 3470 /* 3471 * If we can't get the attributes, then we can't do the 3472 * right access checking. So, we'll fail the request. 3473 */ 3474 if (error) 3475 goto out; 3476 3477 #ifdef DEBUG 3478 if (rfs3_do_pre_op_attr) 3479 bvap = &bva; 3480 else 3481 bvap = NULL; 3482 #else 3483 bvap = &bva; 3484 #endif 3485 3486 if (rdonly(exi, req)) { 3487 resp->status = NFS3ERR_ROFS; 3488 goto out1; 3489 } 3490 3491 if (vp->v_type != VREG) { 3492 resp->status = NFS3ERR_INVAL; 3493 goto out1; 3494 } 3495 3496 if (crgetuid(cr) != bva.va_uid && 3497 (error = VOP_ACCESS(vp, VWRITE, 0, cr))) 3498 goto out; 3499 3500 error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr); 3501 if (!error) 3502 error = VOP_FSYNC(vp, FNODSYNC, cr); 3503 3504 #ifdef DEBUG 3505 if (rfs3_do_post_op_attr) { 3506 ava.va_mask = AT_ALL; 3507 avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava; 3508 } else 3509 avap = NULL; 3510 #else 3511 ava.va_mask = AT_ALL; 3512 avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava; 3513 #endif 3514 3515 if (error) 3516 goto out; 3517 3518 VN_RELE(vp); 3519 3520 resp->status = NFS3_OK; 3521 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); 3522 resp->resok.verf = write3verf; 3523 return; 3524 3525 out: 3526 if (curthread->t_flag & T_WOULDBLOCK) { 3527 curthread->t_flag &= ~T_WOULDBLOCK; 3528 resp->status = NFS3ERR_JUKEBOX; 3529 } else 3530 resp->status = puterrno3(error); 3531 out1: 3532 if (vp != NULL) 3533 VN_RELE(vp); 3534 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc); 3535 } 3536 3537 fhandle_t * 3538 rfs3_commit_getfh(COMMIT3args *args) 3539 { 3540 3541 return ((fhandle_t *)&args->file.fh3_u.nfs_fh3_i.fh3_i); 3542 } 3543 3544 static int 3545 sattr3_to_vattr(sattr3 *sap, struct vattr *vap) 3546 { 3547 3548 vap->va_mask = 0; 3549 3550 if (sap->mode.set_it) { 3551 vap->va_mode = (mode_t)sap->mode.mode; 3552 vap->va_mask |= AT_MODE; 3553 } 3554 if (sap->uid.set_it) { 3555 vap->va_uid = (uid_t)sap->uid.uid; 3556 vap->va_mask |= AT_UID; 3557 } 3558 if (sap->gid.set_it) { 3559 vap->va_gid = (gid_t)sap->gid.gid; 3560 vap->va_mask |= AT_GID; 3561 } 3562 if (sap->size.set_it) { 3563 if (sap->size.size > (size3)((u_longlong_t)-1)) 3564 return (EINVAL); 3565 vap->va_size = sap->size.size; 3566 vap->va_mask |= AT_SIZE; 3567 } 3568 if (sap->atime.set_it == SET_TO_CLIENT_TIME) { 3569 #ifndef _LP64 3570 /* check time validity */ 3571 if (!NFS3_TIME_OK(sap->atime.atime.seconds)) 3572 return (EOVERFLOW); 3573 #endif 3574 /* 3575 * nfs protocol defines times as unsigned so don't extend sign, 3576 * unless sysadmin set nfs_allow_preepoch_time. 3577 */ 3578 NFS_TIME_T_CONVERT(vap->va_atime.tv_sec, 3579 sap->atime.atime.seconds); 3580 vap->va_atime.tv_nsec = (uint32_t)sap->atime.atime.nseconds; 3581 vap->va_mask |= AT_ATIME; 3582 } else if (sap->atime.set_it == SET_TO_SERVER_TIME) { 3583 gethrestime(&vap->va_atime); 3584 vap->va_mask |= AT_ATIME; 3585 } 3586 if (sap->mtime.set_it == SET_TO_CLIENT_TIME) { 3587 #ifndef _LP64 3588 /* check time validity */ 3589 if (!NFS3_TIME_OK(sap->mtime.mtime.seconds)) 3590 return (EOVERFLOW); 3591 #endif 3592 /* 3593 * nfs protocol defines times as unsigned so don't extend sign, 3594 * unless sysadmin set nfs_allow_preepoch_time. 3595 */ 3596 NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec, 3597 sap->mtime.mtime.seconds); 3598 vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds; 3599 vap->va_mask |= AT_MTIME; 3600 } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) { 3601 gethrestime(&vap->va_mtime); 3602 vap->va_mask |= AT_MTIME; 3603 } 3604 3605 return (0); 3606 } 3607 3608 static ftype3 vt_to_nf3[] = { 3609 0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0 3610 }; 3611 3612 static int 3613 vattr_to_fattr3(struct vattr *vap, fattr3 *fap) 3614 { 3615 3616 ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD); 3617 /* Return error if time or size overflow */ 3618 if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) { 3619 return (EOVERFLOW); 3620 } 3621 fap->type = vt_to_nf3[vap->va_type]; 3622 fap->mode = (mode3)(vap->va_mode & MODEMASK); 3623 fap->nlink = (uint32)vap->va_nlink; 3624 if (vap->va_uid == UID_NOBODY) 3625 fap->uid = (uid3)NFS_UID_NOBODY; 3626 else 3627 fap->uid = (uid3)vap->va_uid; 3628 if (vap->va_gid == GID_NOBODY) 3629 fap->gid = (gid3)NFS_GID_NOBODY; 3630 else 3631 fap->gid = (gid3)vap->va_gid; 3632 fap->size = (size3)vap->va_size; 3633 fap->used = (size3)DEV_BSIZE * (size3)vap->va_nblocks; 3634 fap->rdev.specdata1 = (uint32)getmajor(vap->va_rdev); 3635 fap->rdev.specdata2 = (uint32)getminor(vap->va_rdev); 3636 fap->fsid = (uint64)vap->va_fsid; 3637 fap->fileid = (fileid3)vap->va_nodeid; 3638 fap->atime.seconds = vap->va_atime.tv_sec; 3639 fap->atime.nseconds = vap->va_atime.tv_nsec; 3640 fap->mtime.seconds = vap->va_mtime.tv_sec; 3641 fap->mtime.nseconds = vap->va_mtime.tv_nsec; 3642 fap->ctime.seconds = vap->va_ctime.tv_sec; 3643 fap->ctime.nseconds = vap->va_ctime.tv_nsec; 3644 return (0); 3645 } 3646 3647 static int 3648 vattr_to_wcc_attr(struct vattr *vap, wcc_attr *wccap) 3649 { 3650 3651 /* Return error if time or size overflow */ 3652 if (! (NFS_TIME_T_OK(vap->va_mtime.tv_sec) && 3653 NFS_TIME_T_OK(vap->va_ctime.tv_sec) && 3654 NFS3_SIZE_OK(vap->va_size))) { 3655 return (EOVERFLOW); 3656 } 3657 wccap->size = (size3)vap->va_size; 3658 wccap->mtime.seconds = vap->va_mtime.tv_sec; 3659 wccap->mtime.nseconds = vap->va_mtime.tv_nsec; 3660 wccap->ctime.seconds = vap->va_ctime.tv_sec; 3661 wccap->ctime.nseconds = vap->va_ctime.tv_nsec; 3662 return (0); 3663 } 3664 3665 static void 3666 vattr_to_pre_op_attr(struct vattr *vap, pre_op_attr *poap) 3667 { 3668 3669 /* don't return attrs if time overflow */ 3670 if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) { 3671 poap->attributes = TRUE; 3672 } else 3673 poap->attributes = FALSE; 3674 } 3675 3676 void 3677 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap) 3678 { 3679 3680 /* don't return attrs if time overflow */ 3681 if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) { 3682 poap->attributes = TRUE; 3683 } else 3684 poap->attributes = FALSE; 3685 } 3686 3687 static void 3688 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp) 3689 { 3690 3691 vattr_to_pre_op_attr(bvap, &wccp->before); 3692 vattr_to_post_op_attr(avap, &wccp->after); 3693 } 3694 3695 void 3696 rfs3_srvrinit(void) 3697 { 3698 struct rfs3_verf_overlay { 3699 uint_t id; /* a "unique" identifier */ 3700 int ts; /* a unique timestamp */ 3701 } *verfp; 3702 timestruc_t now; 3703 3704 /* 3705 * The following algorithm attempts to find a unique verifier 3706 * to be used as the write verifier returned from the server 3707 * to the client. It is important that this verifier change 3708 * whenever the server reboots. Of secondary importance, it 3709 * is important for the verifier to be unique between two 3710 * different servers. 3711 * 3712 * Thus, an attempt is made to use the system hostid and the 3713 * current time in seconds when the nfssrv kernel module is 3714 * loaded. It is assumed that an NFS server will not be able 3715 * to boot and then to reboot in less than a second. If the 3716 * hostid has not been set, then the current high resolution 3717 * time is used. This will ensure different verifiers each 3718 * time the server reboots and minimize the chances that two 3719 * different servers will have the same verifier. 3720 */ 3721 3722 #ifndef lint 3723 /* 3724 * We ASSERT that this constant logic expression is 3725 * always true because in the past, it wasn't. 3726 */ 3727 ASSERT(sizeof (*verfp) <= sizeof (write3verf)); 3728 #endif 3729 3730 gethrestime(&now); 3731 verfp = (struct rfs3_verf_overlay *)&write3verf; 3732 verfp->ts = (int)now.tv_sec; 3733 verfp->id = (uint_t)nfs_atoi(hw_serial); 3734 3735 if (verfp->id == 0) 3736 verfp->id = (uint_t)now.tv_nsec; 3737 3738 } 3739 3740 void 3741 rfs3_srvrfini(void) 3742 { 3743 /* Nothing to do */ 3744 } 3745