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 goto done; 1073 } 1074 1075 if (args->count == 0) { 1076 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 1077 if (in_crit) 1078 nbl_end_crit(vp); 1079 resp->status = NFS3_OK; 1080 vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 1081 resp->resok.count = 0; 1082 resp->resok.eof = FALSE; 1083 resp->resok.data.data_len = 0; 1084 resp->resok.data.data_val = NULL; 1085 resp->resok.data.mp = NULL; 1086 /* RDMA */ 1087 resp->resok.wlist = args->wlist; 1088 resp->resok.wlist_len = resp->resok.count; 1089 goto done; 1090 } 1091 1092 /* 1093 * do not allocate memory more the max. allowed 1094 * transfer size 1095 */ 1096 if (args->count > rfs3_tsize(req)) 1097 args->count = rfs3_tsize(req); 1098 1099 /* 1100 * If returning data via RDMA Write, then grab the chunk list. 1101 * If we aren't returning READ data w/RDMA_WRITE, then grab 1102 * a mblk. 1103 */ 1104 if (args->wlist) { 1105 mp = NULL; 1106 (void) rdma_get_wchunk(req, &iov, args->wlist); 1107 } else { 1108 /* 1109 * mp will contain the data to be sent out in the read reply. 1110 * This will be freed after the reply has been sent out (by the 1111 * driver). 1112 * Let's roundup the data to a BYTES_PER_XDR_UNIT multiple, so 1113 * that the call to xdrmblk_putmblk() never fails. 1114 */ 1115 mp = allocb_wait(RNDUP(args->count), BPRI_MED, STR_NOSIG, 1116 &alloc_err); 1117 ASSERT(mp != NULL); 1118 ASSERT(alloc_err == 0); 1119 1120 iov.iov_base = (caddr_t)mp->b_datap->db_base; 1121 iov.iov_len = args->count; 1122 } 1123 1124 uio.uio_iov = &iov; 1125 uio.uio_iovcnt = 1; 1126 uio.uio_segflg = UIO_SYSSPACE; 1127 uio.uio_extflg = UIO_COPY_CACHED; 1128 uio.uio_loffset = args->offset; 1129 uio.uio_resid = args->count; 1130 1131 error = VOP_READ(vp, &uio, 0, cr, &ct); 1132 1133 if (error) { 1134 freeb(mp); 1135 /* check if a monitor detected a delegation conflict */ 1136 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 1137 resp->status = NFS3ERR_JUKEBOX; 1138 goto out1; 1139 } 1140 goto out; 1141 } 1142 1143 va.va_mask = AT_ALL; 1144 error = VOP_GETATTR(vp, &va, 0, cr, &ct); 1145 1146 #ifdef DEBUG 1147 if (rfs3_do_post_op_attr) { 1148 if (error) 1149 vap = NULL; 1150 else 1151 vap = &va; 1152 } else 1153 vap = NULL; 1154 #else 1155 if (error) 1156 vap = NULL; 1157 else 1158 vap = &va; 1159 #endif 1160 1161 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 1162 1163 if (in_crit) 1164 nbl_end_crit(vp); 1165 1166 resp->status = NFS3_OK; 1167 vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 1168 resp->resok.count = args->count - uio.uio_resid; 1169 if (!error && offset + resp->resok.count == va.va_size) 1170 resp->resok.eof = TRUE; 1171 else 1172 resp->resok.eof = FALSE; 1173 resp->resok.data.data_len = resp->resok.count; 1174 resp->resok.data.mp = mp; 1175 resp->resok.size = (uint_t)args->count; 1176 1177 if (args->wlist) { 1178 resp->resok.data.data_val = (caddr_t)iov.iov_base; 1179 if (!rdma_setup_read_data3(args, &(resp->resok))) { 1180 resp->status = NFS3ERR_INVAL; 1181 } 1182 } else { 1183 resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base; 1184 (resp->resok).wlist = NULL; 1185 } 1186 1187 done: 1188 DTRACE_NFSV3_4(op__read__done, struct svc_req *, req, 1189 cred_t *, cr, vnode_t *, vp, READ3res *, resp); 1190 1191 VN_RELE(vp); 1192 1193 return; 1194 1195 out: 1196 if (curthread->t_flag & T_WOULDBLOCK) { 1197 curthread->t_flag &= ~T_WOULDBLOCK; 1198 resp->status = NFS3ERR_JUKEBOX; 1199 } else 1200 resp->status = puterrno3(error); 1201 out1: 1202 DTRACE_NFSV3_4(op__read__done, struct svc_req *, req, 1203 cred_t *, cr, vnode_t *, vp, READ3res *, resp); 1204 1205 if (vp != NULL) { 1206 if (need_rwunlock) 1207 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 1208 if (in_crit) 1209 nbl_end_crit(vp); 1210 VN_RELE(vp); 1211 } 1212 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes); 1213 } 1214 1215 void 1216 rfs3_read_free(READ3res *resp) 1217 { 1218 mblk_t *mp; 1219 1220 if (resp->status == NFS3_OK) { 1221 mp = resp->resok.data.mp; 1222 if (mp != NULL) 1223 freeb(mp); 1224 } 1225 } 1226 1227 void * 1228 rfs3_read_getfh(READ3args *args) 1229 { 1230 1231 return (&args->file); 1232 } 1233 1234 #define MAX_IOVECS 12 1235 1236 #ifdef DEBUG 1237 static int rfs3_write_hits = 0; 1238 static int rfs3_write_misses = 0; 1239 #endif 1240 1241 void 1242 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi, 1243 struct svc_req *req, cred_t *cr) 1244 { 1245 int error; 1246 vnode_t *vp; 1247 struct vattr *bvap = NULL; 1248 struct vattr bva; 1249 struct vattr *avap = NULL; 1250 struct vattr ava; 1251 u_offset_t rlimit; 1252 struct uio uio; 1253 struct iovec iov[MAX_IOVECS]; 1254 mblk_t *m; 1255 struct iovec *iovp; 1256 int iovcnt; 1257 int ioflag; 1258 cred_t *savecred; 1259 int in_crit = 0; 1260 int rwlock_ret = -1; 1261 caller_context_t ct; 1262 1263 vp = nfs3_fhtovp(&args->file, exi); 1264 1265 DTRACE_NFSV3_4(op__write__start, struct svc_req *, req, 1266 cred_t *, cr, vnode_t *, vp, WRITE3args *, args); 1267 1268 if (vp == NULL) { 1269 error = ESTALE; 1270 goto err; 1271 } 1272 1273 if (is_system_labeled()) { 1274 bslabel_t *clabel = req->rq_label; 1275 1276 ASSERT(clabel != NULL); 1277 DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *, 1278 "got client label from request(1)", struct svc_req *, req); 1279 1280 if (!blequal(&l_admin_low->tsl_label, clabel)) { 1281 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) { 1282 resp->status = NFS3ERR_ACCES; 1283 goto err1; 1284 } 1285 } 1286 } 1287 1288 ct.cc_sysid = 0; 1289 ct.cc_pid = 0; 1290 ct.cc_caller_id = nfs3_srv_caller_id; 1291 ct.cc_flags = CC_DONTBLOCK; 1292 1293 /* 1294 * We have to enter the critical region before calling VOP_RWLOCK 1295 * to avoid a deadlock with ufs. 1296 */ 1297 if (nbl_need_check(vp)) { 1298 nbl_start_crit(vp, RW_READER); 1299 in_crit = 1; 1300 if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0, 1301 NULL)) { 1302 error = EACCES; 1303 goto err; 1304 } 1305 } 1306 1307 rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct); 1308 1309 /* check if a monitor detected a delegation conflict */ 1310 if (rwlock_ret == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 1311 resp->status = NFS3ERR_JUKEBOX; 1312 rwlock_ret = -1; 1313 goto err1; 1314 } 1315 1316 1317 bva.va_mask = AT_ALL; 1318 error = VOP_GETATTR(vp, &bva, 0, cr, &ct); 1319 1320 /* 1321 * If we can't get the attributes, then we can't do the 1322 * right access checking. So, we'll fail the request. 1323 */ 1324 if (error) 1325 goto err; 1326 1327 bvap = &bva; 1328 #ifdef DEBUG 1329 if (!rfs3_do_pre_op_attr) 1330 bvap = NULL; 1331 #endif 1332 avap = bvap; 1333 1334 if (args->count != args->data.data_len) { 1335 resp->status = NFS3ERR_INVAL; 1336 goto err1; 1337 } 1338 1339 if (rdonly(exi, req)) { 1340 resp->status = NFS3ERR_ROFS; 1341 goto err1; 1342 } 1343 1344 if (vp->v_type != VREG) { 1345 resp->status = NFS3ERR_INVAL; 1346 goto err1; 1347 } 1348 1349 if (crgetuid(cr) != bva.va_uid && 1350 (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct))) 1351 goto err; 1352 1353 if (MANDLOCK(vp, bva.va_mode)) { 1354 resp->status = NFS3ERR_ACCES; 1355 goto err1; 1356 } 1357 1358 if (args->count == 0) { 1359 resp->status = NFS3_OK; 1360 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); 1361 resp->resok.count = 0; 1362 resp->resok.committed = args->stable; 1363 resp->resok.verf = write3verf; 1364 goto out; 1365 } 1366 1367 if (args->mblk != NULL) { 1368 iovcnt = 0; 1369 for (m = args->mblk; m != NULL; m = m->b_cont) 1370 iovcnt++; 1371 if (iovcnt <= MAX_IOVECS) { 1372 #ifdef DEBUG 1373 rfs3_write_hits++; 1374 #endif 1375 iovp = iov; 1376 } else { 1377 #ifdef DEBUG 1378 rfs3_write_misses++; 1379 #endif 1380 iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP); 1381 } 1382 mblk_to_iov(args->mblk, iovcnt, iovp); 1383 1384 } else if (args->rlist != NULL) { 1385 iovcnt = 1; 1386 iovp = iov; 1387 iovp->iov_base = (char *)((args->rlist)->u.c_daddr3); 1388 iovp->iov_len = args->count; 1389 } else { 1390 iovcnt = 1; 1391 iovp = iov; 1392 iovp->iov_base = args->data.data_val; 1393 iovp->iov_len = args->count; 1394 } 1395 1396 uio.uio_iov = iovp; 1397 uio.uio_iovcnt = iovcnt; 1398 1399 uio.uio_segflg = UIO_SYSSPACE; 1400 uio.uio_extflg = UIO_COPY_DEFAULT; 1401 uio.uio_loffset = args->offset; 1402 uio.uio_resid = args->count; 1403 uio.uio_llimit = curproc->p_fsz_ctl; 1404 rlimit = uio.uio_llimit - args->offset; 1405 if (rlimit < (u_offset_t)uio.uio_resid) 1406 uio.uio_resid = (int)rlimit; 1407 1408 if (args->stable == UNSTABLE) 1409 ioflag = 0; 1410 else if (args->stable == FILE_SYNC) 1411 ioflag = FSYNC; 1412 else if (args->stable == DATA_SYNC) 1413 ioflag = FDSYNC; 1414 else { 1415 if (iovp != iov) 1416 kmem_free(iovp, sizeof (*iovp) * iovcnt); 1417 resp->status = NFS3ERR_INVAL; 1418 goto err1; 1419 } 1420 1421 /* 1422 * We're changing creds because VM may fault and we need 1423 * the cred of the current thread to be used if quota 1424 * checking is enabled. 1425 */ 1426 savecred = curthread->t_cred; 1427 curthread->t_cred = cr; 1428 error = VOP_WRITE(vp, &uio, ioflag, cr, &ct); 1429 curthread->t_cred = savecred; 1430 1431 if (iovp != iov) 1432 kmem_free(iovp, sizeof (*iovp) * iovcnt); 1433 1434 /* check if a monitor detected a delegation conflict */ 1435 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 1436 resp->status = NFS3ERR_JUKEBOX; 1437 goto err1; 1438 } 1439 1440 ava.va_mask = AT_ALL; 1441 avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava; 1442 1443 #ifdef DEBUG 1444 if (!rfs3_do_post_op_attr) 1445 avap = NULL; 1446 #endif 1447 1448 if (error) 1449 goto err; 1450 1451 /* 1452 * If we were unable to get the V_WRITELOCK_TRUE, then we 1453 * may not have accurate after attrs, so check if 1454 * we have both attributes, they have a non-zero va_seq, and 1455 * va_seq has changed by exactly one, 1456 * if not, turn off the before attr. 1457 */ 1458 if (rwlock_ret != V_WRITELOCK_TRUE) { 1459 if (bvap == NULL || avap == NULL || 1460 bvap->va_seq == 0 || avap->va_seq == 0 || 1461 avap->va_seq != (bvap->va_seq + 1)) { 1462 bvap = NULL; 1463 } 1464 } 1465 1466 resp->status = NFS3_OK; 1467 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); 1468 resp->resok.count = args->count - uio.uio_resid; 1469 resp->resok.committed = args->stable; 1470 resp->resok.verf = write3verf; 1471 goto out; 1472 1473 err: 1474 if (curthread->t_flag & T_WOULDBLOCK) { 1475 curthread->t_flag &= ~T_WOULDBLOCK; 1476 resp->status = NFS3ERR_JUKEBOX; 1477 } else 1478 resp->status = puterrno3(error); 1479 err1: 1480 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc); 1481 out: 1482 DTRACE_NFSV3_4(op__write__done, struct svc_req *, req, 1483 cred_t *, cr, vnode_t *, vp, WRITE3res *, resp); 1484 1485 if (vp != NULL) { 1486 if (rwlock_ret != -1) 1487 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct); 1488 if (in_crit) 1489 nbl_end_crit(vp); 1490 VN_RELE(vp); 1491 } 1492 } 1493 1494 void * 1495 rfs3_write_getfh(WRITE3args *args) 1496 { 1497 1498 return (&args->file); 1499 } 1500 1501 void 1502 rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi, 1503 struct svc_req *req, cred_t *cr) 1504 { 1505 int error; 1506 int in_crit = 0; 1507 vnode_t *vp; 1508 vnode_t *tvp = NULL; 1509 vnode_t *dvp; 1510 struct vattr *vap; 1511 struct vattr va; 1512 struct vattr *dbvap; 1513 struct vattr dbva; 1514 struct vattr *davap; 1515 struct vattr dava; 1516 enum vcexcl excl; 1517 nfstime3 *mtime; 1518 len_t reqsize; 1519 bool_t trunc; 1520 struct sockaddr *ca; 1521 char *name = NULL; 1522 1523 dbvap = NULL; 1524 davap = NULL; 1525 1526 dvp = nfs3_fhtovp(&args->where.dir, exi); 1527 1528 DTRACE_NFSV3_4(op__create__start, struct svc_req *, req, 1529 cred_t *, cr, vnode_t *, dvp, CREATE3args *, args); 1530 1531 if (dvp == NULL) { 1532 error = ESTALE; 1533 goto out; 1534 } 1535 1536 #ifdef DEBUG 1537 if (rfs3_do_pre_op_attr) { 1538 dbva.va_mask = AT_ALL; 1539 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 1540 } else 1541 dbvap = NULL; 1542 #else 1543 dbva.va_mask = AT_ALL; 1544 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 1545 #endif 1546 davap = dbvap; 1547 1548 if (args->where.name == nfs3nametoolong) { 1549 resp->status = NFS3ERR_NAMETOOLONG; 1550 goto out1; 1551 } 1552 1553 if (args->where.name == NULL || *(args->where.name) == '\0') { 1554 resp->status = NFS3ERR_ACCES; 1555 goto out1; 1556 } 1557 1558 if (rdonly(exi, req)) { 1559 resp->status = NFS3ERR_ROFS; 1560 goto out1; 1561 } 1562 1563 if (is_system_labeled()) { 1564 bslabel_t *clabel = req->rq_label; 1565 1566 ASSERT(clabel != NULL); 1567 DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *, 1568 "got client label from request(1)", struct svc_req *, req); 1569 1570 if (!blequal(&l_admin_low->tsl_label, clabel)) { 1571 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) { 1572 resp->status = NFS3ERR_ACCES; 1573 goto out1; 1574 } 1575 } 1576 } 1577 1578 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 1579 name = nfscmd_convname(ca, exi, args->where.name, 1580 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 1581 1582 if (name == NULL) { 1583 /* This is really a Solaris EILSEQ */ 1584 resp->status = NFS3ERR_INVAL; 1585 goto out1; 1586 } 1587 1588 if (args->how.mode == EXCLUSIVE) { 1589 va.va_mask = AT_TYPE | AT_MODE | AT_MTIME; 1590 va.va_type = VREG; 1591 va.va_mode = (mode_t)0; 1592 /* 1593 * Ensure no time overflows and that types match 1594 */ 1595 mtime = (nfstime3 *)&args->how.createhow3_u.verf; 1596 va.va_mtime.tv_sec = mtime->seconds % INT32_MAX; 1597 va.va_mtime.tv_nsec = mtime->nseconds; 1598 excl = EXCL; 1599 } else { 1600 error = sattr3_to_vattr(&args->how.createhow3_u.obj_attributes, 1601 &va); 1602 if (error) 1603 goto out; 1604 va.va_mask |= AT_TYPE; 1605 va.va_type = VREG; 1606 if (args->how.mode == GUARDED) 1607 excl = EXCL; 1608 else { 1609 excl = NONEXCL; 1610 1611 /* 1612 * During creation of file in non-exclusive mode 1613 * if size of file is being set then make sure 1614 * that if the file already exists that no conflicting 1615 * non-blocking mandatory locks exists in the region 1616 * being modified. If there are conflicting locks fail 1617 * the operation with EACCES. 1618 */ 1619 if (va.va_mask & AT_SIZE) { 1620 struct vattr tva; 1621 1622 /* 1623 * Does file already exist? 1624 */ 1625 error = VOP_LOOKUP(dvp, name, &tvp, 1626 NULL, 0, NULL, cr, NULL, NULL, NULL); 1627 1628 /* 1629 * Check to see if the file has been delegated 1630 * to a v4 client. If so, then begin recall of 1631 * the delegation and return JUKEBOX to allow 1632 * the client to retrasmit its request. 1633 */ 1634 1635 trunc = va.va_size == 0; 1636 if (!error && 1637 rfs4_check_delegated(FWRITE, tvp, trunc)) { 1638 resp->status = NFS3ERR_JUKEBOX; 1639 goto out1; 1640 } 1641 1642 /* 1643 * Check for NBMAND lock conflicts 1644 */ 1645 if (!error && nbl_need_check(tvp)) { 1646 u_offset_t offset; 1647 ssize_t len; 1648 1649 nbl_start_crit(tvp, RW_READER); 1650 in_crit = 1; 1651 1652 tva.va_mask = AT_SIZE; 1653 error = VOP_GETATTR(tvp, &tva, 0, cr, 1654 NULL); 1655 /* 1656 * Can't check for conflicts, so return 1657 * error. 1658 */ 1659 if (error) 1660 goto out; 1661 1662 offset = tva.va_size < va.va_size ? 1663 tva.va_size : va.va_size; 1664 len = tva.va_size < va.va_size ? 1665 va.va_size - tva.va_size : 1666 tva.va_size - va.va_size; 1667 if (nbl_conflict(tvp, NBL_WRITE, 1668 offset, len, 0, NULL)) { 1669 error = EACCES; 1670 goto out; 1671 } 1672 } else if (tvp) { 1673 VN_RELE(tvp); 1674 tvp = NULL; 1675 } 1676 } 1677 } 1678 if (va.va_mask & AT_SIZE) 1679 reqsize = va.va_size; 1680 } 1681 1682 /* 1683 * Must specify the mode. 1684 */ 1685 if (!(va.va_mask & AT_MODE)) { 1686 resp->status = NFS3ERR_INVAL; 1687 goto out1; 1688 } 1689 1690 /* 1691 * If the filesystem is exported with nosuid, then mask off 1692 * the setuid and setgid bits. 1693 */ 1694 if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID)) 1695 va.va_mode &= ~(VSUID | VSGID); 1696 1697 tryagain: 1698 /* 1699 * The file open mode used is VWRITE. If the client needs 1700 * some other semantic, then it should do the access checking 1701 * itself. It would have been nice to have the file open mode 1702 * passed as part of the arguments. 1703 */ 1704 error = VOP_CREATE(dvp, name, &va, excl, VWRITE, 1705 &vp, cr, 0, NULL, NULL); 1706 1707 #ifdef DEBUG 1708 if (rfs3_do_post_op_attr) { 1709 dava.va_mask = AT_ALL; 1710 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 1711 } else 1712 davap = NULL; 1713 #else 1714 dava.va_mask = AT_ALL; 1715 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 1716 #endif 1717 1718 if (error) { 1719 /* 1720 * If we got something other than file already exists 1721 * then just return this error. Otherwise, we got 1722 * EEXIST. If we were doing a GUARDED create, then 1723 * just return this error. Otherwise, we need to 1724 * make sure that this wasn't a duplicate of an 1725 * exclusive create request. 1726 * 1727 * The assumption is made that a non-exclusive create 1728 * request will never return EEXIST. 1729 */ 1730 if (error != EEXIST || args->how.mode == GUARDED) 1731 goto out; 1732 /* 1733 * Lookup the file so that we can get a vnode for it. 1734 */ 1735 error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, 1736 NULL, cr, NULL, NULL, NULL); 1737 if (error) { 1738 /* 1739 * We couldn't find the file that we thought that 1740 * we just created. So, we'll just try creating 1741 * it again. 1742 */ 1743 if (error == ENOENT) 1744 goto tryagain; 1745 goto out; 1746 } 1747 1748 /* 1749 * If the file is delegated to a v4 client, go ahead 1750 * and initiate recall, this create is a hint that a 1751 * conflicting v3 open has occurred. 1752 */ 1753 1754 if (rfs4_check_delegated(FWRITE, vp, FALSE)) { 1755 VN_RELE(vp); 1756 resp->status = NFS3ERR_JUKEBOX; 1757 goto out1; 1758 } 1759 1760 va.va_mask = AT_ALL; 1761 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 1762 1763 mtime = (nfstime3 *)&args->how.createhow3_u.verf; 1764 /* % with INT32_MAX to prevent overflows */ 1765 if (args->how.mode == EXCLUSIVE && (vap == NULL || 1766 vap->va_mtime.tv_sec != 1767 (mtime->seconds % INT32_MAX) || 1768 vap->va_mtime.tv_nsec != mtime->nseconds)) { 1769 VN_RELE(vp); 1770 error = EEXIST; 1771 goto out; 1772 } 1773 } else { 1774 1775 if ((args->how.mode == UNCHECKED || 1776 args->how.mode == GUARDED) && 1777 args->how.createhow3_u.obj_attributes.size.set_it && 1778 va.va_size == 0) 1779 trunc = TRUE; 1780 else 1781 trunc = FALSE; 1782 1783 if (rfs4_check_delegated(FWRITE, vp, trunc)) { 1784 VN_RELE(vp); 1785 resp->status = NFS3ERR_JUKEBOX; 1786 goto out1; 1787 } 1788 1789 va.va_mask = AT_ALL; 1790 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 1791 1792 /* 1793 * We need to check to make sure that the file got 1794 * created to the indicated size. If not, we do a 1795 * setattr to try to change the size, but we don't 1796 * try too hard. This shouldn't a problem as most 1797 * clients will only specifiy a size of zero which 1798 * local file systems handle. However, even if 1799 * the client does specify a non-zero size, it can 1800 * still recover by checking the size of the file 1801 * after it has created it and then issue a setattr 1802 * request of its own to set the size of the file. 1803 */ 1804 if (vap != NULL && 1805 (args->how.mode == UNCHECKED || 1806 args->how.mode == GUARDED) && 1807 args->how.createhow3_u.obj_attributes.size.set_it && 1808 vap->va_size != reqsize) { 1809 va.va_mask = AT_SIZE; 1810 va.va_size = reqsize; 1811 (void) VOP_SETATTR(vp, &va, 0, cr, NULL); 1812 va.va_mask = AT_ALL; 1813 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 1814 } 1815 } 1816 1817 if (name != args->where.name) 1818 kmem_free(name, MAXPATHLEN + 1); 1819 1820 #ifdef DEBUG 1821 if (!rfs3_do_post_op_attr) 1822 vap = NULL; 1823 #endif 1824 1825 #ifdef DEBUG 1826 if (!rfs3_do_post_op_fh3) 1827 resp->resok.obj.handle_follows = FALSE; 1828 else { 1829 #endif 1830 error = makefh3(&resp->resok.obj.handle, vp, exi); 1831 if (error) 1832 resp->resok.obj.handle_follows = FALSE; 1833 else 1834 resp->resok.obj.handle_follows = TRUE; 1835 #ifdef DEBUG 1836 } 1837 #endif 1838 1839 /* 1840 * Force modified data and metadata out to stable storage. 1841 */ 1842 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 1843 (void) VOP_FSYNC(dvp, 0, cr, NULL); 1844 1845 VN_RELE(vp); 1846 if (tvp != NULL) { 1847 if (in_crit) 1848 nbl_end_crit(tvp); 1849 VN_RELE(tvp); 1850 } 1851 1852 resp->status = NFS3_OK; 1853 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 1854 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 1855 1856 DTRACE_NFSV3_4(op__create__done, struct svc_req *, req, 1857 cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp); 1858 1859 VN_RELE(dvp); 1860 return; 1861 1862 out: 1863 if (curthread->t_flag & T_WOULDBLOCK) { 1864 curthread->t_flag &= ~T_WOULDBLOCK; 1865 resp->status = NFS3ERR_JUKEBOX; 1866 } else 1867 resp->status = puterrno3(error); 1868 out1: 1869 DTRACE_NFSV3_4(op__create__done, struct svc_req *, req, 1870 cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp); 1871 1872 if (name != NULL && name != args->where.name) 1873 kmem_free(name, MAXPATHLEN + 1); 1874 1875 if (tvp != NULL) { 1876 if (in_crit) 1877 nbl_end_crit(tvp); 1878 VN_RELE(tvp); 1879 } 1880 if (dvp != NULL) 1881 VN_RELE(dvp); 1882 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 1883 } 1884 1885 void * 1886 rfs3_create_getfh(CREATE3args *args) 1887 { 1888 1889 return (&args->where.dir); 1890 } 1891 1892 void 1893 rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi, 1894 struct svc_req *req, cred_t *cr) 1895 { 1896 int error; 1897 vnode_t *vp = NULL; 1898 vnode_t *dvp; 1899 struct vattr *vap; 1900 struct vattr va; 1901 struct vattr *dbvap; 1902 struct vattr dbva; 1903 struct vattr *davap; 1904 struct vattr dava; 1905 struct sockaddr *ca; 1906 char *name = NULL; 1907 1908 dbvap = NULL; 1909 davap = NULL; 1910 1911 dvp = nfs3_fhtovp(&args->where.dir, exi); 1912 1913 DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req, 1914 cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args); 1915 1916 if (dvp == NULL) { 1917 error = ESTALE; 1918 goto out; 1919 } 1920 1921 #ifdef DEBUG 1922 if (rfs3_do_pre_op_attr) { 1923 dbva.va_mask = AT_ALL; 1924 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 1925 } else 1926 dbvap = NULL; 1927 #else 1928 dbva.va_mask = AT_ALL; 1929 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 1930 #endif 1931 davap = dbvap; 1932 1933 if (args->where.name == nfs3nametoolong) { 1934 resp->status = NFS3ERR_NAMETOOLONG; 1935 goto out1; 1936 } 1937 1938 if (args->where.name == NULL || *(args->where.name) == '\0') { 1939 resp->status = NFS3ERR_ACCES; 1940 goto out1; 1941 } 1942 1943 if (rdonly(exi, req)) { 1944 resp->status = NFS3ERR_ROFS; 1945 goto out1; 1946 } 1947 1948 if (is_system_labeled()) { 1949 bslabel_t *clabel = req->rq_label; 1950 1951 ASSERT(clabel != NULL); 1952 DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *, 1953 "got client label from request(1)", struct svc_req *, req); 1954 1955 if (!blequal(&l_admin_low->tsl_label, clabel)) { 1956 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) { 1957 resp->status = NFS3ERR_ACCES; 1958 goto out1; 1959 } 1960 } 1961 } 1962 1963 error = sattr3_to_vattr(&args->attributes, &va); 1964 if (error) 1965 goto out; 1966 1967 if (!(va.va_mask & AT_MODE)) { 1968 resp->status = NFS3ERR_INVAL; 1969 goto out1; 1970 } 1971 1972 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 1973 name = nfscmd_convname(ca, exi, args->where.name, 1974 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 1975 1976 if (name == NULL) { 1977 resp->status = NFS3ERR_INVAL; 1978 goto out1; 1979 } 1980 1981 va.va_mask |= AT_TYPE; 1982 va.va_type = VDIR; 1983 1984 error = VOP_MKDIR(dvp, name, &va, &vp, cr, NULL, 0, NULL); 1985 1986 if (name != args->where.name) 1987 kmem_free(name, MAXPATHLEN + 1); 1988 1989 #ifdef DEBUG 1990 if (rfs3_do_post_op_attr) { 1991 dava.va_mask = AT_ALL; 1992 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 1993 } else 1994 davap = NULL; 1995 #else 1996 dava.va_mask = AT_ALL; 1997 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 1998 #endif 1999 2000 /* 2001 * Force modified data and metadata out to stable storage. 2002 */ 2003 (void) VOP_FSYNC(dvp, 0, cr, NULL); 2004 2005 if (error) 2006 goto out; 2007 2008 #ifdef DEBUG 2009 if (!rfs3_do_post_op_fh3) 2010 resp->resok.obj.handle_follows = FALSE; 2011 else { 2012 #endif 2013 error = makefh3(&resp->resok.obj.handle, vp, exi); 2014 if (error) 2015 resp->resok.obj.handle_follows = FALSE; 2016 else 2017 resp->resok.obj.handle_follows = TRUE; 2018 #ifdef DEBUG 2019 } 2020 #endif 2021 2022 #ifdef DEBUG 2023 if (rfs3_do_post_op_attr) { 2024 va.va_mask = AT_ALL; 2025 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 2026 } else 2027 vap = NULL; 2028 #else 2029 va.va_mask = AT_ALL; 2030 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 2031 #endif 2032 2033 /* 2034 * Force modified data and metadata out to stable storage. 2035 */ 2036 (void) VOP_FSYNC(vp, 0, cr, NULL); 2037 2038 VN_RELE(vp); 2039 2040 resp->status = NFS3_OK; 2041 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 2042 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 2043 2044 DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req, 2045 cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp); 2046 VN_RELE(dvp); 2047 2048 return; 2049 2050 out: 2051 if (curthread->t_flag & T_WOULDBLOCK) { 2052 curthread->t_flag &= ~T_WOULDBLOCK; 2053 resp->status = NFS3ERR_JUKEBOX; 2054 } else 2055 resp->status = puterrno3(error); 2056 out1: 2057 DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req, 2058 cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp); 2059 if (dvp != NULL) 2060 VN_RELE(dvp); 2061 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 2062 } 2063 2064 void * 2065 rfs3_mkdir_getfh(MKDIR3args *args) 2066 { 2067 2068 return (&args->where.dir); 2069 } 2070 2071 void 2072 rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi, 2073 struct svc_req *req, cred_t *cr) 2074 { 2075 int error; 2076 vnode_t *vp; 2077 vnode_t *dvp; 2078 struct vattr *vap; 2079 struct vattr va; 2080 struct vattr *dbvap; 2081 struct vattr dbva; 2082 struct vattr *davap; 2083 struct vattr dava; 2084 struct sockaddr *ca; 2085 char *name = NULL; 2086 char *symdata = NULL; 2087 2088 dbvap = NULL; 2089 davap = NULL; 2090 2091 dvp = nfs3_fhtovp(&args->where.dir, exi); 2092 2093 DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req, 2094 cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args); 2095 2096 if (dvp == NULL) { 2097 error = ESTALE; 2098 goto err; 2099 } 2100 2101 #ifdef DEBUG 2102 if (rfs3_do_pre_op_attr) { 2103 dbva.va_mask = AT_ALL; 2104 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 2105 } else 2106 dbvap = NULL; 2107 #else 2108 dbva.va_mask = AT_ALL; 2109 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 2110 #endif 2111 davap = dbvap; 2112 2113 if (args->where.name == nfs3nametoolong) { 2114 resp->status = NFS3ERR_NAMETOOLONG; 2115 goto err1; 2116 } 2117 2118 if (args->where.name == NULL || *(args->where.name) == '\0') { 2119 resp->status = NFS3ERR_ACCES; 2120 goto err1; 2121 } 2122 2123 if (rdonly(exi, req)) { 2124 resp->status = NFS3ERR_ROFS; 2125 goto err1; 2126 } 2127 2128 if (is_system_labeled()) { 2129 bslabel_t *clabel = req->rq_label; 2130 2131 ASSERT(clabel != NULL); 2132 DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *, 2133 "got client label from request(1)", struct svc_req *, req); 2134 2135 if (!blequal(&l_admin_low->tsl_label, clabel)) { 2136 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) { 2137 resp->status = NFS3ERR_ACCES; 2138 goto err1; 2139 } 2140 } 2141 } 2142 2143 error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va); 2144 if (error) 2145 goto err; 2146 2147 if (!(va.va_mask & AT_MODE)) { 2148 resp->status = NFS3ERR_INVAL; 2149 goto err1; 2150 } 2151 2152 if (args->symlink.symlink_data == nfs3nametoolong) { 2153 resp->status = NFS3ERR_NAMETOOLONG; 2154 goto err1; 2155 } 2156 2157 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2158 name = nfscmd_convname(ca, exi, args->where.name, 2159 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2160 2161 if (name == NULL) { 2162 /* This is really a Solaris EILSEQ */ 2163 resp->status = NFS3ERR_INVAL; 2164 goto err1; 2165 } 2166 2167 symdata = nfscmd_convname(ca, exi, args->symlink.symlink_data, 2168 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2169 if (symdata == NULL) { 2170 /* This is really a Solaris EILSEQ */ 2171 resp->status = NFS3ERR_INVAL; 2172 goto err1; 2173 } 2174 2175 2176 va.va_mask |= AT_TYPE; 2177 va.va_type = VLNK; 2178 2179 error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0); 2180 2181 #ifdef DEBUG 2182 if (rfs3_do_post_op_attr) { 2183 dava.va_mask = AT_ALL; 2184 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 2185 } else 2186 davap = NULL; 2187 #else 2188 dava.va_mask = AT_ALL; 2189 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 2190 #endif 2191 2192 if (error) 2193 goto err; 2194 2195 error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr, 2196 NULL, NULL, NULL); 2197 2198 /* 2199 * Force modified data and metadata out to stable storage. 2200 */ 2201 (void) VOP_FSYNC(dvp, 0, cr, NULL); 2202 2203 2204 resp->status = NFS3_OK; 2205 if (error) { 2206 resp->resok.obj.handle_follows = FALSE; 2207 vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes); 2208 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 2209 goto out; 2210 } 2211 2212 #ifdef DEBUG 2213 if (!rfs3_do_post_op_fh3) 2214 resp->resok.obj.handle_follows = FALSE; 2215 else { 2216 #endif 2217 error = makefh3(&resp->resok.obj.handle, vp, exi); 2218 if (error) 2219 resp->resok.obj.handle_follows = FALSE; 2220 else 2221 resp->resok.obj.handle_follows = TRUE; 2222 #ifdef DEBUG 2223 } 2224 #endif 2225 2226 #ifdef DEBUG 2227 if (rfs3_do_post_op_attr) { 2228 va.va_mask = AT_ALL; 2229 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 2230 } else 2231 vap = NULL; 2232 #else 2233 va.va_mask = AT_ALL; 2234 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 2235 #endif 2236 2237 /* 2238 * Force modified data and metadata out to stable storage. 2239 */ 2240 (void) VOP_FSYNC(vp, 0, cr, NULL); 2241 2242 VN_RELE(vp); 2243 2244 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 2245 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 2246 goto out; 2247 2248 err: 2249 if (curthread->t_flag & T_WOULDBLOCK) { 2250 curthread->t_flag &= ~T_WOULDBLOCK; 2251 resp->status = NFS3ERR_JUKEBOX; 2252 } else 2253 resp->status = puterrno3(error); 2254 err1: 2255 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 2256 out: 2257 if (name != NULL && name != args->where.name) 2258 kmem_free(name, MAXPATHLEN + 1); 2259 if (symdata != NULL && symdata != args->symlink.symlink_data) 2260 kmem_free(symdata, MAXPATHLEN + 1); 2261 2262 DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req, 2263 cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp); 2264 2265 if (dvp != NULL) 2266 VN_RELE(dvp); 2267 } 2268 2269 void * 2270 rfs3_symlink_getfh(SYMLINK3args *args) 2271 { 2272 2273 return (&args->where.dir); 2274 } 2275 2276 void 2277 rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi, 2278 struct svc_req *req, cred_t *cr) 2279 { 2280 int error; 2281 vnode_t *vp; 2282 vnode_t *realvp; 2283 vnode_t *dvp; 2284 struct vattr *vap; 2285 struct vattr va; 2286 struct vattr *dbvap; 2287 struct vattr dbva; 2288 struct vattr *davap; 2289 struct vattr dava; 2290 int mode; 2291 enum vcexcl excl; 2292 struct sockaddr *ca; 2293 char *name = NULL; 2294 2295 dbvap = NULL; 2296 davap = NULL; 2297 2298 dvp = nfs3_fhtovp(&args->where.dir, exi); 2299 2300 DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req, 2301 cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args); 2302 2303 if (dvp == NULL) { 2304 error = ESTALE; 2305 goto out; 2306 } 2307 2308 #ifdef DEBUG 2309 if (rfs3_do_pre_op_attr) { 2310 dbva.va_mask = AT_ALL; 2311 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 2312 } else 2313 dbvap = NULL; 2314 #else 2315 dbva.va_mask = AT_ALL; 2316 dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 2317 #endif 2318 davap = dbvap; 2319 2320 if (args->where.name == nfs3nametoolong) { 2321 resp->status = NFS3ERR_NAMETOOLONG; 2322 goto out1; 2323 } 2324 2325 if (args->where.name == NULL || *(args->where.name) == '\0') { 2326 resp->status = NFS3ERR_ACCES; 2327 goto out1; 2328 } 2329 2330 if (rdonly(exi, req)) { 2331 resp->status = NFS3ERR_ROFS; 2332 goto out1; 2333 } 2334 2335 if (is_system_labeled()) { 2336 bslabel_t *clabel = req->rq_label; 2337 2338 ASSERT(clabel != NULL); 2339 DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *, 2340 "got client label from request(1)", struct svc_req *, req); 2341 2342 if (!blequal(&l_admin_low->tsl_label, clabel)) { 2343 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) { 2344 resp->status = NFS3ERR_ACCES; 2345 goto out1; 2346 } 2347 } 2348 } 2349 2350 switch (args->what.type) { 2351 case NF3CHR: 2352 case NF3BLK: 2353 error = sattr3_to_vattr( 2354 &args->what.mknoddata3_u.device.dev_attributes, &va); 2355 if (error) 2356 goto out; 2357 if (secpolicy_sys_devices(cr) != 0) { 2358 resp->status = NFS3ERR_PERM; 2359 goto out1; 2360 } 2361 if (args->what.type == NF3CHR) 2362 va.va_type = VCHR; 2363 else 2364 va.va_type = VBLK; 2365 va.va_rdev = makedevice( 2366 args->what.mknoddata3_u.device.spec.specdata1, 2367 args->what.mknoddata3_u.device.spec.specdata2); 2368 va.va_mask |= AT_TYPE | AT_RDEV; 2369 break; 2370 case NF3SOCK: 2371 error = sattr3_to_vattr( 2372 &args->what.mknoddata3_u.pipe_attributes, &va); 2373 if (error) 2374 goto out; 2375 va.va_type = VSOCK; 2376 va.va_mask |= AT_TYPE; 2377 break; 2378 case NF3FIFO: 2379 error = sattr3_to_vattr( 2380 &args->what.mknoddata3_u.pipe_attributes, &va); 2381 if (error) 2382 goto out; 2383 va.va_type = VFIFO; 2384 va.va_mask |= AT_TYPE; 2385 break; 2386 default: 2387 resp->status = NFS3ERR_BADTYPE; 2388 goto out1; 2389 } 2390 2391 /* 2392 * Must specify the mode. 2393 */ 2394 if (!(va.va_mask & AT_MODE)) { 2395 resp->status = NFS3ERR_INVAL; 2396 goto out1; 2397 } 2398 2399 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2400 name = nfscmd_convname(ca, exi, args->where.name, 2401 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2402 2403 if (name == NULL) { 2404 resp->status = NFS3ERR_INVAL; 2405 goto out1; 2406 } 2407 2408 excl = EXCL; 2409 2410 mode = 0; 2411 2412 error = VOP_CREATE(dvp, name, &va, excl, mode, 2413 &vp, cr, 0, NULL, NULL); 2414 2415 if (name != args->where.name) 2416 kmem_free(name, MAXPATHLEN + 1); 2417 2418 #ifdef DEBUG 2419 if (rfs3_do_post_op_attr) { 2420 dava.va_mask = AT_ALL; 2421 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 2422 } else 2423 davap = NULL; 2424 #else 2425 dava.va_mask = AT_ALL; 2426 davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 2427 #endif 2428 2429 /* 2430 * Force modified data and metadata out to stable storage. 2431 */ 2432 (void) VOP_FSYNC(dvp, 0, cr, NULL); 2433 2434 if (error) 2435 goto out; 2436 2437 resp->status = NFS3_OK; 2438 2439 #ifdef DEBUG 2440 if (!rfs3_do_post_op_fh3) 2441 resp->resok.obj.handle_follows = FALSE; 2442 else { 2443 #endif 2444 error = makefh3(&resp->resok.obj.handle, vp, exi); 2445 if (error) 2446 resp->resok.obj.handle_follows = FALSE; 2447 else 2448 resp->resok.obj.handle_follows = TRUE; 2449 #ifdef DEBUG 2450 } 2451 #endif 2452 2453 #ifdef DEBUG 2454 if (rfs3_do_post_op_attr) { 2455 va.va_mask = AT_ALL; 2456 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 2457 } else 2458 vap = NULL; 2459 #else 2460 va.va_mask = AT_ALL; 2461 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 2462 #endif 2463 2464 /* 2465 * Force modified metadata out to stable storage. 2466 * 2467 * if a underlying vp exists, pass it to VOP_FSYNC 2468 */ 2469 if (VOP_REALVP(vp, &realvp, NULL) == 0) 2470 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL); 2471 else 2472 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 2473 2474 VN_RELE(vp); 2475 2476 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 2477 vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 2478 DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req, 2479 cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp); 2480 VN_RELE(dvp); 2481 return; 2482 2483 out: 2484 if (curthread->t_flag & T_WOULDBLOCK) { 2485 curthread->t_flag &= ~T_WOULDBLOCK; 2486 resp->status = NFS3ERR_JUKEBOX; 2487 } else 2488 resp->status = puterrno3(error); 2489 out1: 2490 DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req, 2491 cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp); 2492 if (dvp != NULL) 2493 VN_RELE(dvp); 2494 vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 2495 } 2496 2497 void * 2498 rfs3_mknod_getfh(MKNOD3args *args) 2499 { 2500 2501 return (&args->where.dir); 2502 } 2503 2504 void 2505 rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi, 2506 struct svc_req *req, cred_t *cr) 2507 { 2508 int error = 0; 2509 vnode_t *vp; 2510 struct vattr *bvap; 2511 struct vattr bva; 2512 struct vattr *avap; 2513 struct vattr ava; 2514 vnode_t *targvp = NULL; 2515 struct sockaddr *ca; 2516 char *name = NULL; 2517 2518 bvap = NULL; 2519 avap = NULL; 2520 2521 vp = nfs3_fhtovp(&args->object.dir, exi); 2522 2523 DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req, 2524 cred_t *, cr, vnode_t *, vp, REMOVE3args *, args); 2525 2526 if (vp == NULL) { 2527 error = ESTALE; 2528 goto err; 2529 } 2530 2531 #ifdef DEBUG 2532 if (rfs3_do_pre_op_attr) { 2533 bva.va_mask = AT_ALL; 2534 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva; 2535 } else 2536 bvap = NULL; 2537 #else 2538 bva.va_mask = AT_ALL; 2539 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva; 2540 #endif 2541 avap = bvap; 2542 2543 if (vp->v_type != VDIR) { 2544 resp->status = NFS3ERR_NOTDIR; 2545 goto err1; 2546 } 2547 2548 if (args->object.name == nfs3nametoolong) { 2549 resp->status = NFS3ERR_NAMETOOLONG; 2550 goto err1; 2551 } 2552 2553 if (args->object.name == NULL || *(args->object.name) == '\0') { 2554 resp->status = NFS3ERR_ACCES; 2555 goto err1; 2556 } 2557 2558 if (rdonly(exi, req)) { 2559 resp->status = NFS3ERR_ROFS; 2560 goto err1; 2561 } 2562 2563 if (is_system_labeled()) { 2564 bslabel_t *clabel = req->rq_label; 2565 2566 ASSERT(clabel != NULL); 2567 DTRACE_PROBE2(tx__rfs3__log__info__opremove__clabel, char *, 2568 "got client label from request(1)", struct svc_req *, req); 2569 2570 if (!blequal(&l_admin_low->tsl_label, clabel)) { 2571 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) { 2572 resp->status = NFS3ERR_ACCES; 2573 goto err1; 2574 } 2575 } 2576 } 2577 2578 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2579 name = nfscmd_convname(ca, exi, args->object.name, 2580 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2581 2582 if (name == NULL) { 2583 resp->status = NFS3ERR_INVAL; 2584 goto err1; 2585 } 2586 2587 /* 2588 * Check for a conflict with a non-blocking mandatory share 2589 * reservation and V4 delegations 2590 */ 2591 error = VOP_LOOKUP(vp, name, &targvp, NULL, 0, 2592 NULL, cr, NULL, NULL, NULL); 2593 if (error != 0) 2594 goto err; 2595 2596 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) { 2597 resp->status = NFS3ERR_JUKEBOX; 2598 goto err1; 2599 } 2600 2601 if (!nbl_need_check(targvp)) { 2602 error = VOP_REMOVE(vp, name, cr, NULL, 0); 2603 } else { 2604 nbl_start_crit(targvp, RW_READER); 2605 if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) { 2606 error = EACCES; 2607 } else { 2608 error = VOP_REMOVE(vp, name, cr, NULL, 0); 2609 } 2610 nbl_end_crit(targvp); 2611 } 2612 VN_RELE(targvp); 2613 targvp = NULL; 2614 2615 #ifdef DEBUG 2616 if (rfs3_do_post_op_attr) { 2617 ava.va_mask = AT_ALL; 2618 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava; 2619 } else 2620 avap = NULL; 2621 #else 2622 ava.va_mask = AT_ALL; 2623 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava; 2624 #endif 2625 2626 /* 2627 * Force modified data and metadata out to stable storage. 2628 */ 2629 (void) VOP_FSYNC(vp, 0, cr, NULL); 2630 2631 if (error) 2632 goto err; 2633 2634 resp->status = NFS3_OK; 2635 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc); 2636 goto out; 2637 2638 err: 2639 if (curthread->t_flag & T_WOULDBLOCK) { 2640 curthread->t_flag &= ~T_WOULDBLOCK; 2641 resp->status = NFS3ERR_JUKEBOX; 2642 } else 2643 resp->status = puterrno3(error); 2644 err1: 2645 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc); 2646 out: 2647 DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req, 2648 cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp); 2649 2650 if (name != NULL && name != args->object.name) 2651 kmem_free(name, MAXPATHLEN + 1); 2652 2653 if (vp != NULL) 2654 VN_RELE(vp); 2655 } 2656 2657 void * 2658 rfs3_remove_getfh(REMOVE3args *args) 2659 { 2660 2661 return (&args->object.dir); 2662 } 2663 2664 void 2665 rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi, 2666 struct svc_req *req, cred_t *cr) 2667 { 2668 int error; 2669 vnode_t *vp; 2670 struct vattr *bvap; 2671 struct vattr bva; 2672 struct vattr *avap; 2673 struct vattr ava; 2674 struct sockaddr *ca; 2675 char *name = NULL; 2676 2677 bvap = NULL; 2678 avap = NULL; 2679 2680 vp = nfs3_fhtovp(&args->object.dir, exi); 2681 2682 DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req, 2683 cred_t *, cr, vnode_t *, vp, RMDIR3args *, args); 2684 2685 if (vp == NULL) { 2686 error = ESTALE; 2687 goto err; 2688 } 2689 2690 #ifdef DEBUG 2691 if (rfs3_do_pre_op_attr) { 2692 bva.va_mask = AT_ALL; 2693 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva; 2694 } else 2695 bvap = NULL; 2696 #else 2697 bva.va_mask = AT_ALL; 2698 bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva; 2699 #endif 2700 avap = bvap; 2701 2702 if (vp->v_type != VDIR) { 2703 resp->status = NFS3ERR_NOTDIR; 2704 goto err1; 2705 } 2706 2707 if (args->object.name == nfs3nametoolong) { 2708 resp->status = NFS3ERR_NAMETOOLONG; 2709 goto err1; 2710 } 2711 2712 if (args->object.name == NULL || *(args->object.name) == '\0') { 2713 resp->status = NFS3ERR_ACCES; 2714 goto err1; 2715 } 2716 2717 if (rdonly(exi, req)) { 2718 resp->status = NFS3ERR_ROFS; 2719 goto err1; 2720 } 2721 2722 if (is_system_labeled()) { 2723 bslabel_t *clabel = req->rq_label; 2724 2725 ASSERT(clabel != NULL); 2726 DTRACE_PROBE2(tx__rfs3__log__info__opremovedir__clabel, char *, 2727 "got client label from request(1)", struct svc_req *, req); 2728 2729 if (!blequal(&l_admin_low->tsl_label, clabel)) { 2730 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) { 2731 resp->status = NFS3ERR_ACCES; 2732 goto err1; 2733 } 2734 } 2735 } 2736 2737 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2738 name = nfscmd_convname(ca, exi, args->object.name, 2739 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2740 2741 if (name == NULL) { 2742 resp->status = NFS3ERR_INVAL; 2743 goto err1; 2744 } 2745 2746 error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0); 2747 2748 if (name != args->object.name) 2749 kmem_free(name, MAXPATHLEN + 1); 2750 2751 #ifdef DEBUG 2752 if (rfs3_do_post_op_attr) { 2753 ava.va_mask = AT_ALL; 2754 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava; 2755 } else 2756 avap = NULL; 2757 #else 2758 ava.va_mask = AT_ALL; 2759 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava; 2760 #endif 2761 2762 /* 2763 * Force modified data and metadata out to stable storage. 2764 */ 2765 (void) VOP_FSYNC(vp, 0, cr, NULL); 2766 2767 if (error) { 2768 /* 2769 * System V defines rmdir to return EEXIST, not ENOTEMPTY, 2770 * if the directory is not empty. A System V NFS server 2771 * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit 2772 * over the wire. 2773 */ 2774 if (error == EEXIST) 2775 error = ENOTEMPTY; 2776 goto err; 2777 } 2778 2779 resp->status = NFS3_OK; 2780 vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc); 2781 goto out; 2782 2783 err: 2784 if (curthread->t_flag & T_WOULDBLOCK) { 2785 curthread->t_flag &= ~T_WOULDBLOCK; 2786 resp->status = NFS3ERR_JUKEBOX; 2787 } else 2788 resp->status = puterrno3(error); 2789 err1: 2790 vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc); 2791 out: 2792 DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req, 2793 cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp); 2794 if (vp != NULL) 2795 VN_RELE(vp); 2796 2797 } 2798 2799 void * 2800 rfs3_rmdir_getfh(RMDIR3args *args) 2801 { 2802 2803 return (&args->object.dir); 2804 } 2805 2806 void 2807 rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi, 2808 struct svc_req *req, cred_t *cr) 2809 { 2810 int error = 0; 2811 vnode_t *fvp; 2812 vnode_t *tvp; 2813 vnode_t *targvp; 2814 struct vattr *fbvap; 2815 struct vattr fbva; 2816 struct vattr *favap; 2817 struct vattr fava; 2818 struct vattr *tbvap; 2819 struct vattr tbva; 2820 struct vattr *tavap; 2821 struct vattr tava; 2822 nfs_fh3 *fh3; 2823 struct exportinfo *to_exi; 2824 vnode_t *srcvp = NULL; 2825 bslabel_t *clabel; 2826 struct sockaddr *ca; 2827 char *name = NULL; 2828 char *toname = NULL; 2829 2830 fbvap = NULL; 2831 favap = NULL; 2832 tbvap = NULL; 2833 tavap = NULL; 2834 tvp = NULL; 2835 2836 fvp = nfs3_fhtovp(&args->from.dir, exi); 2837 2838 DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req, 2839 cred_t *, cr, vnode_t *, fvp, RENAME3args *, args); 2840 2841 if (fvp == NULL) { 2842 error = ESTALE; 2843 goto err; 2844 } 2845 2846 if (is_system_labeled()) { 2847 clabel = req->rq_label; 2848 ASSERT(clabel != NULL); 2849 DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *, 2850 "got client label from request(1)", struct svc_req *, req); 2851 2852 if (!blequal(&l_admin_low->tsl_label, clabel)) { 2853 if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK)) { 2854 resp->status = NFS3ERR_ACCES; 2855 goto err1; 2856 } 2857 } 2858 } 2859 2860 #ifdef DEBUG 2861 if (rfs3_do_pre_op_attr) { 2862 fbva.va_mask = AT_ALL; 2863 fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva; 2864 } else 2865 fbvap = NULL; 2866 #else 2867 fbva.va_mask = AT_ALL; 2868 fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva; 2869 #endif 2870 favap = fbvap; 2871 2872 fh3 = &args->to.dir; 2873 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3)); 2874 if (to_exi == NULL) { 2875 resp->status = NFS3ERR_ACCES; 2876 goto err1; 2877 } 2878 exi_rele(to_exi); 2879 2880 if (to_exi != exi) { 2881 resp->status = NFS3ERR_XDEV; 2882 goto err1; 2883 } 2884 2885 tvp = nfs3_fhtovp(&args->to.dir, exi); 2886 if (tvp == NULL) { 2887 error = ESTALE; 2888 goto err; 2889 } 2890 2891 #ifdef DEBUG 2892 if (rfs3_do_pre_op_attr) { 2893 tbva.va_mask = AT_ALL; 2894 tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva; 2895 } else 2896 tbvap = NULL; 2897 #else 2898 tbva.va_mask = AT_ALL; 2899 tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva; 2900 #endif 2901 tavap = tbvap; 2902 2903 if (fvp->v_type != VDIR || tvp->v_type != VDIR) { 2904 resp->status = NFS3ERR_NOTDIR; 2905 goto err1; 2906 } 2907 2908 if (args->from.name == nfs3nametoolong || 2909 args->to.name == nfs3nametoolong) { 2910 resp->status = NFS3ERR_NAMETOOLONG; 2911 goto err1; 2912 } 2913 if (args->from.name == NULL || *(args->from.name) == '\0' || 2914 args->to.name == NULL || *(args->to.name) == '\0') { 2915 resp->status = NFS3ERR_ACCES; 2916 goto err1; 2917 } 2918 2919 if (rdonly(exi, req)) { 2920 resp->status = NFS3ERR_ROFS; 2921 goto err1; 2922 } 2923 2924 if (is_system_labeled()) { 2925 if (!blequal(&l_admin_low->tsl_label, clabel)) { 2926 if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK)) { 2927 resp->status = NFS3ERR_ACCES; 2928 goto err1; 2929 } 2930 } 2931 } 2932 2933 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2934 name = nfscmd_convname(ca, exi, args->from.name, 2935 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2936 2937 if (name == NULL) { 2938 resp->status = NFS3ERR_INVAL; 2939 goto err1; 2940 } 2941 2942 toname = nfscmd_convname(ca, exi, args->to.name, 2943 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2944 2945 if (toname == NULL) { 2946 resp->status = NFS3ERR_INVAL; 2947 goto err1; 2948 } 2949 2950 /* 2951 * Check for a conflict with a non-blocking mandatory share 2952 * reservation or V4 delegations. 2953 */ 2954 error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0, 2955 NULL, cr, NULL, NULL, NULL); 2956 if (error != 0) 2957 goto err; 2958 2959 /* 2960 * If we rename a delegated file we should recall the 2961 * delegation, since future opens should fail or would 2962 * refer to a new file. 2963 */ 2964 if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) { 2965 resp->status = NFS3ERR_JUKEBOX; 2966 goto err1; 2967 } 2968 2969 /* 2970 * Check for renaming over a delegated file. Check rfs4_deleg_policy 2971 * first to avoid VOP_LOOKUP if possible. 2972 */ 2973 if (rfs4_deleg_policy != SRV_NEVER_DELEGATE && 2974 VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr, 2975 NULL, NULL, NULL) == 0) { 2976 2977 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) { 2978 VN_RELE(targvp); 2979 resp->status = NFS3ERR_JUKEBOX; 2980 goto err1; 2981 } 2982 VN_RELE(targvp); 2983 } 2984 2985 if (!nbl_need_check(srcvp)) { 2986 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0); 2987 } else { 2988 nbl_start_crit(srcvp, RW_READER); 2989 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) 2990 error = EACCES; 2991 else 2992 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0); 2993 nbl_end_crit(srcvp); 2994 } 2995 if (error == 0) 2996 vn_renamepath(tvp, srcvp, args->to.name, 2997 strlen(args->to.name)); 2998 VN_RELE(srcvp); 2999 srcvp = NULL; 3000 3001 #ifdef DEBUG 3002 if (rfs3_do_post_op_attr) { 3003 fava.va_mask = AT_ALL; 3004 favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava; 3005 tava.va_mask = AT_ALL; 3006 tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava; 3007 } else { 3008 favap = NULL; 3009 tavap = NULL; 3010 } 3011 #else 3012 fava.va_mask = AT_ALL; 3013 favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava; 3014 tava.va_mask = AT_ALL; 3015 tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava; 3016 #endif 3017 3018 /* 3019 * Force modified data and metadata out to stable storage. 3020 */ 3021 (void) VOP_FSYNC(fvp, 0, cr, NULL); 3022 (void) VOP_FSYNC(tvp, 0, cr, NULL); 3023 3024 if (error) 3025 goto err; 3026 3027 resp->status = NFS3_OK; 3028 vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc); 3029 vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc); 3030 goto out; 3031 3032 err: 3033 if (curthread->t_flag & T_WOULDBLOCK) { 3034 curthread->t_flag &= ~T_WOULDBLOCK; 3035 resp->status = NFS3ERR_JUKEBOX; 3036 } else { 3037 resp->status = puterrno3(error); 3038 } 3039 err1: 3040 vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc); 3041 vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc); 3042 3043 out: 3044 if (name != NULL && name != args->from.name) 3045 kmem_free(name, MAXPATHLEN + 1); 3046 if (toname != NULL && toname != args->to.name) 3047 kmem_free(toname, MAXPATHLEN + 1); 3048 3049 DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req, 3050 cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp); 3051 if (fvp != NULL) 3052 VN_RELE(fvp); 3053 if (tvp != NULL) 3054 VN_RELE(tvp); 3055 } 3056 3057 void * 3058 rfs3_rename_getfh(RENAME3args *args) 3059 { 3060 3061 return (&args->from.dir); 3062 } 3063 3064 void 3065 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi, 3066 struct svc_req *req, cred_t *cr) 3067 { 3068 int error; 3069 vnode_t *vp; 3070 vnode_t *dvp; 3071 struct vattr *vap; 3072 struct vattr va; 3073 struct vattr *bvap; 3074 struct vattr bva; 3075 struct vattr *avap; 3076 struct vattr ava; 3077 nfs_fh3 *fh3; 3078 struct exportinfo *to_exi; 3079 bslabel_t *clabel; 3080 struct sockaddr *ca; 3081 char *name = NULL; 3082 3083 vap = NULL; 3084 bvap = NULL; 3085 avap = NULL; 3086 dvp = NULL; 3087 3088 vp = nfs3_fhtovp(&args->file, exi); 3089 3090 DTRACE_NFSV3_4(op__link__start, struct svc_req *, req, 3091 cred_t *, cr, vnode_t *, vp, LINK3args *, args); 3092 3093 if (vp == NULL) { 3094 error = ESTALE; 3095 goto out; 3096 } 3097 3098 #ifdef DEBUG 3099 if (rfs3_do_pre_op_attr) { 3100 va.va_mask = AT_ALL; 3101 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 3102 } else 3103 vap = NULL; 3104 #else 3105 va.va_mask = AT_ALL; 3106 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 3107 #endif 3108 3109 fh3 = &args->link.dir; 3110 to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3)); 3111 if (to_exi == NULL) { 3112 resp->status = NFS3ERR_ACCES; 3113 goto out1; 3114 } 3115 exi_rele(to_exi); 3116 3117 if (to_exi != exi) { 3118 resp->status = NFS3ERR_XDEV; 3119 goto out1; 3120 } 3121 3122 if (is_system_labeled()) { 3123 clabel = req->rq_label; 3124 3125 ASSERT(clabel != NULL); 3126 DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *, 3127 "got client label from request(1)", struct svc_req *, req); 3128 3129 if (!blequal(&l_admin_low->tsl_label, clabel)) { 3130 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { 3131 resp->status = NFS3ERR_ACCES; 3132 goto out1; 3133 } 3134 } 3135 } 3136 3137 dvp = nfs3_fhtovp(&args->link.dir, exi); 3138 if (dvp == NULL) { 3139 error = ESTALE; 3140 goto out; 3141 } 3142 3143 #ifdef DEBUG 3144 if (rfs3_do_pre_op_attr) { 3145 bva.va_mask = AT_ALL; 3146 bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva; 3147 } else 3148 bvap = NULL; 3149 #else 3150 bva.va_mask = AT_ALL; 3151 bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva; 3152 #endif 3153 3154 if (dvp->v_type != VDIR) { 3155 resp->status = NFS3ERR_NOTDIR; 3156 goto out1; 3157 } 3158 3159 if (args->link.name == nfs3nametoolong) { 3160 resp->status = NFS3ERR_NAMETOOLONG; 3161 goto out1; 3162 } 3163 3164 if (args->link.name == NULL || *(args->link.name) == '\0') { 3165 resp->status = NFS3ERR_ACCES; 3166 goto out1; 3167 } 3168 3169 if (rdonly(exi, req)) { 3170 resp->status = NFS3ERR_ROFS; 3171 goto out1; 3172 } 3173 3174 if (is_system_labeled()) { 3175 DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *, 3176 "got client label from request(1)", struct svc_req *, req); 3177 3178 if (!blequal(&l_admin_low->tsl_label, clabel)) { 3179 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) { 3180 resp->status = NFS3ERR_ACCES; 3181 goto out1; 3182 } 3183 } 3184 } 3185 3186 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 3187 name = nfscmd_convname(ca, exi, args->link.name, 3188 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 3189 3190 if (name == NULL) { 3191 resp->status = NFS3ERR_SERVERFAULT; 3192 goto out1; 3193 } 3194 3195 error = VOP_LINK(dvp, vp, name, cr, NULL, 0); 3196 3197 #ifdef DEBUG 3198 if (rfs3_do_post_op_attr) { 3199 va.va_mask = AT_ALL; 3200 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 3201 ava.va_mask = AT_ALL; 3202 avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava; 3203 } else { 3204 vap = NULL; 3205 avap = NULL; 3206 } 3207 #else 3208 va.va_mask = AT_ALL; 3209 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 3210 ava.va_mask = AT_ALL; 3211 avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava; 3212 #endif 3213 3214 /* 3215 * Force modified data and metadata out to stable storage. 3216 */ 3217 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 3218 (void) VOP_FSYNC(dvp, 0, cr, NULL); 3219 3220 if (error) 3221 goto out; 3222 3223 VN_RELE(dvp); 3224 3225 resp->status = NFS3_OK; 3226 vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 3227 vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc); 3228 3229 DTRACE_NFSV3_4(op__link__done, struct svc_req *, req, 3230 cred_t *, cr, vnode_t *, vp, LINK3res *, resp); 3231 3232 VN_RELE(vp); 3233 3234 return; 3235 3236 out: 3237 if (curthread->t_flag & T_WOULDBLOCK) { 3238 curthread->t_flag &= ~T_WOULDBLOCK; 3239 resp->status = NFS3ERR_JUKEBOX; 3240 } else 3241 resp->status = puterrno3(error); 3242 out1: 3243 if (name != NULL && name != args->link.name) 3244 kmem_free(name, MAXPATHLEN + 1); 3245 3246 DTRACE_NFSV3_4(op__link__done, struct svc_req *, req, 3247 cred_t *, cr, vnode_t *, vp, LINK3res *, resp); 3248 3249 if (vp != NULL) 3250 VN_RELE(vp); 3251 if (dvp != NULL) 3252 VN_RELE(dvp); 3253 vattr_to_post_op_attr(vap, &resp->resfail.file_attributes); 3254 vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc); 3255 } 3256 3257 void * 3258 rfs3_link_getfh(LINK3args *args) 3259 { 3260 3261 return (&args->file); 3262 } 3263 3264 /* 3265 * This macro defines the size of a response which contains attribute 3266 * information and one directory entry (whose length is specified by 3267 * the macro parameter). If the incoming request is larger than this, 3268 * then we are guaranteed to be able to return at one directory entry 3269 * if one exists. Therefore, we do not need to check for 3270 * NFS3ERR_TOOSMALL if the requested size is larger then this. If it 3271 * is not, then we need to check to make sure that this error does not 3272 * need to be returned. 3273 * 3274 * NFS3_READDIR_MIN_COUNT is comprised of following : 3275 * 3276 * status - 1 * BYTES_PER_XDR_UNIT 3277 * attr. flag - 1 * BYTES_PER_XDR_UNIT 3278 * cookie verifier - 2 * BYTES_PER_XDR_UNIT 3279 * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT 3280 * boolean - 1 * BYTES_PER_XDR_UNIT 3281 * file id - 2 * BYTES_PER_XDR_UNIT 3282 * directory name length - 1 * BYTES_PER_XDR_UNIT 3283 * cookie - 2 * BYTES_PER_XDR_UNIT 3284 * end of list - 1 * BYTES_PER_XDR_UNIT 3285 * end of file - 1 * BYTES_PER_XDR_UNIT 3286 * Name length of directory to the nearest byte 3287 */ 3288 3289 #define NFS3_READDIR_MIN_COUNT(length) \ 3290 ((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \ 3291 BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT)) 3292 3293 /* ARGSUSED */ 3294 void 3295 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi, 3296 struct svc_req *req, cred_t *cr) 3297 { 3298 int error; 3299 vnode_t *vp; 3300 struct vattr *vap; 3301 struct vattr va; 3302 struct iovec iov; 3303 struct uio uio; 3304 char *data; 3305 int iseof; 3306 int bufsize; 3307 int namlen; 3308 uint_t count; 3309 struct sockaddr *ca; 3310 3311 vap = NULL; 3312 3313 vp = nfs3_fhtovp(&args->dir, exi); 3314 3315 DTRACE_NFSV3_4(op__readdir__start, struct svc_req *, req, 3316 cred_t *, cr, vnode_t *, vp, READDIR3args *, args); 3317 3318 if (vp == NULL) { 3319 error = ESTALE; 3320 goto out; 3321 } 3322 3323 if (is_system_labeled()) { 3324 bslabel_t *clabel = req->rq_label; 3325 3326 ASSERT(clabel != NULL); 3327 DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *, 3328 "got client label from request(1)", struct svc_req *, req); 3329 3330 if (!blequal(&l_admin_low->tsl_label, clabel)) { 3331 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { 3332 resp->status = NFS3ERR_ACCES; 3333 goto out1; 3334 } 3335 } 3336 } 3337 3338 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 3339 3340 #ifdef DEBUG 3341 if (rfs3_do_pre_op_attr) { 3342 va.va_mask = AT_ALL; 3343 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 3344 } else 3345 vap = NULL; 3346 #else 3347 va.va_mask = AT_ALL; 3348 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 3349 #endif 3350 3351 if (vp->v_type != VDIR) { 3352 resp->status = NFS3ERR_NOTDIR; 3353 goto out1; 3354 } 3355 3356 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL); 3357 if (error) 3358 goto out; 3359 3360 /* 3361 * Now don't allow arbitrary count to alloc; 3362 * allow the maximum not to exceed rfs3_tsize() 3363 */ 3364 if (args->count > rfs3_tsize(req)) 3365 args->count = rfs3_tsize(req); 3366 3367 /* 3368 * Make sure that there is room to read at least one entry 3369 * if any are available. 3370 */ 3371 if (args->count < DIRENT64_RECLEN(MAXNAMELEN)) 3372 count = DIRENT64_RECLEN(MAXNAMELEN); 3373 else 3374 count = args->count; 3375 3376 data = kmem_alloc(count, KM_SLEEP); 3377 3378 iov.iov_base = data; 3379 iov.iov_len = count; 3380 uio.uio_iov = &iov; 3381 uio.uio_iovcnt = 1; 3382 uio.uio_segflg = UIO_SYSSPACE; 3383 uio.uio_extflg = UIO_COPY_CACHED; 3384 uio.uio_loffset = (offset_t)args->cookie; 3385 uio.uio_resid = count; 3386 3387 error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0); 3388 3389 #ifdef DEBUG 3390 if (rfs3_do_post_op_attr) { 3391 va.va_mask = AT_ALL; 3392 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 3393 } else 3394 vap = NULL; 3395 #else 3396 va.va_mask = AT_ALL; 3397 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 3398 #endif 3399 3400 if (error) { 3401 kmem_free(data, count); 3402 goto out; 3403 } 3404 3405 /* 3406 * If the count was not large enough to be able to guarantee 3407 * to be able to return at least one entry, then need to 3408 * check to see if NFS3ERR_TOOSMALL should be returned. 3409 */ 3410 if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) { 3411 /* 3412 * bufsize is used to keep track of the size of the response. 3413 * It is primed with: 3414 * 1 for the status + 3415 * 1 for the dir_attributes.attributes boolean + 3416 * 2 for the cookie verifier 3417 * all times BYTES_PER_XDR_UNIT to convert from XDR units 3418 * to bytes. If there are directory attributes to be 3419 * returned, then: 3420 * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3 3421 * time BYTES_PER_XDR_UNIT is added to account for them. 3422 */ 3423 bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT; 3424 if (vap != NULL) 3425 bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT; 3426 /* 3427 * An entry is composed of: 3428 * 1 for the true/false list indicator + 3429 * 2 for the fileid + 3430 * 1 for the length of the name + 3431 * 2 for the cookie + 3432 * all times BYTES_PER_XDR_UNIT to convert from 3433 * XDR units to bytes, plus the length of the name 3434 * rounded up to the nearest BYTES_PER_XDR_UNIT. 3435 */ 3436 if (count != uio.uio_resid) { 3437 namlen = strlen(((struct dirent64 *)data)->d_name); 3438 bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT + 3439 roundup(namlen, BYTES_PER_XDR_UNIT); 3440 } 3441 /* 3442 * We need to check to see if the number of bytes left 3443 * to go into the buffer will actually fit into the 3444 * buffer. This is calculated as the size of this 3445 * entry plus: 3446 * 1 for the true/false list indicator + 3447 * 1 for the eof indicator 3448 * times BYTES_PER_XDR_UNIT to convert from from 3449 * XDR units to bytes. 3450 */ 3451 bufsize += (1 + 1) * BYTES_PER_XDR_UNIT; 3452 if (bufsize > args->count) { 3453 kmem_free(data, count); 3454 resp->status = NFS3ERR_TOOSMALL; 3455 goto out1; 3456 } 3457 } 3458 3459 /* 3460 * Have a valid readir buffer for the native character 3461 * set. Need to check if a conversion is necessary and 3462 * potentially rewrite the whole buffer. Note that if the 3463 * conversion expands names enough, the structure may not 3464 * fit. In this case, we need to drop entries until if fits 3465 * and patch the counts in order that the next readdir will 3466 * get the correct entries. 3467 */ 3468 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 3469 data = nfscmd_convdirent(ca, exi, data, count, &resp->status); 3470 3471 3472 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 3473 3474 #if 0 /* notyet */ 3475 /* 3476 * Don't do this. It causes local disk writes when just 3477 * reading the file and the overhead is deemed larger 3478 * than the benefit. 3479 */ 3480 /* 3481 * Force modified metadata out to stable storage. 3482 */ 3483 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 3484 #endif 3485 3486 resp->status = NFS3_OK; 3487 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes); 3488 resp->resok.cookieverf = 0; 3489 resp->resok.reply.entries = (entry3 *)data; 3490 resp->resok.reply.eof = iseof; 3491 resp->resok.size = count - uio.uio_resid; 3492 resp->resok.count = args->count; 3493 resp->resok.freecount = count; 3494 3495 DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req, 3496 cred_t *, cr, vnode_t *, vp, READDIR3res *, resp); 3497 3498 VN_RELE(vp); 3499 3500 return; 3501 3502 out: 3503 if (curthread->t_flag & T_WOULDBLOCK) { 3504 curthread->t_flag &= ~T_WOULDBLOCK; 3505 resp->status = NFS3ERR_JUKEBOX; 3506 } else 3507 resp->status = puterrno3(error); 3508 out1: 3509 DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req, 3510 cred_t *, cr, vnode_t *, vp, READDIR3res *, resp); 3511 3512 if (vp != NULL) { 3513 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 3514 VN_RELE(vp); 3515 } 3516 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes); 3517 } 3518 3519 void * 3520 rfs3_readdir_getfh(READDIR3args *args) 3521 { 3522 3523 return (&args->dir); 3524 } 3525 3526 void 3527 rfs3_readdir_free(READDIR3res *resp) 3528 { 3529 3530 if (resp->status == NFS3_OK) 3531 kmem_free(resp->resok.reply.entries, resp->resok.freecount); 3532 } 3533 3534 #ifdef nextdp 3535 #undef nextdp 3536 #endif 3537 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) 3538 3539 /* 3540 * This macro computes the size of a response which contains 3541 * one directory entry including the attributes as well as file handle. 3542 * If the incoming request is larger than this, then we are guaranteed to be 3543 * able to return at least one more directory entry if one exists. 3544 * 3545 * NFS3_READDIRPLUS_ENTRY is made up of the following: 3546 * 3547 * boolean - 1 * BYTES_PER_XDR_UNIT 3548 * file id - 2 * BYTES_PER_XDR_UNIT 3549 * directory name length - 1 * BYTES_PER_XDR_UNIT 3550 * cookie - 2 * BYTES_PER_XDR_UNIT 3551 * attribute flag - 1 * BYTES_PER_XDR_UNIT 3552 * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT 3553 * status byte for file handle - 1 * BYTES_PER_XDR_UNIT 3554 * length of a file handle - 1 * BYTES_PER_XDR_UNIT 3555 * Maximum length of a file handle (NFS3_MAXFHSIZE) 3556 * name length of the entry to the nearest bytes 3557 */ 3558 #define NFS3_READDIRPLUS_ENTRY(namelen) \ 3559 ((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \ 3560 BYTES_PER_XDR_UNIT + \ 3561 NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT)) 3562 3563 static int rfs3_readdir_unit = MAXBSIZE; 3564 3565 /* ARGSUSED */ 3566 void 3567 rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp, 3568 struct exportinfo *exi, struct svc_req *req, cred_t *cr) 3569 { 3570 int error; 3571 vnode_t *vp; 3572 struct vattr *vap; 3573 struct vattr va; 3574 struct iovec iov; 3575 struct uio uio; 3576 char *data; 3577 int iseof; 3578 struct dirent64 *dp; 3579 vnode_t *nvp; 3580 struct vattr *nvap; 3581 struct vattr nva; 3582 entryplus3_info *infop = NULL; 3583 int size = 0; 3584 int nents = 0; 3585 int bufsize = 0; 3586 int entrysize = 0; 3587 int tofit = 0; 3588 int rd_unit = rfs3_readdir_unit; 3589 int prev_len; 3590 int space_left; 3591 int i; 3592 uint_t *namlen = NULL; 3593 char *ndata = NULL; 3594 struct sockaddr *ca; 3595 size_t ret; 3596 3597 vap = NULL; 3598 3599 vp = nfs3_fhtovp(&args->dir, exi); 3600 3601 DTRACE_NFSV3_4(op__readdirplus__start, struct svc_req *, req, 3602 cred_t *, cr, vnode_t *, vp, READDIRPLUS3args *, args); 3603 3604 if (vp == NULL) { 3605 error = ESTALE; 3606 goto out; 3607 } 3608 3609 if (is_system_labeled()) { 3610 bslabel_t *clabel = req->rq_label; 3611 3612 ASSERT(clabel != NULL); 3613 DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel, 3614 char *, "got client label from request(1)", 3615 struct svc_req *, req); 3616 3617 if (!blequal(&l_admin_low->tsl_label, clabel)) { 3618 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { 3619 resp->status = NFS3ERR_ACCES; 3620 goto out1; 3621 } 3622 } 3623 } 3624 3625 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 3626 3627 #ifdef DEBUG 3628 if (rfs3_do_pre_op_attr) { 3629 va.va_mask = AT_ALL; 3630 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 3631 } else 3632 vap = NULL; 3633 #else 3634 va.va_mask = AT_ALL; 3635 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 3636 #endif 3637 3638 if (vp->v_type != VDIR) { 3639 error = ENOTDIR; 3640 goto out; 3641 } 3642 3643 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL); 3644 if (error) 3645 goto out; 3646 3647 /* 3648 * Don't allow arbitrary counts for allocation 3649 */ 3650 if (args->maxcount > rfs3_tsize(req)) 3651 args->maxcount = rfs3_tsize(req); 3652 3653 /* 3654 * Make sure that there is room to read at least one entry 3655 * if any are available 3656 */ 3657 args->dircount = MIN(args->dircount, args->maxcount); 3658 3659 if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN)) 3660 args->dircount = DIRENT64_RECLEN(MAXNAMELEN); 3661 3662 /* 3663 * This allocation relies on a minimum directory entry 3664 * being roughly 24 bytes. Therefore, the namlen array 3665 * will have enough space based on the maximum number of 3666 * entries to read. 3667 */ 3668 namlen = kmem_alloc(args->dircount, KM_SLEEP); 3669 3670 space_left = args->dircount; 3671 data = kmem_alloc(args->dircount, KM_SLEEP); 3672 dp = (struct dirent64 *)data; 3673 uio.uio_iov = &iov; 3674 uio.uio_iovcnt = 1; 3675 uio.uio_segflg = UIO_SYSSPACE; 3676 uio.uio_extflg = UIO_COPY_CACHED; 3677 uio.uio_loffset = (offset_t)args->cookie; 3678 3679 /* 3680 * bufsize is used to keep track of the size of the response as we 3681 * get post op attributes and filehandles for each entry. This is 3682 * an optimization as the server may have read more entries than will 3683 * fit in the buffer specified by maxcount. We stop calculating 3684 * post op attributes and filehandles once we have exceeded maxcount. 3685 * This will minimize the effect of truncation. 3686 * 3687 * It is primed with: 3688 * 1 for the status + 3689 * 1 for the dir_attributes.attributes boolean + 3690 * 2 for the cookie verifier 3691 * all times BYTES_PER_XDR_UNIT to convert from XDR units 3692 * to bytes. If there are directory attributes to be 3693 * returned, then: 3694 * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3 3695 * time BYTES_PER_XDR_UNIT is added to account for them. 3696 */ 3697 bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT; 3698 if (vap != NULL) 3699 bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT; 3700 3701 getmoredents: 3702 /* 3703 * Here we make a check so that our read unit is not larger than 3704 * the space left in the buffer. 3705 */ 3706 rd_unit = MIN(rd_unit, space_left); 3707 iov.iov_base = (char *)dp; 3708 iov.iov_len = rd_unit; 3709 uio.uio_resid = rd_unit; 3710 prev_len = rd_unit; 3711 3712 error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0); 3713 3714 if (error) { 3715 kmem_free(data, args->dircount); 3716 goto out; 3717 } 3718 3719 if (uio.uio_resid == prev_len && !iseof) { 3720 if (nents == 0) { 3721 kmem_free(data, args->dircount); 3722 resp->status = NFS3ERR_TOOSMALL; 3723 goto out1; 3724 } 3725 3726 /* 3727 * We could not get any more entries, so get the attributes 3728 * and filehandle for the entries already obtained. 3729 */ 3730 goto good; 3731 } 3732 3733 /* 3734 * We estimate the size of the response by assuming the 3735 * entry exists and attributes and filehandle are also valid 3736 */ 3737 for (size = prev_len - uio.uio_resid; 3738 size > 0; 3739 size -= dp->d_reclen, dp = nextdp(dp)) { 3740 3741 if (dp->d_ino == 0) { 3742 nents++; 3743 continue; 3744 } 3745 3746 namlen[nents] = strlen(dp->d_name); 3747 entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]); 3748 3749 /* 3750 * We need to check to see if the number of bytes left 3751 * to go into the buffer will actually fit into the 3752 * buffer. This is calculated as the size of this 3753 * entry plus: 3754 * 1 for the true/false list indicator + 3755 * 1 for the eof indicator 3756 * times BYTES_PER_XDR_UNIT to convert from XDR units 3757 * to bytes. 3758 * 3759 * Also check the dircount limit against the first entry read 3760 * 3761 */ 3762 tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT; 3763 if (bufsize + tofit > args->maxcount) { 3764 /* 3765 * We make a check here to see if this was the 3766 * first entry being measured. If so, then maxcount 3767 * was too small to begin with and so we need to 3768 * return with NFS3ERR_TOOSMALL. 3769 */ 3770 if (nents == 0) { 3771 kmem_free(data, args->dircount); 3772 resp->status = NFS3ERR_TOOSMALL; 3773 goto out1; 3774 } 3775 iseof = FALSE; 3776 goto good; 3777 } 3778 bufsize += entrysize; 3779 nents++; 3780 } 3781 3782 /* 3783 * If there is enough room to fit at least 1 more entry including 3784 * post op attributes and filehandle in the buffer AND that we haven't 3785 * exceeded dircount then go back and get some more. 3786 */ 3787 if (!iseof && 3788 (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) { 3789 space_left -= (prev_len - uio.uio_resid); 3790 if (space_left >= DIRENT64_RECLEN(MAXNAMELEN)) 3791 goto getmoredents; 3792 3793 /* else, fall through */ 3794 } 3795 3796 good: 3797 3798 #ifdef DEBUG 3799 if (rfs3_do_post_op_attr) { 3800 va.va_mask = AT_ALL; 3801 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 3802 } else 3803 vap = NULL; 3804 #else 3805 va.va_mask = AT_ALL; 3806 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 3807 #endif 3808 3809 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 3810 3811 infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP); 3812 resp->resok.infop = infop; 3813 3814 dp = (struct dirent64 *)data; 3815 for (i = 0; i < nents; i++) { 3816 3817 if (dp->d_ino == 0) { 3818 infop[i].attr.attributes = FALSE; 3819 infop[i].fh.handle_follows = FALSE; 3820 dp = nextdp(dp); 3821 continue; 3822 } 3823 3824 infop[i].namelen = namlen[i]; 3825 3826 error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr, 3827 NULL, NULL, NULL); 3828 if (error) { 3829 infop[i].attr.attributes = FALSE; 3830 infop[i].fh.handle_follows = FALSE; 3831 dp = nextdp(dp); 3832 continue; 3833 } 3834 3835 #ifdef DEBUG 3836 if (rfs3_do_post_op_attr) { 3837 nva.va_mask = AT_ALL; 3838 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? 3839 NULL : &nva; 3840 } else 3841 nvap = NULL; 3842 #else 3843 nva.va_mask = AT_ALL; 3844 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva; 3845 #endif 3846 vattr_to_post_op_attr(nvap, &infop[i].attr); 3847 3848 #ifdef DEBUG 3849 if (!rfs3_do_post_op_fh3) 3850 infop[i].fh.handle_follows = FALSE; 3851 else { 3852 #endif 3853 error = makefh3(&infop[i].fh.handle, nvp, exi); 3854 if (!error) 3855 infop[i].fh.handle_follows = TRUE; 3856 else 3857 infop[i].fh.handle_follows = FALSE; 3858 #ifdef DEBUG 3859 } 3860 #endif 3861 3862 VN_RELE(nvp); 3863 dp = nextdp(dp); 3864 } 3865 3866 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 3867 ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata); 3868 if (ndata == NULL) 3869 ndata = data; 3870 3871 if (ret > 0) { 3872 /* 3873 * We had to drop one or more entries in order to fit 3874 * during the character conversion. We need to patch 3875 * up the size and eof info. 3876 */ 3877 if (iseof) 3878 iseof = FALSE; 3879 3880 ret = nfscmd_dropped_entrysize((struct dirent64 *)data, 3881 nents, ret); 3882 } 3883 3884 3885 #if 0 /* notyet */ 3886 /* 3887 * Don't do this. It causes local disk writes when just 3888 * reading the file and the overhead is deemed larger 3889 * than the benefit. 3890 */ 3891 /* 3892 * Force modified metadata out to stable storage. 3893 */ 3894 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 3895 #endif 3896 3897 kmem_free(namlen, args->dircount); 3898 3899 resp->status = NFS3_OK; 3900 vattr_to_post_op_attr(vap, &resp->resok.dir_attributes); 3901 resp->resok.cookieverf = 0; 3902 resp->resok.reply.entries = (entryplus3 *)ndata; 3903 resp->resok.reply.eof = iseof; 3904 resp->resok.size = nents; 3905 resp->resok.count = args->dircount - ret; 3906 resp->resok.maxcount = args->maxcount; 3907 3908 DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req, 3909 cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp); 3910 if (ndata != data) 3911 kmem_free(data, args->dircount); 3912 3913 3914 VN_RELE(vp); 3915 3916 return; 3917 3918 out: 3919 if (curthread->t_flag & T_WOULDBLOCK) { 3920 curthread->t_flag &= ~T_WOULDBLOCK; 3921 resp->status = NFS3ERR_JUKEBOX; 3922 } else { 3923 resp->status = puterrno3(error); 3924 } 3925 out1: 3926 DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req, 3927 cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp); 3928 3929 if (vp != NULL) { 3930 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 3931 VN_RELE(vp); 3932 } 3933 3934 if (namlen != NULL) 3935 kmem_free(namlen, args->dircount); 3936 3937 vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes); 3938 } 3939 3940 void * 3941 rfs3_readdirplus_getfh(READDIRPLUS3args *args) 3942 { 3943 3944 return (&args->dir); 3945 } 3946 3947 void 3948 rfs3_readdirplus_free(READDIRPLUS3res *resp) 3949 { 3950 3951 if (resp->status == NFS3_OK) { 3952 kmem_free(resp->resok.reply.entries, resp->resok.count); 3953 kmem_free(resp->resok.infop, 3954 resp->resok.size * sizeof (struct entryplus3_info)); 3955 } 3956 } 3957 3958 /* ARGSUSED */ 3959 void 3960 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi, 3961 struct svc_req *req, cred_t *cr) 3962 { 3963 int error; 3964 vnode_t *vp; 3965 struct vattr *vap; 3966 struct vattr va; 3967 struct statvfs64 sb; 3968 3969 vap = NULL; 3970 3971 vp = nfs3_fhtovp(&args->fsroot, exi); 3972 3973 DTRACE_NFSV3_4(op__fsstat__start, struct svc_req *, req, 3974 cred_t *, cr, vnode_t *, vp, FSSTAT3args *, args); 3975 3976 if (vp == NULL) { 3977 error = ESTALE; 3978 goto out; 3979 } 3980 3981 if (is_system_labeled()) { 3982 bslabel_t *clabel = req->rq_label; 3983 3984 ASSERT(clabel != NULL); 3985 DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *, 3986 "got client label from request(1)", struct svc_req *, req); 3987 3988 if (!blequal(&l_admin_low->tsl_label, clabel)) { 3989 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { 3990 resp->status = NFS3ERR_ACCES; 3991 goto out1; 3992 } 3993 } 3994 } 3995 3996 error = VFS_STATVFS(vp->v_vfsp, &sb); 3997 3998 #ifdef DEBUG 3999 if (rfs3_do_post_op_attr) { 4000 va.va_mask = AT_ALL; 4001 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 4002 } else 4003 vap = NULL; 4004 #else 4005 va.va_mask = AT_ALL; 4006 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 4007 #endif 4008 4009 if (error) 4010 goto out; 4011 4012 resp->status = NFS3_OK; 4013 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 4014 if (sb.f_blocks != (fsblkcnt64_t)-1) 4015 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks; 4016 else 4017 resp->resok.tbytes = (size3)sb.f_blocks; 4018 if (sb.f_bfree != (fsblkcnt64_t)-1) 4019 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree; 4020 else 4021 resp->resok.fbytes = (size3)sb.f_bfree; 4022 if (sb.f_bavail != (fsblkcnt64_t)-1) 4023 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail; 4024 else 4025 resp->resok.abytes = (size3)sb.f_bavail; 4026 resp->resok.tfiles = (size3)sb.f_files; 4027 resp->resok.ffiles = (size3)sb.f_ffree; 4028 resp->resok.afiles = (size3)sb.f_favail; 4029 resp->resok.invarsec = 0; 4030 4031 DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req, 4032 cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp); 4033 VN_RELE(vp); 4034 4035 return; 4036 4037 out: 4038 if (curthread->t_flag & T_WOULDBLOCK) { 4039 curthread->t_flag &= ~T_WOULDBLOCK; 4040 resp->status = NFS3ERR_JUKEBOX; 4041 } else 4042 resp->status = puterrno3(error); 4043 out1: 4044 DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req, 4045 cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp); 4046 4047 if (vp != NULL) 4048 VN_RELE(vp); 4049 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); 4050 } 4051 4052 void * 4053 rfs3_fsstat_getfh(FSSTAT3args *args) 4054 { 4055 4056 return (&args->fsroot); 4057 } 4058 4059 /* ARGSUSED */ 4060 void 4061 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi, 4062 struct svc_req *req, cred_t *cr) 4063 { 4064 vnode_t *vp; 4065 struct vattr *vap; 4066 struct vattr va; 4067 uint32_t xfer_size; 4068 ulong_t l = 0; 4069 int error; 4070 4071 vp = nfs3_fhtovp(&args->fsroot, exi); 4072 4073 DTRACE_NFSV3_4(op__fsinfo__start, struct svc_req *, req, 4074 cred_t *, cr, vnode_t *, vp, FSINFO3args *, args); 4075 4076 if (vp == NULL) { 4077 if (curthread->t_flag & T_WOULDBLOCK) { 4078 curthread->t_flag &= ~T_WOULDBLOCK; 4079 resp->status = NFS3ERR_JUKEBOX; 4080 } else 4081 resp->status = NFS3ERR_STALE; 4082 vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes); 4083 goto out; 4084 } 4085 4086 if (is_system_labeled()) { 4087 bslabel_t *clabel = req->rq_label; 4088 4089 ASSERT(clabel != NULL); 4090 DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *, 4091 "got client label from request(1)", struct svc_req *, req); 4092 4093 if (!blequal(&l_admin_low->tsl_label, clabel)) { 4094 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { 4095 resp->status = NFS3ERR_STALE; 4096 vattr_to_post_op_attr(NULL, 4097 &resp->resfail.obj_attributes); 4098 goto out; 4099 } 4100 } 4101 } 4102 4103 #ifdef DEBUG 4104 if (rfs3_do_post_op_attr) { 4105 va.va_mask = AT_ALL; 4106 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 4107 } else 4108 vap = NULL; 4109 #else 4110 va.va_mask = AT_ALL; 4111 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 4112 #endif 4113 4114 resp->status = NFS3_OK; 4115 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 4116 xfer_size = rfs3_tsize(req); 4117 resp->resok.rtmax = xfer_size; 4118 resp->resok.rtpref = xfer_size; 4119 resp->resok.rtmult = DEV_BSIZE; 4120 resp->resok.wtmax = xfer_size; 4121 resp->resok.wtpref = xfer_size; 4122 resp->resok.wtmult = DEV_BSIZE; 4123 resp->resok.dtpref = MAXBSIZE; 4124 4125 /* 4126 * Large file spec: want maxfilesize based on limit of 4127 * underlying filesystem. We can guess 2^31-1 if need be. 4128 */ 4129 error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL); 4130 4131 if (!error && l != 0 && l <= 64) 4132 resp->resok.maxfilesize = (1LL << (l-1)) - 1; 4133 else 4134 resp->resok.maxfilesize = MAXOFF32_T; 4135 4136 resp->resok.time_delta.seconds = 0; 4137 resp->resok.time_delta.nseconds = 1000; 4138 resp->resok.properties = FSF3_LINK | FSF3_SYMLINK | 4139 FSF3_HOMOGENEOUS | FSF3_CANSETTIME; 4140 4141 DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req, 4142 cred_t *, cr, vnode_t *, vp, FSINFO3res *, resp); 4143 4144 VN_RELE(vp); 4145 4146 return; 4147 4148 out: 4149 DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req, 4150 cred_t *, cr, vnode_t *, NULL, FSINFO3res *, resp); 4151 if (vp != NULL) 4152 VN_RELE(vp); 4153 } 4154 4155 void * 4156 rfs3_fsinfo_getfh(FSINFO3args *args) 4157 { 4158 4159 return (&args->fsroot); 4160 } 4161 4162 /* ARGSUSED */ 4163 void 4164 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi, 4165 struct svc_req *req, cred_t *cr) 4166 { 4167 int error; 4168 vnode_t *vp; 4169 struct vattr *vap; 4170 struct vattr va; 4171 ulong_t val; 4172 4173 vap = NULL; 4174 4175 vp = nfs3_fhtovp(&args->object, exi); 4176 4177 DTRACE_NFSV3_4(op__pathconf__start, struct svc_req *, req, 4178 cred_t *, cr, vnode_t *, vp, PATHCONF3args *, args); 4179 4180 if (vp == NULL) { 4181 error = ESTALE; 4182 goto out; 4183 } 4184 4185 if (is_system_labeled()) { 4186 bslabel_t *clabel = req->rq_label; 4187 4188 ASSERT(clabel != NULL); 4189 DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *, 4190 "got client label from request(1)", struct svc_req *, req); 4191 4192 if (!blequal(&l_admin_low->tsl_label, clabel)) { 4193 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { 4194 resp->status = NFS3ERR_ACCES; 4195 goto out1; 4196 } 4197 } 4198 } 4199 4200 #ifdef DEBUG 4201 if (rfs3_do_post_op_attr) { 4202 va.va_mask = AT_ALL; 4203 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 4204 } else 4205 vap = NULL; 4206 #else 4207 va.va_mask = AT_ALL; 4208 vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 4209 #endif 4210 4211 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL); 4212 if (error) 4213 goto out; 4214 resp->resok.info.link_max = (uint32)val; 4215 4216 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL); 4217 if (error) 4218 goto out; 4219 resp->resok.info.name_max = (uint32)val; 4220 4221 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL); 4222 if (error) 4223 goto out; 4224 if (val == 1) 4225 resp->resok.info.no_trunc = TRUE; 4226 else 4227 resp->resok.info.no_trunc = FALSE; 4228 4229 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL); 4230 if (error) 4231 goto out; 4232 if (val == 1) 4233 resp->resok.info.chown_restricted = TRUE; 4234 else 4235 resp->resok.info.chown_restricted = FALSE; 4236 4237 resp->status = NFS3_OK; 4238 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 4239 resp->resok.info.case_insensitive = FALSE; 4240 resp->resok.info.case_preserving = TRUE; 4241 DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req, 4242 cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp); 4243 VN_RELE(vp); 4244 return; 4245 4246 out: 4247 if (curthread->t_flag & T_WOULDBLOCK) { 4248 curthread->t_flag &= ~T_WOULDBLOCK; 4249 resp->status = NFS3ERR_JUKEBOX; 4250 } else 4251 resp->status = puterrno3(error); 4252 out1: 4253 DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req, 4254 cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp); 4255 if (vp != NULL) 4256 VN_RELE(vp); 4257 vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); 4258 } 4259 4260 void * 4261 rfs3_pathconf_getfh(PATHCONF3args *args) 4262 { 4263 4264 return (&args->object); 4265 } 4266 4267 void 4268 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi, 4269 struct svc_req *req, cred_t *cr) 4270 { 4271 int error; 4272 vnode_t *vp; 4273 struct vattr *bvap; 4274 struct vattr bva; 4275 struct vattr *avap; 4276 struct vattr ava; 4277 4278 bvap = NULL; 4279 avap = NULL; 4280 4281 vp = nfs3_fhtovp(&args->file, exi); 4282 4283 DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req, 4284 cred_t *, cr, vnode_t *, vp, COMMIT3args *, args); 4285 4286 if (vp == NULL) { 4287 error = ESTALE; 4288 goto out; 4289 } 4290 4291 bva.va_mask = AT_ALL; 4292 error = VOP_GETATTR(vp, &bva, 0, cr, NULL); 4293 4294 /* 4295 * If we can't get the attributes, then we can't do the 4296 * right access checking. So, we'll fail the request. 4297 */ 4298 if (error) 4299 goto out; 4300 4301 #ifdef DEBUG 4302 if (rfs3_do_pre_op_attr) 4303 bvap = &bva; 4304 else 4305 bvap = NULL; 4306 #else 4307 bvap = &bva; 4308 #endif 4309 4310 if (rdonly(exi, req)) { 4311 resp->status = NFS3ERR_ROFS; 4312 goto out1; 4313 } 4314 4315 if (vp->v_type != VREG) { 4316 resp->status = NFS3ERR_INVAL; 4317 goto out1; 4318 } 4319 4320 if (is_system_labeled()) { 4321 bslabel_t *clabel = req->rq_label; 4322 4323 ASSERT(clabel != NULL); 4324 DTRACE_PROBE2(tx__rfs3__log__info__opcommit__clabel, char *, 4325 "got client label from request(1)", struct svc_req *, req); 4326 4327 if (!blequal(&l_admin_low->tsl_label, clabel)) { 4328 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) { 4329 resp->status = NFS3ERR_ACCES; 4330 goto out1; 4331 } 4332 } 4333 } 4334 4335 if (crgetuid(cr) != bva.va_uid && 4336 (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL))) 4337 goto out; 4338 4339 error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr, NULL); 4340 if (!error) 4341 error = VOP_FSYNC(vp, FNODSYNC, cr, NULL); 4342 4343 #ifdef DEBUG 4344 if (rfs3_do_post_op_attr) { 4345 ava.va_mask = AT_ALL; 4346 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava; 4347 } else 4348 avap = NULL; 4349 #else 4350 ava.va_mask = AT_ALL; 4351 avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava; 4352 #endif 4353 4354 if (error) 4355 goto out; 4356 4357 resp->status = NFS3_OK; 4358 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); 4359 resp->resok.verf = write3verf; 4360 4361 DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req, 4362 cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp); 4363 4364 VN_RELE(vp); 4365 4366 return; 4367 4368 out: 4369 if (curthread->t_flag & T_WOULDBLOCK) { 4370 curthread->t_flag &= ~T_WOULDBLOCK; 4371 resp->status = NFS3ERR_JUKEBOX; 4372 } else 4373 resp->status = puterrno3(error); 4374 out1: 4375 DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req, 4376 cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp); 4377 4378 if (vp != NULL) 4379 VN_RELE(vp); 4380 vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc); 4381 } 4382 4383 void * 4384 rfs3_commit_getfh(COMMIT3args *args) 4385 { 4386 4387 return (&args->file); 4388 } 4389 4390 static int 4391 sattr3_to_vattr(sattr3 *sap, struct vattr *vap) 4392 { 4393 4394 vap->va_mask = 0; 4395 4396 if (sap->mode.set_it) { 4397 vap->va_mode = (mode_t)sap->mode.mode; 4398 vap->va_mask |= AT_MODE; 4399 } 4400 if (sap->uid.set_it) { 4401 vap->va_uid = (uid_t)sap->uid.uid; 4402 vap->va_mask |= AT_UID; 4403 } 4404 if (sap->gid.set_it) { 4405 vap->va_gid = (gid_t)sap->gid.gid; 4406 vap->va_mask |= AT_GID; 4407 } 4408 if (sap->size.set_it) { 4409 if (sap->size.size > (size3)((u_longlong_t)-1)) 4410 return (EINVAL); 4411 vap->va_size = sap->size.size; 4412 vap->va_mask |= AT_SIZE; 4413 } 4414 if (sap->atime.set_it == SET_TO_CLIENT_TIME) { 4415 #ifndef _LP64 4416 /* check time validity */ 4417 if (!NFS3_TIME_OK(sap->atime.atime.seconds)) 4418 return (EOVERFLOW); 4419 #endif 4420 /* 4421 * nfs protocol defines times as unsigned so don't extend sign, 4422 * unless sysadmin set nfs_allow_preepoch_time. 4423 */ 4424 NFS_TIME_T_CONVERT(vap->va_atime.tv_sec, 4425 sap->atime.atime.seconds); 4426 vap->va_atime.tv_nsec = (uint32_t)sap->atime.atime.nseconds; 4427 vap->va_mask |= AT_ATIME; 4428 } else if (sap->atime.set_it == SET_TO_SERVER_TIME) { 4429 gethrestime(&vap->va_atime); 4430 vap->va_mask |= AT_ATIME; 4431 } 4432 if (sap->mtime.set_it == SET_TO_CLIENT_TIME) { 4433 #ifndef _LP64 4434 /* check time validity */ 4435 if (!NFS3_TIME_OK(sap->mtime.mtime.seconds)) 4436 return (EOVERFLOW); 4437 #endif 4438 /* 4439 * nfs protocol defines times as unsigned so don't extend sign, 4440 * unless sysadmin set nfs_allow_preepoch_time. 4441 */ 4442 NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec, 4443 sap->mtime.mtime.seconds); 4444 vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds; 4445 vap->va_mask |= AT_MTIME; 4446 } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) { 4447 gethrestime(&vap->va_mtime); 4448 vap->va_mask |= AT_MTIME; 4449 } 4450 4451 return (0); 4452 } 4453 4454 static ftype3 vt_to_nf3[] = { 4455 0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0 4456 }; 4457 4458 static int 4459 vattr_to_fattr3(struct vattr *vap, fattr3 *fap) 4460 { 4461 4462 ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD); 4463 /* Return error if time or size overflow */ 4464 if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) { 4465 return (EOVERFLOW); 4466 } 4467 fap->type = vt_to_nf3[vap->va_type]; 4468 fap->mode = (mode3)(vap->va_mode & MODEMASK); 4469 fap->nlink = (uint32)vap->va_nlink; 4470 if (vap->va_uid == UID_NOBODY) 4471 fap->uid = (uid3)NFS_UID_NOBODY; 4472 else 4473 fap->uid = (uid3)vap->va_uid; 4474 if (vap->va_gid == GID_NOBODY) 4475 fap->gid = (gid3)NFS_GID_NOBODY; 4476 else 4477 fap->gid = (gid3)vap->va_gid; 4478 fap->size = (size3)vap->va_size; 4479 fap->used = (size3)DEV_BSIZE * (size3)vap->va_nblocks; 4480 fap->rdev.specdata1 = (uint32)getmajor(vap->va_rdev); 4481 fap->rdev.specdata2 = (uint32)getminor(vap->va_rdev); 4482 fap->fsid = (uint64)vap->va_fsid; 4483 fap->fileid = (fileid3)vap->va_nodeid; 4484 fap->atime.seconds = vap->va_atime.tv_sec; 4485 fap->atime.nseconds = vap->va_atime.tv_nsec; 4486 fap->mtime.seconds = vap->va_mtime.tv_sec; 4487 fap->mtime.nseconds = vap->va_mtime.tv_nsec; 4488 fap->ctime.seconds = vap->va_ctime.tv_sec; 4489 fap->ctime.nseconds = vap->va_ctime.tv_nsec; 4490 return (0); 4491 } 4492 4493 static int 4494 vattr_to_wcc_attr(struct vattr *vap, wcc_attr *wccap) 4495 { 4496 4497 /* Return error if time or size overflow */ 4498 if (!(NFS_TIME_T_OK(vap->va_mtime.tv_sec) && 4499 NFS_TIME_T_OK(vap->va_ctime.tv_sec) && 4500 NFS3_SIZE_OK(vap->va_size))) { 4501 return (EOVERFLOW); 4502 } 4503 wccap->size = (size3)vap->va_size; 4504 wccap->mtime.seconds = vap->va_mtime.tv_sec; 4505 wccap->mtime.nseconds = vap->va_mtime.tv_nsec; 4506 wccap->ctime.seconds = vap->va_ctime.tv_sec; 4507 wccap->ctime.nseconds = vap->va_ctime.tv_nsec; 4508 return (0); 4509 } 4510 4511 static void 4512 vattr_to_pre_op_attr(struct vattr *vap, pre_op_attr *poap) 4513 { 4514 4515 /* don't return attrs if time overflow */ 4516 if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) { 4517 poap->attributes = TRUE; 4518 } else 4519 poap->attributes = FALSE; 4520 } 4521 4522 void 4523 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap) 4524 { 4525 4526 /* don't return attrs if time overflow */ 4527 if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) { 4528 poap->attributes = TRUE; 4529 } else 4530 poap->attributes = FALSE; 4531 } 4532 4533 static void 4534 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp) 4535 { 4536 4537 vattr_to_pre_op_attr(bvap, &wccp->before); 4538 vattr_to_post_op_attr(avap, &wccp->after); 4539 } 4540 4541 void 4542 rfs3_srvrinit(void) 4543 { 4544 struct rfs3_verf_overlay { 4545 uint_t id; /* a "unique" identifier */ 4546 int ts; /* a unique timestamp */ 4547 } *verfp; 4548 timestruc_t now; 4549 4550 /* 4551 * The following algorithm attempts to find a unique verifier 4552 * to be used as the write verifier returned from the server 4553 * to the client. It is important that this verifier change 4554 * whenever the server reboots. Of secondary importance, it 4555 * is important for the verifier to be unique between two 4556 * different servers. 4557 * 4558 * Thus, an attempt is made to use the system hostid and the 4559 * current time in seconds when the nfssrv kernel module is 4560 * loaded. It is assumed that an NFS server will not be able 4561 * to boot and then to reboot in less than a second. If the 4562 * hostid has not been set, then the current high resolution 4563 * time is used. This will ensure different verifiers each 4564 * time the server reboots and minimize the chances that two 4565 * different servers will have the same verifier. 4566 */ 4567 4568 #ifndef lint 4569 /* 4570 * We ASSERT that this constant logic expression is 4571 * always true because in the past, it wasn't. 4572 */ 4573 ASSERT(sizeof (*verfp) <= sizeof (write3verf)); 4574 #endif 4575 4576 gethrestime(&now); 4577 verfp = (struct rfs3_verf_overlay *)&write3verf; 4578 verfp->ts = (int)now.tv_sec; 4579 verfp->id = zone_get_hostid(NULL); 4580 4581 if (verfp->id == 0) 4582 verfp->id = (uint_t)now.tv_nsec; 4583 4584 nfs3_srv_caller_id = fs_new_caller_id(); 4585 4586 } 4587 4588 static int 4589 rdma_setup_read_data3(READ3args *args, READ3resok *rok) 4590 { 4591 struct clist *wcl; 4592 int data_len, avail_len, num; 4593 count3 count = rok->count; 4594 4595 data_len = num = avail_len = 0; 4596 4597 wcl = args->wlist; 4598 while (wcl != NULL) { 4599 if (wcl->c_dmemhandle.mrc_rmr == 0) 4600 break; 4601 4602 avail_len += wcl->c_len; 4603 if (wcl->c_len < count) { 4604 data_len += wcl->c_len; 4605 } else { 4606 /* Can make the rest chunks all 0-len */ 4607 data_len += count; 4608 wcl->c_len = count; 4609 } 4610 count -= wcl->c_len; 4611 num ++; 4612 wcl = wcl->c_next; 4613 } 4614 4615 /* 4616 * MUST fail if there are still more data 4617 */ 4618 if (count > 0) { 4619 DTRACE_PROBE2(nfss__e__read3_wlist_fail, 4620 int, data_len, int, count); 4621 return (FALSE); 4622 } 4623 4624 wcl = args->wlist; 4625 rok->count = data_len; 4626 rok->wlist_len = data_len; 4627 rok->wlist = wcl; 4628 4629 return (TRUE); 4630 } 4631 4632 void 4633 rfs3_srvrfini(void) 4634 { 4635 /* Nothing to do */ 4636 } 4637