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