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