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