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