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