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