1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/types.h> 28 #include <sys/systm.h> 29 #include <sys/cred.h> 30 #include <sys/buf.h> 31 #include <sys/vfs.h> 32 #include <sys/vnode.h> 33 #include <sys/uio.h> 34 #include <sys/errno.h> 35 #include <sys/sysmacros.h> 36 #include <sys/statvfs.h> 37 #include <sys/kmem.h> 38 #include <sys/dirent.h> 39 #include <rpc/types.h> 40 #include <rpc/auth.h> 41 #include <rpc/rpcsec_gss.h> 42 #include <rpc/svc.h> 43 #include <sys/strsubr.h> 44 #include <sys/strsun.h> 45 #include <sys/sdt.h> 46 47 #include <nfs/nfs.h> 48 #include <nfs/export.h> 49 #include <nfs/nfs4.h> 50 #include <nfs/nfs_cmd.h> 51 52 53 /* 54 * RFS4_MINLEN_ENTRY4: XDR-encoded size of smallest possible dirent. 55 * This is used to return NFS4ERR_TOOSMALL when clients specify 56 * maxcount that isn't large enough to hold the smallest possible 57 * XDR encoded dirent. 58 * 59 * sizeof cookie (8 bytes) + 60 * sizeof name_len (4 bytes) + 61 * sizeof smallest (padded) name (4 bytes) + 62 * sizeof bitmap4_len (12 bytes) + NOTE: we always encode len=2 bm4 63 * sizeof attrlist4_len (4 bytes) + 64 * sizeof next boolean (4 bytes) 65 * 66 * RFS4_MINLEN_RDDIR4: XDR-encoded size of READDIR op reply containing 67 * the smallest possible entry4 (assumes no attrs requested). 68 * sizeof nfsstat4 (4 bytes) + 69 * sizeof verifier4 (8 bytes) + 70 * sizeof entsecond_to_ry4list bool (4 bytes) + 71 * sizeof entry4 (36 bytes) + 72 * sizeof eof bool (4 bytes) 73 * 74 * RFS4_MINLEN_RDDIR_BUF: minimum length of buffer server will provide to 75 * VOP_READDIR. Its value is the size of the maximum possible dirent 76 * for solaris. The DIRENT64_RECLEN macro returns the size of dirent 77 * required for a given name length. MAXNAMELEN is the maximum 78 * filename length allowed in Solaris. The first two DIRENT64_RECLEN() 79 * macros are to allow for . and .. entries -- just a minor tweak to try 80 * and guarantee that buffer we give to VOP_READDIR will be large enough 81 * to hold ., .., and the largest possible solaris dirent64. 82 */ 83 #define RFS4_MINLEN_ENTRY4 36 84 #define RFS4_MINLEN_RDDIR4 (4 + NFS4_VERIFIER_SIZE + 4 + RFS4_MINLEN_ENTRY4 + 4) 85 #define RFS4_MINLEN_RDDIR_BUF \ 86 (DIRENT64_RECLEN(1) + DIRENT64_RECLEN(2) + DIRENT64_RECLEN(MAXNAMELEN)) 87 88 89 #ifdef nextdp 90 #undef nextdp 91 #endif 92 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) 93 94 verifier4 Readdir4verf = 0x0; 95 96 static nfs_ftype4 vt_to_nf4[] = { 97 0, NF4REG, NF4DIR, NF4BLK, NF4CHR, NF4LNK, NF4FIFO, 0, 0, NF4SOCK, 0 98 }; 99 100 int 101 nfs4_readdir_getvp(vnode_t *dvp, char *d_name, vnode_t **vpp, 102 struct exportinfo **exi, struct svc_req *req, 103 struct compound_state *cs, int expseudo) 104 { 105 int error; 106 int ismntpt; 107 fid_t fid; 108 vnode_t *vp, *pre_tvp; 109 nfsstat4 status; 110 struct exportinfo *newexi, *saveexi; 111 cred_t *scr; 112 113 *vpp = vp = NULL; 114 115 if (error = VOP_LOOKUP(dvp, d_name, &vp, NULL, 0, NULL, cs->cr, 116 NULL, NULL, NULL)) 117 return (error); 118 119 /* 120 * If the directory is a referral point, don't return the 121 * attrs, instead set rdattr_error to MOVED. 122 */ 123 if (vn_is_nfs_reparse(vp, cs->cr) && !client_is_downrev(req)) { 124 VN_RELE(vp); 125 DTRACE_PROBE2(nfs4serv__func__referral__moved, 126 vnode_t *, vp, char *, "nfs4_readdir_getvp"); 127 return (NFS4ERR_MOVED); 128 } 129 130 /* Is this object mounted upon? */ 131 ismntpt = vn_ismntpt(vp); 132 133 /* 134 * Nothing more to do if object is not a mount point or 135 * a possible LOFS shadow of an LOFS mount (which won't 136 * have v_vfsmountedhere set) 137 */ 138 if (ismntpt == 0 && dvp->v_vfsp == vp->v_vfsp && expseudo == 0) { 139 *vpp = vp; 140 return (0); 141 } 142 143 if (ismntpt) { 144 /* 145 * Something is mounted here. Traverse and manage the 146 * namespace 147 */ 148 pre_tvp = vp; 149 VN_HOLD(pre_tvp); 150 151 if ((error = traverse(&vp)) != 0) { 152 VN_RELE(pre_tvp); 153 return (error); 154 } 155 if (vn_is_nfs_reparse(vp, cs->cr)) { 156 VN_RELE(vp); 157 VN_RELE(pre_tvp); 158 DTRACE_PROBE2(nfs4serv__func__referral__moved, 159 vnode_t *, vp, char *, "nfs4_readdir_getvp"); 160 return (NFS4ERR_MOVED); 161 } 162 } 163 164 bzero(&fid, sizeof (fid)); 165 fid.fid_len = MAXFIDSZ; 166 167 /* 168 * If VOP_FID not supported by underlying fs (mntfs, procfs, 169 * etc.), then return attrs for stub instead of VROOT object. 170 * If it fails for any other reason, then return the error. 171 */ 172 if (error = VOP_FID(vp, &fid, NULL)) { 173 if (ismntpt == 0) { 174 VN_RELE(vp); 175 return (error); 176 } 177 178 if (error != ENOSYS && error != ENOTSUP) { 179 VN_RELE(vp); 180 VN_RELE(pre_tvp); 181 return (error); 182 } 183 /* go back to vnode that is "under" mount */ 184 VN_RELE(vp); 185 *vpp = pre_tvp; 186 return (0); 187 } 188 189 newexi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); 190 if (newexi == NULL) { 191 if (ismntpt == 0) { 192 *vpp = vp; 193 } else { 194 VN_RELE(vp); 195 *vpp = pre_tvp; 196 } 197 return (0); 198 } 199 200 if (ismntpt) 201 VN_RELE(pre_tvp); 202 203 /* Save the exi and present the new one to checkauth4() */ 204 saveexi = cs->exi; 205 cs->exi = newexi; 206 207 /* Get the right cred like lookup does */ 208 scr = cs->cr; 209 cs->cr = crdup(cs->basecr); 210 211 status = call_checkauth4(cs, req); 212 213 crfree(cs->cr); 214 cs->cr = scr; 215 cs->exi = saveexi; 216 217 /* Reset what call_checkauth4() may have set */ 218 *cs->statusp = NFS4_OK; 219 220 if (status != NFS4_OK) { 221 VN_RELE(vp); 222 if (status == NFS4ERR_DELAY) 223 status = NFS4ERR_ACCESS; 224 return (status); 225 } 226 *vpp = vp; 227 *exi = newexi; 228 229 return (0); 230 } 231 232 /* This is the set of pathconf data for vfs */ 233 typedef struct { 234 uint64_t maxfilesize; 235 uint32_t maxlink; 236 uint32_t maxname; 237 } rfs4_pc_encode_t; 238 239 240 static int 241 rfs4_get_pc_encode(vnode_t *vp, rfs4_pc_encode_t *pce, bitmap4 ar, cred_t *cr) 242 { 243 int error; 244 ulong_t pc_val; 245 246 pce->maxfilesize = 0; 247 pce->maxlink = 0; 248 pce->maxname = 0; 249 250 if (ar & FATTR4_MAXFILESIZE_MASK) { 251 /* Maximum File Size */ 252 error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &pc_val, cr, NULL); 253 if (error) 254 return (error); 255 256 /* 257 * If the underlying file system does not support 258 * _PC_FILESIZEBITS, return a reasonable default. Note that 259 * error code on VOP_PATHCONF will be 0, even if the underlying 260 * file system does not support _PC_FILESIZEBITS. 261 */ 262 if (pc_val == (ulong_t)-1) { 263 pce->maxfilesize = MAXOFF32_T; 264 } else { 265 if (pc_val >= (sizeof (uint64_t) * 8)) 266 pce->maxfilesize = INT64_MAX; 267 else 268 pce->maxfilesize = ((1LL << (pc_val - 1)) - 1); 269 } 270 } 271 272 if (ar & FATTR4_MAXLINK_MASK) { 273 /* Maximum Link Count */ 274 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &pc_val, cr, NULL); 275 if (error) 276 return (error); 277 278 pce->maxlink = pc_val; 279 } 280 281 if (ar & FATTR4_MAXNAME_MASK) { 282 /* Maximum Name Length */ 283 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &pc_val, cr, NULL); 284 if (error) 285 return (error); 286 287 pce->maxname = pc_val; 288 } 289 290 return (0); 291 } 292 293 /* This is the set of statvfs data that is ready for encoding */ 294 typedef struct { 295 uint64_t space_avail; 296 uint64_t space_free; 297 uint64_t space_total; 298 u_longlong_t fa; 299 u_longlong_t ff; 300 u_longlong_t ft; 301 } rfs4_sb_encode_t; 302 303 static int 304 rfs4_get_sb_encode(vfs_t *vfsp, rfs4_sb_encode_t *psbe) 305 { 306 int error; 307 struct statvfs64 sb; 308 309 /* Grab the per filesystem info */ 310 if (error = VFS_STATVFS(vfsp, &sb)) { 311 return (error); 312 } 313 314 /* Calculate space available */ 315 if (sb.f_bavail != (fsblkcnt64_t)-1) { 316 psbe->space_avail = 317 (fattr4_space_avail) sb.f_frsize * 318 (fattr4_space_avail) sb.f_bavail; 319 } else { 320 psbe->space_avail = 321 (fattr4_space_avail) sb.f_bavail; 322 } 323 324 /* Calculate space free */ 325 if (sb.f_bfree != (fsblkcnt64_t)-1) { 326 psbe->space_free = 327 (fattr4_space_free) sb.f_frsize * 328 (fattr4_space_free) sb.f_bfree; 329 } else { 330 psbe->space_free = 331 (fattr4_space_free) sb.f_bfree; 332 } 333 334 /* Calculate space total */ 335 if (sb.f_blocks != (fsblkcnt64_t)-1) { 336 psbe->space_total = 337 (fattr4_space_total) sb.f_frsize * 338 (fattr4_space_total) sb.f_blocks; 339 } else { 340 psbe->space_total = 341 (fattr4_space_total) sb.f_blocks; 342 } 343 344 /* For use later on attr encode */ 345 psbe->fa = sb.f_favail; 346 psbe->ff = sb.f_ffree; 347 psbe->ft = sb.f_files; 348 349 return (0); 350 } 351 352 /* 353 * Macros to handle if we have don't have enough space for the requested 354 * attributes and this is the first entry and the 355 * requested attributes are more than the minimal useful 356 * set, reset the attributes to the minimal set and 357 * retry the encoding. If the client has asked for both 358 * mounted_on_fileid and fileid, prefer mounted_on_fileid. 359 */ 360 #define MINIMAL_RD_ATTRS \ 361 (FATTR4_MOUNTED_ON_FILEID_MASK| \ 362 FATTR4_FILEID_MASK| \ 363 FATTR4_RDATTR_ERROR_MASK) 364 365 #define MINIMIZE_ATTR_MASK(m) { \ 366 if ((m) & FATTR4_MOUNTED_ON_FILEID_MASK) \ 367 (m) &= FATTR4_RDATTR_ERROR_MASK|FATTR4_MOUNTED_ON_FILEID_MASK;\ 368 else \ 369 (m) &= FATTR4_RDATTR_ERROR_MASK|FATTR4_FILEID_MASK; \ 370 } 371 372 #define IS_MIN_ATTR_MASK(m) (((m) & ~MINIMAL_RD_ATTRS) == 0) 373 /* 374 * If readdir only needs to return FILEID, we can take it from the 375 * dirent struct and save doing the lookup. 376 */ 377 /* ARGSUSED */ 378 void 379 rfs4_op_readdir(nfs_argop4 *argop, nfs_resop4 *resop, 380 struct svc_req *req, struct compound_state *cs) 381 { 382 READDIR4args *args = &argop->nfs_argop4_u.opreaddir; 383 READDIR4res *resp = &resop->nfs_resop4_u.opreaddir; 384 struct exportinfo *newexi = NULL; 385 int error; 386 mblk_t *mp; 387 uint_t mpcount; 388 int alloc_err = 0; 389 vnode_t *dvp = cs->vp; 390 vnode_t *vp; 391 vattr_t va; 392 struct dirent64 *dp; 393 rfs4_sb_encode_t dsbe, sbe; 394 int vfs_different; 395 int rddir_data_len, rddir_result_size; 396 caddr_t rddir_data; 397 offset_t rddir_next_offset; 398 int dircount; 399 int no_space; 400 int iseofdir; 401 uint_t eof; 402 struct iovec iov; 403 struct uio uio; 404 int tsize; 405 int check_visible; 406 int expseudo = 0; 407 408 uint32_t *ptr, *ptr_redzone; 409 uint32_t *beginning_ptr; 410 uint32_t *lastentry_ptr; 411 uint32_t *attrmask_ptr; 412 uint32_t *attr_offset_ptr; 413 uint32_t attr_length; 414 uint32_t rndup; 415 uint32_t namelen; 416 uint32_t rddirattr_error = 0; 417 int nents; 418 bitmap4 ar = args->attr_request & NFS4_SRV_RDDIR_SUPPORTED_ATTRS; 419 bitmap4 ae; 420 rfs4_pc_encode_t dpce, pce; 421 ulong_t pc_val; 422 uint64_t maxread; 423 uint64_t maxwrite; 424 uint_t true = TRUE; 425 uint_t false = FALSE; 426 uid_t lastuid; 427 gid_t lastgid; 428 int lu_set, lg_set; 429 utf8string owner, group; 430 int owner_error, group_error; 431 struct sockaddr *ca; 432 char *name = NULL; 433 434 DTRACE_NFSV4_2(op__readdir__start, struct compound_state *, cs, 435 READDIR4args *, args); 436 437 lu_set = lg_set = 0; 438 owner.utf8string_len = group.utf8string_len = 0; 439 owner.utf8string_val = group.utf8string_val = NULL; 440 441 resp->mblk = NULL; 442 443 /* Maximum read and write size */ 444 maxread = maxwrite = rfs4_tsize(req); 445 446 if (dvp == NULL) { 447 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 448 goto out; 449 } 450 451 /* 452 * If there is an unshared filesystem mounted on this vnode, 453 * do not allow readdir in this directory. 454 */ 455 if (vn_ismntpt(dvp)) { 456 *cs->statusp = resp->status = NFS4ERR_ACCESS; 457 goto out; 458 } 459 460 if (dvp->v_type != VDIR) { 461 *cs->statusp = resp->status = NFS4ERR_NOTDIR; 462 goto out; 463 } 464 465 if (args->maxcount <= RFS4_MINLEN_RDDIR4) { 466 *cs->statusp = resp->status = NFS4ERR_TOOSMALL; 467 goto out; 468 } 469 470 /* 471 * If write-only attrs are requested, then fail the readdir op 472 */ 473 if (args->attr_request & 474 (FATTR4_TIME_MODIFY_SET_MASK | FATTR4_TIME_ACCESS_SET_MASK)) { 475 *cs->statusp = resp->status = NFS4ERR_INVAL; 476 goto out; 477 } 478 479 error = VOP_ACCESS(dvp, VREAD, 0, cs->cr, NULL); 480 if (error) { 481 *cs->statusp = resp->status = puterrno4(error); 482 goto out; 483 } 484 485 if (args->cookieverf != Readdir4verf) { 486 *cs->statusp = resp->status = NFS4ERR_NOT_SAME; 487 goto out; 488 } 489 490 /* Is there pseudo-fs work that is needed for this readdir? */ 491 check_visible = PSEUDO(cs->exi) || 492 ! is_exported_sec(cs->nfsflavor, cs->exi) || 493 cs->access & CS_ACCESS_LIMITED; 494 495 /* Check the requested attributes and only do the work if needed */ 496 497 if (ar & (FATTR4_MAXFILESIZE_MASK | 498 FATTR4_MAXLINK_MASK | 499 FATTR4_MAXNAME_MASK)) { 500 if (error = rfs4_get_pc_encode(cs->vp, &dpce, ar, cs->cr)) { 501 *cs->statusp = resp->status = puterrno4(error); 502 goto out; 503 } 504 pce = dpce; 505 } 506 507 /* If there is statvfs data requested, pick it up once */ 508 if (ar & 509 (FATTR4_FILES_AVAIL_MASK | 510 FATTR4_FILES_FREE_MASK | 511 FATTR4_FILES_TOTAL_MASK | 512 FATTR4_FILES_AVAIL_MASK | 513 FATTR4_FILES_FREE_MASK | 514 FATTR4_FILES_TOTAL_MASK)) { 515 if (error = rfs4_get_sb_encode(dvp->v_vfsp, &dsbe)) { 516 *cs->statusp = resp->status = puterrno4(error); 517 goto out; 518 } 519 sbe = dsbe; 520 } 521 522 /* 523 * Max transfer size of the server is the absolute limite. 524 * If the client has decided to max out with something really 525 * tiny, then return toosmall. Otherwise, move forward and 526 * see if a single entry can be encoded. 527 */ 528 tsize = rfs4_tsize(req); 529 if (args->maxcount > tsize) 530 args->maxcount = tsize; 531 else if (args->maxcount < RFS4_MINLEN_RDDIR_BUF) { 532 if (args->maxcount < RFS4_MINLEN_ENTRY4) { 533 *cs->statusp = resp->status = NFS4ERR_TOOSMALL; 534 goto out; 535 } 536 } 537 538 /* 539 * How large should the mblk be for outgoing encoding. 540 */ 541 if (args->maxcount < MAXBSIZE) 542 mpcount = MAXBSIZE; 543 else 544 mpcount = args->maxcount; 545 546 /* 547 * mp will contain the data to be sent out in the readdir reply. 548 * It will be freed after the reply has been sent. 549 * Let's roundup the data to a BYTES_PER_XDR_UNIX multiple, 550 * so that the call to xdrmblk_putmblk() never fails. 551 */ 552 mp = allocb(RNDUP(mpcount), BPRI_MED); 553 554 if (mp == NULL) { 555 /* 556 * The allocation of the client's requested size has 557 * failed. It may be that the size is too large for 558 * current system utilization; step down to a "common" 559 * size and wait for the allocation to occur. 560 */ 561 if (mpcount > MAXBSIZE) 562 args->maxcount = mpcount = MAXBSIZE; 563 mp = allocb_wait(RNDUP(mpcount), BPRI_MED, 564 STR_NOSIG, &alloc_err); 565 } 566 567 ASSERT(mp != NULL); 568 ASSERT(alloc_err == 0); 569 570 resp->mblk = mp; 571 572 ptr = beginning_ptr = (uint32_t *)mp->b_datap->db_base; 573 574 /* 575 * The "redzone" at the end of the encoding buffer is used 576 * to deal with xdr encoding length. Instead of checking 577 * each encoding of an attribute value before it is done, 578 * make the assumption that it will fit into the buffer and 579 * check occasionally. 580 * 581 * The largest block of attributes that are encoded without 582 * checking the redzone is 18 * BYTES_PER_XDR_UNIT (72 bytes) 583 * "round" to 128 as the redzone size. 584 */ 585 if (args->maxcount < (mpcount - 128)) 586 ptr_redzone = 587 (uint32_t *)(((char *)ptr) + RNDUP(args->maxcount)); 588 else 589 ptr_redzone = 590 (uint32_t *)((((char *)ptr) + RNDUP(mpcount)) - 128); 591 592 /* 593 * Set the dircount; this will be used as the size for the 594 * readdir of the underlying filesystem. First make sure 595 * that it is large enough to do a reasonable readdir (client 596 * may have short changed us - it is an advisory number); 597 * then make sure that it isn't too large. 598 * After all of that, if maxcount is "small" then just use 599 * that for the dircount number. 600 */ 601 dircount = (args->dircount < MAXBSIZE) ? MAXBSIZE : args->dircount; 602 dircount = (dircount > tsize) ? tsize : dircount; 603 if (dircount > args->maxcount) 604 dircount = args->maxcount; 605 if (args->maxcount <= MAXBSIZE) { 606 if (args->maxcount < RFS4_MINLEN_RDDIR_BUF) 607 dircount = RFS4_MINLEN_RDDIR_BUF; 608 else 609 dircount = args->maxcount; 610 } 611 612 /* number of entries fully encoded in outgoing buffer */ 613 nents = 0; 614 615 /* ENCODE READDIR4res.cookieverf */ 616 IXDR_PUT_HYPER(ptr, Readdir4verf); 617 618 rddir_data_len = dircount; 619 rddir_data = kmem_alloc(rddir_data_len, KM_NOSLEEP); 620 if (rddir_data == NULL) { 621 /* The allocation failed; downsize and wait for it this time */ 622 if (rddir_data_len > MAXBSIZE) 623 rddir_data_len = dircount = MAXBSIZE; 624 rddir_data = kmem_alloc(rddir_data_len, KM_SLEEP); 625 } 626 627 rddir_next_offset = (offset_t)args->cookie; 628 629 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 630 631 readagain: 632 633 no_space = FALSE; 634 iseofdir = FALSE; 635 636 vp = NULL; 637 638 /* Move on to reading the directory contents */ 639 iov.iov_base = rddir_data; 640 iov.iov_len = rddir_data_len; 641 uio.uio_iov = &iov; 642 uio.uio_iovcnt = 1; 643 uio.uio_segflg = UIO_SYSSPACE; 644 uio.uio_extflg = UIO_COPY_CACHED; 645 uio.uio_loffset = rddir_next_offset; 646 uio.uio_resid = rddir_data_len; 647 648 (void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL); 649 650 error = VOP_READDIR(dvp, &uio, cs->cr, &iseofdir, NULL, 0); 651 652 VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL); 653 654 if (error) { 655 kmem_free((caddr_t)rddir_data, rddir_data_len); 656 freeb(resp->mblk); 657 resp->mblk = NULL; 658 resp->data_len = 0; 659 *cs->statusp = resp->status = puterrno4(error); 660 goto out; 661 } 662 663 664 rddir_result_size = rddir_data_len - uio.uio_resid; 665 666 /* No data were read. Check if we reached the end of the directory. */ 667 if (rddir_result_size == 0) { 668 /* encode the BOOLEAN marking no further entries */ 669 IXDR_PUT_U_INT32(ptr, false); 670 /* encode the BOOLEAN signifying end of directory */ 671 IXDR_PUT_U_INT32(ptr, iseofdir ? true : false); 672 resp->data_len = (char *)ptr - (char *)beginning_ptr; 673 resp->mblk->b_wptr += resp->data_len; 674 kmem_free((caddr_t)rddir_data, rddir_data_len); 675 *cs->statusp = resp->status = NFS4_OK; 676 goto out; 677 } 678 679 lastentry_ptr = ptr; 680 no_space = 0; 681 for (dp = (struct dirent64 *)rddir_data; 682 !no_space && rddir_result_size > 0; dp = nextdp(dp)) { 683 684 /* reset expseudo */ 685 expseudo = 0; 686 687 if (vp) { 688 VN_RELE(vp); 689 vp = NULL; 690 } 691 692 if (newexi) 693 newexi = NULL; 694 695 rddir_result_size -= dp->d_reclen; 696 697 /* skip "." and ".." entries */ 698 if (dp->d_ino == 0 || NFS_IS_DOTNAME(dp->d_name)) { 699 rddir_next_offset = dp->d_off; 700 continue; 701 } 702 703 if (check_visible && 704 !nfs_visible_inode(cs->exi, dp->d_ino, &expseudo)) { 705 rddir_next_offset = dp->d_off; 706 continue; 707 } 708 709 /* 710 * Only if the client requested attributes... 711 * If the VOP_LOOKUP fails ENOENT, then skip this entry 712 * for the readdir response. If there was another error, 713 * then set the rddirattr_error and the error will be 714 * encoded later in the "attributes" section. 715 */ 716 ae = ar; 717 if (ar == 0) 718 goto reencode_attrs; 719 720 error = nfs4_readdir_getvp(dvp, dp->d_name, 721 &vp, &newexi, req, cs, expseudo); 722 if (error == ENOENT) { 723 rddir_next_offset = dp->d_off; 724 continue; 725 } 726 727 rddirattr_error = error; 728 729 /* 730 * The vp obtained from above may be from a 731 * different filesystem mount and the vfs-like 732 * attributes should be obtained from that 733 * different vfs; only do this if appropriate. 734 */ 735 if (vp && 736 (vfs_different = (dvp->v_vfsp != vp->v_vfsp))) { 737 if (ar & (FATTR4_FILES_AVAIL_MASK | 738 FATTR4_FILES_FREE_MASK | 739 FATTR4_FILES_TOTAL_MASK | 740 FATTR4_FILES_AVAIL_MASK | 741 FATTR4_FILES_FREE_MASK | 742 FATTR4_FILES_TOTAL_MASK)) { 743 if (error = 744 rfs4_get_sb_encode(dvp->v_vfsp, 745 &sbe)) { 746 /* Remove attrs from encode */ 747 ae &= ~(FATTR4_FILES_AVAIL_MASK | 748 FATTR4_FILES_FREE_MASK | 749 FATTR4_FILES_TOTAL_MASK | 750 FATTR4_FILES_AVAIL_MASK | 751 FATTR4_FILES_FREE_MASK | 752 FATTR4_FILES_TOTAL_MASK); 753 rddirattr_error = error; 754 } 755 } 756 if (ar & (FATTR4_MAXFILESIZE_MASK | 757 FATTR4_MAXLINK_MASK | 758 FATTR4_MAXNAME_MASK)) { 759 if (error = rfs4_get_pc_encode(cs->vp, 760 &pce, ar, cs->cr)) { 761 ar &= ~(FATTR4_MAXFILESIZE_MASK | 762 FATTR4_MAXLINK_MASK | 763 FATTR4_MAXNAME_MASK); 764 rddirattr_error = error; 765 } 766 } 767 } 768 769 reencode_attrs: 770 /* encode the BOOLEAN for the existence of the next entry */ 771 IXDR_PUT_U_INT32(ptr, true); 772 /* encode the COOKIE for the entry */ 773 IXDR_PUT_U_HYPER(ptr, dp->d_off); 774 775 name = nfscmd_convname(ca, cs->exi, dp->d_name, 776 NFSCMD_CONV_OUTBOUND, MAXPATHLEN + 1); 777 778 if (name == NULL) { 779 rddir_next_offset = dp->d_off; 780 continue; 781 } 782 /* Calculate the dirent name length */ 783 namelen = strlen(name); 784 785 rndup = RNDUP(namelen) / BYTES_PER_XDR_UNIT; 786 787 /* room for LENGTH + string ? */ 788 if ((ptr + (1 + rndup)) > ptr_redzone) { 789 no_space = TRUE; 790 continue; 791 } 792 793 /* encode the LENGTH of the name */ 794 IXDR_PUT_U_INT32(ptr, namelen); 795 /* encode the RNDUP FILL first */ 796 ptr[rndup - 1] = 0; 797 /* encode the NAME of the entry */ 798 bcopy(name, (char *)ptr, namelen); 799 /* now bump the ptr after... */ 800 ptr += rndup; 801 802 if (name != dp->d_name) 803 kmem_free(name, MAXPATHLEN + 1); 804 805 /* 806 * Keep checking on the dircount to see if we have 807 * reached the limit; from the RFC, dircount is to be 808 * the XDR encoded limit of the cookie plus name. 809 * So the count is the name, XDR_UNIT of length for 810 * that name and 2 * XDR_UNIT bytes of cookie; 811 * However, use the regular DIRENT64 to match most 812 * client's APIs. 813 */ 814 dircount -= DIRENT64_RECLEN(namelen); 815 if (nents != 0 && dircount < 0) { 816 no_space = TRUE; 817 continue; 818 } 819 820 /* 821 * Attributes requested? 822 * Gather up the attribute info and the previous VOP_LOOKUP() 823 * succeeded; if an error occurs on the VOP_GETATTR() then 824 * return just the error (again if it is requested). 825 * Note that the previous VOP_LOOKUP() could have failed 826 * itself which leaves this code without anything for 827 * a VOP_GETATTR(). 828 * Also note that the readdir_attr_error is left in the 829 * encoding mask if requested and so is the mounted_on_fileid. 830 */ 831 if (ae != 0) { 832 if (!vp) { 833 ae = ar & (FATTR4_RDATTR_ERROR_MASK | 834 FATTR4_MOUNTED_ON_FILEID_MASK); 835 } else { 836 va.va_mask = AT_ALL; 837 rddirattr_error = 838 VOP_GETATTR(vp, &va, 0, cs->cr, NULL); 839 if (rddirattr_error) { 840 ae = ar & (FATTR4_RDATTR_ERROR_MASK | 841 FATTR4_MOUNTED_ON_FILEID_MASK); 842 } else { 843 /* 844 * We may lie about the object 845 * type for a referral 846 */ 847 if (vn_is_nfs_reparse(vp, cs->cr) && 848 client_is_downrev(req)) 849 va.va_type = VLNK; 850 } 851 } 852 } 853 854 /* START OF ATTRIBUTE ENCODING */ 855 856 /* encode the LENGTH of the BITMAP4 array */ 857 IXDR_PUT_U_INT32(ptr, 2); 858 /* encode the BITMAP4 */ 859 attrmask_ptr = ptr; 860 IXDR_PUT_HYPER(ptr, ae); 861 attr_offset_ptr = ptr; 862 /* encode the default LENGTH of the attributes for entry */ 863 IXDR_PUT_U_INT32(ptr, 0); 864 865 if (ptr > ptr_redzone) { 866 no_space = TRUE; 867 continue; 868 } 869 870 /* Check if any of the first 32 attributes are being encoded */ 871 if (ae & 0xffffffff00000000) { 872 /* 873 * Redzone check is done at the end of this section. 874 * This particular section will encode a maximum of 875 * 18 * BYTES_PER_XDR_UNIT of data 876 */ 877 if (ae & 878 (FATTR4_SUPPORTED_ATTRS_MASK | 879 FATTR4_TYPE_MASK | 880 FATTR4_FH_EXPIRE_TYPE_MASK | 881 FATTR4_CHANGE_MASK | 882 FATTR4_SIZE_MASK | 883 FATTR4_LINK_SUPPORT_MASK | 884 FATTR4_SYMLINK_SUPPORT_MASK | 885 FATTR4_NAMED_ATTR_MASK | 886 FATTR4_FSID_MASK | 887 FATTR4_UNIQUE_HANDLES_MASK | 888 FATTR4_LEASE_TIME_MASK | 889 FATTR4_RDATTR_ERROR_MASK)) { 890 891 if (ae & FATTR4_SUPPORTED_ATTRS_MASK) { 892 IXDR_PUT_INT32(ptr, 2); 893 IXDR_PUT_HYPER(ptr, 894 rfs4_supported_attrs); 895 } 896 if (ae & FATTR4_TYPE_MASK) { 897 uint_t ftype = vt_to_nf4[va.va_type]; 898 if (dvp->v_flag & V_XATTRDIR) { 899 if (va.va_type == VDIR) 900 ftype = NF4ATTRDIR; 901 else 902 ftype = NF4NAMEDATTR; 903 } 904 IXDR_PUT_U_INT32(ptr, ftype); 905 } 906 if (ae & FATTR4_FH_EXPIRE_TYPE_MASK) { 907 uint_t expire_type = FH4_PERSISTENT; 908 IXDR_PUT_U_INT32(ptr, expire_type); 909 } 910 if (ae & FATTR4_CHANGE_MASK) { 911 u_longlong_t change; 912 NFS4_SET_FATTR4_CHANGE(change, 913 va.va_ctime); 914 IXDR_PUT_HYPER(ptr, change); 915 } 916 if (ae & FATTR4_SIZE_MASK) { 917 u_longlong_t size = va.va_size; 918 IXDR_PUT_HYPER(ptr, size); 919 } 920 if (ae & FATTR4_LINK_SUPPORT_MASK) { 921 IXDR_PUT_U_INT32(ptr, true); 922 } 923 if (ae & FATTR4_SYMLINK_SUPPORT_MASK) { 924 IXDR_PUT_U_INT32(ptr, true); 925 } 926 if (ae & FATTR4_NAMED_ATTR_MASK) { 927 uint_t isit; 928 pc_val = FALSE; 929 int sattr_error; 930 931 if (!(vp->v_vfsp->vfs_flag & 932 VFS_XATTR)) { 933 isit = FALSE; 934 } else { 935 sattr_error = VOP_PATHCONF(vp, 936 _PC_SATTR_EXISTS, 937 &pc_val, cs->cr, NULL); 938 if (sattr_error || pc_val == 0) 939 (void) VOP_PATHCONF(vp, 940 _PC_XATTR_EXISTS, 941 &pc_val, 942 cs->cr, NULL); 943 } 944 isit = (pc_val ? TRUE : FALSE); 945 IXDR_PUT_U_INT32(ptr, isit); 946 } 947 if (ae & FATTR4_FSID_MASK) { 948 u_longlong_t major, minor; 949 struct exportinfo *exi; 950 951 exi = newexi ? newexi : cs->exi; 952 if (exi->exi_volatile_dev) { 953 int *pmaj = (int *)&major; 954 955 pmaj[0] = exi->exi_fsid.val[0]; 956 pmaj[1] = exi->exi_fsid.val[1]; 957 minor = 0; 958 } else { 959 major = getmajor(va.va_fsid); 960 minor = getminor(va.va_fsid); 961 } 962 IXDR_PUT_HYPER(ptr, major); 963 IXDR_PUT_HYPER(ptr, minor); 964 } 965 if (ae & FATTR4_UNIQUE_HANDLES_MASK) { 966 IXDR_PUT_U_INT32(ptr, false); 967 } 968 if (ae & FATTR4_LEASE_TIME_MASK) { 969 uint_t lt = rfs4_lease_time; 970 IXDR_PUT_U_INT32(ptr, lt); 971 } 972 if (ae & FATTR4_RDATTR_ERROR_MASK) { 973 rddirattr_error = 974 (rddirattr_error == 0 ? 975 0 : puterrno4(rddirattr_error)); 976 IXDR_PUT_U_INT32(ptr, rddirattr_error); 977 } 978 979 /* Check the redzone boundary */ 980 if (ptr > ptr_redzone) { 981 if (nents || IS_MIN_ATTR_MASK(ar)) { 982 no_space = TRUE; 983 continue; 984 } 985 MINIMIZE_ATTR_MASK(ar); 986 ae = ar; 987 ptr = lastentry_ptr; 988 goto reencode_attrs; 989 } 990 } 991 /* 992 * Redzone check is done at the end of this section. 993 * This particular section will encode a maximum of 994 * 4 * BYTES_PER_XDR_UNIT of data. 995 * NOTE: that if ACLs are supported that the 996 * redzone calculations will need to change. 997 */ 998 if (ae & 999 (FATTR4_ACL_MASK | 1000 FATTR4_ACLSUPPORT_MASK | 1001 FATTR4_ARCHIVE_MASK | 1002 FATTR4_CANSETTIME_MASK | 1003 FATTR4_CASE_INSENSITIVE_MASK | 1004 FATTR4_CASE_PRESERVING_MASK | 1005 FATTR4_CHOWN_RESTRICTED_MASK)) { 1006 1007 if (ae & FATTR4_ACL_MASK) { 1008 ASSERT(0); 1009 } 1010 if (ae & FATTR4_ACLSUPPORT_MASK) { 1011 ASSERT(0); 1012 } 1013 if (ae & FATTR4_ARCHIVE_MASK) { 1014 ASSERT(0); 1015 } 1016 if (ae & FATTR4_CANSETTIME_MASK) { 1017 IXDR_PUT_U_INT32(ptr, true); 1018 } 1019 if (ae & FATTR4_CASE_INSENSITIVE_MASK) { 1020 IXDR_PUT_U_INT32(ptr, false); 1021 } 1022 if (ae & FATTR4_CASE_PRESERVING_MASK) { 1023 IXDR_PUT_U_INT32(ptr, true); 1024 } 1025 if (ae & FATTR4_CHOWN_RESTRICTED_MASK) { 1026 uint_t isit; 1027 pc_val = FALSE; 1028 (void) VOP_PATHCONF(vp, 1029 _PC_CHOWN_RESTRICTED, 1030 &pc_val, cs->cr, NULL); 1031 isit = (pc_val ? TRUE : FALSE); 1032 IXDR_PUT_U_INT32(ptr, isit); 1033 } 1034 /* Check the redzone boundary */ 1035 if (ptr > ptr_redzone) { 1036 if (nents || IS_MIN_ATTR_MASK(ar)) { 1037 no_space = TRUE; 1038 continue; 1039 } 1040 MINIMIZE_ATTR_MASK(ar); 1041 ae = ar; 1042 ptr = lastentry_ptr; 1043 goto reencode_attrs; 1044 } 1045 } 1046 /* 1047 * Redzone check is done before the filehandle 1048 * is encoded. 1049 */ 1050 if (ae & 1051 (FATTR4_FILEHANDLE_MASK | 1052 FATTR4_FILEID_MASK)) { 1053 1054 if (ae & FATTR4_FILEHANDLE_MASK) { 1055 struct { 1056 uint_t len; 1057 char *val; 1058 char fh[NFS_FH4_LEN]; 1059 } fh; 1060 fh.len = 0; 1061 fh.val = fh.fh; 1062 (void) makefh4((nfs_fh4 *)&fh, vp, 1063 (newexi ? newexi : cs->exi)); 1064 1065 if (dvp->v_flag & V_XATTRDIR) 1066 set_fh4_flag((nfs_fh4 *)&fh, 1067 FH4_NAMEDATTR); 1068 1069 if (!xdr_inline_encode_nfs_fh4( 1070 &ptr, ptr_redzone, 1071 (nfs_fh4_fmt_t *)fh.val)) { 1072 if (nents || 1073 IS_MIN_ATTR_MASK(ar)) { 1074 no_space = TRUE; 1075 continue; 1076 } 1077 MINIMIZE_ATTR_MASK(ar); 1078 ae = ar; 1079 ptr = lastentry_ptr; 1080 goto reencode_attrs; 1081 } 1082 } 1083 if (ae & FATTR4_FILEID_MASK) { 1084 IXDR_PUT_HYPER(ptr, va.va_nodeid); 1085 } 1086 /* Check the redzone boundary */ 1087 if (ptr > ptr_redzone) { 1088 if (nents || IS_MIN_ATTR_MASK(ar)) { 1089 no_space = TRUE; 1090 continue; 1091 } 1092 MINIMIZE_ATTR_MASK(ar); 1093 ae = ar; 1094 ptr = lastentry_ptr; 1095 goto reencode_attrs; 1096 } 1097 } 1098 /* 1099 * Redzone check is done at the end of this section. 1100 * This particular section will encode a maximum of 1101 * 15 * BYTES_PER_XDR_UNIT of data. 1102 */ 1103 if (ae & 1104 (FATTR4_FILES_AVAIL_MASK | 1105 FATTR4_FILES_FREE_MASK | 1106 FATTR4_FILES_TOTAL_MASK | 1107 FATTR4_FS_LOCATIONS_MASK | 1108 FATTR4_HIDDEN_MASK | 1109 FATTR4_HOMOGENEOUS_MASK | 1110 FATTR4_MAXFILESIZE_MASK | 1111 FATTR4_MAXLINK_MASK | 1112 FATTR4_MAXNAME_MASK | 1113 FATTR4_MAXREAD_MASK | 1114 FATTR4_MAXWRITE_MASK)) { 1115 1116 if (ae & FATTR4_FILES_AVAIL_MASK) { 1117 IXDR_PUT_HYPER(ptr, sbe.fa); 1118 } 1119 if (ae & FATTR4_FILES_FREE_MASK) { 1120 IXDR_PUT_HYPER(ptr, sbe.ff); 1121 } 1122 if (ae & FATTR4_FILES_TOTAL_MASK) { 1123 IXDR_PUT_HYPER(ptr, sbe.ft); 1124 } 1125 if (ae & FATTR4_FS_LOCATIONS_MASK) { 1126 ASSERT(0); 1127 } 1128 if (ae & FATTR4_HIDDEN_MASK) { 1129 ASSERT(0); 1130 } 1131 if (ae & FATTR4_HOMOGENEOUS_MASK) { 1132 IXDR_PUT_U_INT32(ptr, true); 1133 } 1134 if (ae & FATTR4_MAXFILESIZE_MASK) { 1135 IXDR_PUT_HYPER(ptr, pce.maxfilesize); 1136 } 1137 if (ae & FATTR4_MAXLINK_MASK) { 1138 IXDR_PUT_U_INT32(ptr, pce.maxlink); 1139 } 1140 if (ae & FATTR4_MAXNAME_MASK) { 1141 IXDR_PUT_U_INT32(ptr, pce.maxname); 1142 } 1143 if (ae & FATTR4_MAXREAD_MASK) { 1144 IXDR_PUT_HYPER(ptr, maxread); 1145 } 1146 if (ae & FATTR4_MAXWRITE_MASK) { 1147 IXDR_PUT_HYPER(ptr, maxwrite); 1148 } 1149 /* Check the redzone boundary */ 1150 if (ptr > ptr_redzone) { 1151 if (nents || IS_MIN_ATTR_MASK(ar)) { 1152 no_space = TRUE; 1153 continue; 1154 } 1155 MINIMIZE_ATTR_MASK(ar); 1156 ae = ar; 1157 ptr = lastentry_ptr; 1158 goto reencode_attrs; 1159 } 1160 } 1161 } 1162 if (ae & 0x00000000ffffffff) { 1163 /* 1164 * Redzone check is done at the end of this section. 1165 * This particular section will encode a maximum of 1166 * 3 * BYTES_PER_XDR_UNIT of data. 1167 */ 1168 if (ae & 1169 (FATTR4_MIMETYPE_MASK | 1170 FATTR4_MODE_MASK | 1171 FATTR4_NO_TRUNC_MASK | 1172 FATTR4_NUMLINKS_MASK)) { 1173 1174 if (ae & FATTR4_MIMETYPE_MASK) { 1175 ASSERT(0); 1176 } 1177 if (ae & FATTR4_MODE_MASK) { 1178 uint_t m = va.va_mode; 1179 IXDR_PUT_U_INT32(ptr, m); 1180 } 1181 if (ae & FATTR4_NO_TRUNC_MASK) { 1182 IXDR_PUT_U_INT32(ptr, true); 1183 } 1184 if (ae & FATTR4_NUMLINKS_MASK) { 1185 IXDR_PUT_U_INT32(ptr, va.va_nlink); 1186 } 1187 /* Check the redzone boundary */ 1188 if (ptr > ptr_redzone) { 1189 if (nents || IS_MIN_ATTR_MASK(ar)) { 1190 no_space = TRUE; 1191 continue; 1192 } 1193 MINIMIZE_ATTR_MASK(ar); 1194 ae = ar; 1195 ptr = lastentry_ptr; 1196 goto reencode_attrs; 1197 } 1198 } 1199 /* 1200 * Redzone check is done before the encoding of the 1201 * owner string since the length is indeterminate. 1202 */ 1203 if (ae & FATTR4_OWNER_MASK) { 1204 if (!lu_set) { 1205 owner_error = nfs_idmap_uid_str( 1206 va.va_uid, &owner, TRUE); 1207 if (!owner_error) { 1208 lu_set = TRUE; 1209 lastuid = va.va_uid; 1210 } 1211 } else if (va.va_uid != lastuid) { 1212 if (owner.utf8string_len != 0) { 1213 kmem_free(owner.utf8string_val, 1214 owner.utf8string_len); 1215 owner.utf8string_len = 0; 1216 owner.utf8string_val = NULL; 1217 } 1218 owner_error = nfs_idmap_uid_str( 1219 va.va_uid, &owner, TRUE); 1220 if (!owner_error) { 1221 lastuid = va.va_uid; 1222 } else { 1223 lu_set = FALSE; 1224 } 1225 } 1226 if (!owner_error) { 1227 if ((ptr + 1228 (owner.utf8string_len / 1229 BYTES_PER_XDR_UNIT) 1230 + 2) > ptr_redzone) { 1231 if (nents || 1232 IS_MIN_ATTR_MASK(ar)) { 1233 no_space = TRUE; 1234 continue; 1235 } 1236 MINIMIZE_ATTR_MASK(ar); 1237 ae = ar; 1238 ptr = lastentry_ptr; 1239 goto reencode_attrs; 1240 } 1241 /* encode the LENGTH of owner string */ 1242 IXDR_PUT_U_INT32(ptr, 1243 owner.utf8string_len); 1244 /* encode the RNDUP FILL first */ 1245 rndup = RNDUP(owner.utf8string_len) / 1246 BYTES_PER_XDR_UNIT; 1247 ptr[rndup - 1] = 0; 1248 /* encode the OWNER */ 1249 bcopy(owner.utf8string_val, ptr, 1250 owner.utf8string_len); 1251 ptr += rndup; 1252 } 1253 } 1254 /* 1255 * Redzone check is done before the encoding of the 1256 * group string since the length is indeterminate. 1257 */ 1258 if (ae & FATTR4_OWNER_GROUP_MASK) { 1259 if (!lg_set) { 1260 group_error = 1261 nfs_idmap_gid_str(va.va_gid, 1262 &group, TRUE); 1263 if (!group_error) { 1264 lg_set = TRUE; 1265 lastgid = va.va_gid; 1266 } 1267 } else if (va.va_gid != lastgid) { 1268 if (group.utf8string_len != 0) { 1269 kmem_free( 1270 group.utf8string_val, 1271 group.utf8string_len); 1272 group.utf8string_len = 0; 1273 group.utf8string_val = NULL; 1274 } 1275 group_error = 1276 nfs_idmap_gid_str(va.va_gid, 1277 &group, TRUE); 1278 if (!group_error) 1279 lastgid = va.va_gid; 1280 else 1281 lg_set = FALSE; 1282 } 1283 if (!group_error) { 1284 if ((ptr + 1285 (group.utf8string_len / 1286 BYTES_PER_XDR_UNIT) 1287 + 2) > ptr_redzone) { 1288 if (nents || 1289 IS_MIN_ATTR_MASK(ar)) { 1290 no_space = TRUE; 1291 continue; 1292 } 1293 MINIMIZE_ATTR_MASK(ar); 1294 ae = ar; 1295 ptr = lastentry_ptr; 1296 goto reencode_attrs; 1297 } 1298 /* encode the LENGTH of owner string */ 1299 IXDR_PUT_U_INT32(ptr, 1300 group.utf8string_len); 1301 /* encode the RNDUP FILL first */ 1302 rndup = RNDUP(group.utf8string_len) / 1303 BYTES_PER_XDR_UNIT; 1304 ptr[rndup - 1] = 0; 1305 /* encode the OWNER */ 1306 bcopy(group.utf8string_val, ptr, 1307 group.utf8string_len); 1308 ptr += rndup; 1309 } 1310 } 1311 if (ae & 1312 (FATTR4_QUOTA_AVAIL_HARD_MASK | 1313 FATTR4_QUOTA_AVAIL_SOFT_MASK | 1314 FATTR4_QUOTA_USED_MASK)) { 1315 if (ae & FATTR4_QUOTA_AVAIL_HARD_MASK) { 1316 ASSERT(0); 1317 } 1318 if (ae & FATTR4_QUOTA_AVAIL_SOFT_MASK) { 1319 ASSERT(0); 1320 } 1321 if (ae & FATTR4_QUOTA_USED_MASK) { 1322 ASSERT(0); 1323 } 1324 } 1325 /* 1326 * Redzone check is done at the end of this section. 1327 * This particular section will encode a maximum of 1328 * 10 * BYTES_PER_XDR_UNIT of data. 1329 */ 1330 if (ae & 1331 (FATTR4_RAWDEV_MASK | 1332 FATTR4_SPACE_AVAIL_MASK | 1333 FATTR4_SPACE_FREE_MASK | 1334 FATTR4_SPACE_TOTAL_MASK | 1335 FATTR4_SPACE_USED_MASK | 1336 FATTR4_SYSTEM_MASK)) { 1337 1338 if (ae & FATTR4_RAWDEV_MASK) { 1339 fattr4_rawdev rd; 1340 rd.specdata1 = 1341 (uint32)getmajor(va.va_rdev); 1342 rd.specdata2 = 1343 (uint32)getminor(va.va_rdev); 1344 IXDR_PUT_U_INT32(ptr, rd.specdata1); 1345 IXDR_PUT_U_INT32(ptr, rd.specdata2); 1346 } 1347 if (ae & FATTR4_SPACE_AVAIL_MASK) { 1348 IXDR_PUT_HYPER(ptr, sbe.space_avail); 1349 } 1350 if (ae & FATTR4_SPACE_FREE_MASK) { 1351 IXDR_PUT_HYPER(ptr, sbe.space_free); 1352 } 1353 if (ae & FATTR4_SPACE_TOTAL_MASK) { 1354 IXDR_PUT_HYPER(ptr, sbe.space_total); 1355 } 1356 if (ae & FATTR4_SPACE_USED_MASK) { 1357 u_longlong_t su; 1358 su = (fattr4_space_used) DEV_BSIZE * 1359 (fattr4_space_used) va.va_nblocks; 1360 IXDR_PUT_HYPER(ptr, su); 1361 } 1362 if (ae & FATTR4_SYSTEM_MASK) { 1363 ASSERT(0); 1364 } 1365 /* Check the redzone boundary */ 1366 if (ptr > ptr_redzone) { 1367 if (nents || IS_MIN_ATTR_MASK(ar)) { 1368 no_space = TRUE; 1369 continue; 1370 } 1371 MINIMIZE_ATTR_MASK(ar); 1372 ae = ar; 1373 ptr = lastentry_ptr; 1374 goto reencode_attrs; 1375 } 1376 } 1377 /* 1378 * Redzone check is done at the end of this section. 1379 * This particular section will encode a maximum of 1380 * 14 * BYTES_PER_XDR_UNIT of data. 1381 */ 1382 if (ae & 1383 (FATTR4_TIME_ACCESS_MASK | 1384 FATTR4_TIME_ACCESS_SET_MASK | 1385 FATTR4_TIME_BACKUP_MASK | 1386 FATTR4_TIME_CREATE_MASK | 1387 FATTR4_TIME_DELTA_MASK | 1388 FATTR4_TIME_METADATA_MASK | 1389 FATTR4_TIME_MODIFY_MASK | 1390 FATTR4_TIME_MODIFY_SET_MASK | 1391 FATTR4_MOUNTED_ON_FILEID_MASK)) { 1392 1393 if (ae & FATTR4_TIME_ACCESS_MASK) { 1394 u_longlong_t sec = 1395 (u_longlong_t)va.va_atime.tv_sec; 1396 uint_t nsec = 1397 (uint_t)va.va_atime.tv_nsec; 1398 IXDR_PUT_HYPER(ptr, sec); 1399 IXDR_PUT_INT32(ptr, nsec); 1400 } 1401 if (ae & FATTR4_TIME_ACCESS_SET_MASK) { 1402 ASSERT(0); 1403 } 1404 if (ae & FATTR4_TIME_BACKUP_MASK) { 1405 ASSERT(0); 1406 } 1407 if (ae & FATTR4_TIME_CREATE_MASK) { 1408 ASSERT(0); 1409 } 1410 if (ae & FATTR4_TIME_DELTA_MASK) { 1411 u_longlong_t sec = 0; 1412 uint_t nsec = 1000; 1413 IXDR_PUT_HYPER(ptr, sec); 1414 IXDR_PUT_INT32(ptr, nsec); 1415 } 1416 if (ae & FATTR4_TIME_METADATA_MASK) { 1417 u_longlong_t sec = 1418 (u_longlong_t)va.va_ctime.tv_sec; 1419 uint_t nsec = 1420 (uint_t)va.va_ctime.tv_nsec; 1421 IXDR_PUT_HYPER(ptr, sec); 1422 IXDR_PUT_INT32(ptr, nsec); 1423 } 1424 if (ae & FATTR4_TIME_MODIFY_MASK) { 1425 u_longlong_t sec = 1426 (u_longlong_t)va.va_mtime.tv_sec; 1427 uint_t nsec = 1428 (uint_t)va.va_mtime.tv_nsec; 1429 IXDR_PUT_HYPER(ptr, sec); 1430 IXDR_PUT_INT32(ptr, nsec); 1431 } 1432 if (ae & FATTR4_TIME_MODIFY_SET_MASK) { 1433 ASSERT(0); 1434 } 1435 if (ae & FATTR4_MOUNTED_ON_FILEID_MASK) { 1436 IXDR_PUT_HYPER(ptr, dp->d_ino); 1437 } 1438 /* Check the redzone boundary */ 1439 if (ptr > ptr_redzone) { 1440 if (nents || IS_MIN_ATTR_MASK(ar)) { 1441 no_space = TRUE; 1442 continue; 1443 } 1444 MINIMIZE_ATTR_MASK(ar); 1445 ae = ar; 1446 ptr = lastentry_ptr; 1447 goto reencode_attrs; 1448 } 1449 } 1450 } 1451 1452 /* Reset to directory's vfs info when encoding complete */ 1453 if (vfs_different) { 1454 dsbe = sbe; 1455 dpce = pce; 1456 vfs_different = 0; 1457 } 1458 1459 /* "go back" and encode the attributes' length */ 1460 attr_length = 1461 (char *)ptr - 1462 (char *)attr_offset_ptr - 1463 BYTES_PER_XDR_UNIT; 1464 IXDR_PUT_U_INT32(attr_offset_ptr, attr_length); 1465 1466 /* 1467 * If there was trouble obtaining a mapping for either 1468 * the owner or group attributes, then remove them from 1469 * bitmap4 for this entry and reset the bitmap value 1470 * in the data stream. 1471 */ 1472 if (owner_error || group_error) { 1473 if (owner_error) 1474 ae &= ~FATTR4_OWNER_MASK; 1475 if (group_error) 1476 ae &= ~FATTR4_OWNER_GROUP_MASK; 1477 IXDR_PUT_HYPER(attrmask_ptr, ae); 1478 } 1479 1480 /* END OF ATTRIBUTE ENCODING */ 1481 1482 lastentry_ptr = ptr; 1483 nents++; 1484 rddir_next_offset = dp->d_off; 1485 } 1486 1487 /* 1488 * Check for the case that another VOP_READDIR() has to be done. 1489 * - no space encoding error 1490 * - no entry successfully encoded 1491 * - still more directory to read 1492 */ 1493 if (!no_space && nents == 0 && !iseofdir) 1494 goto readagain; 1495 1496 *cs->statusp = resp->status = NFS4_OK; 1497 1498 /* 1499 * If no_space is set then we terminated prematurely, 1500 * rewind to the last entry and this can never be EOF. 1501 */ 1502 if (no_space) { 1503 ptr = lastentry_ptr; 1504 eof = FALSE; /* ended encoded prematurely */ 1505 } else { 1506 eof = (iseofdir ? TRUE : FALSE); 1507 } 1508 1509 /* 1510 * If we have entries, always return them, otherwise only error 1511 * if we ran out of space. 1512 */ 1513 if (nents || !no_space) { 1514 ASSERT(ptr != NULL); 1515 /* encode the BOOLEAN marking no further entries */ 1516 IXDR_PUT_U_INT32(ptr, false); 1517 /* encode the BOOLEAN signifying end of directory */ 1518 IXDR_PUT_U_INT32(ptr, eof); 1519 1520 resp->data_len = (char *)ptr - (char *)beginning_ptr; 1521 resp->mblk->b_wptr += resp->data_len; 1522 } else { 1523 freeb(mp); 1524 resp->mblk = NULL; 1525 resp->data_len = 0; 1526 *cs->statusp = resp->status = NFS4ERR_TOOSMALL; 1527 } 1528 1529 kmem_free((caddr_t)rddir_data, rddir_data_len); 1530 if (vp) 1531 VN_RELE(vp); 1532 if (owner.utf8string_len != 0) 1533 kmem_free(owner.utf8string_val, owner.utf8string_len); 1534 if (group.utf8string_len != 0) 1535 kmem_free(group.utf8string_val, group.utf8string_len); 1536 1537 out: 1538 DTRACE_NFSV4_2(op__readdir__done, struct compound_state *, cs, 1539 READDIR4res *, resp); 1540 } 1541