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