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