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