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