xref: /titanic_44/usr/src/uts/common/fs/cachefs/cachefs_dir.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*da6c28aaSamw  * Common Development and Distribution License (the "License").
6*da6c28aaSamw  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*da6c28aaSamw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <sys/param.h>
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <sys/systm.h>
307c478bd9Sstevel@tonic-gate #include <sys/cred.h>
317c478bd9Sstevel@tonic-gate #include <sys/proc.h>
327c478bd9Sstevel@tonic-gate #include <sys/user.h>
337c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
347c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
357c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
367c478bd9Sstevel@tonic-gate #include <sys/uio.h>
377c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
387c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
397c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
407c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
417c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
427c478bd9Sstevel@tonic-gate #include <sys/errno.h>
437c478bd9Sstevel@tonic-gate #include <sys/debug.h>
447c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
457c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
467c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
477c478bd9Sstevel@tonic-gate #include <sys/dirent.h>
487c478bd9Sstevel@tonic-gate #include <sys/fbuf.h>
497c478bd9Sstevel@tonic-gate #include <rpc/types.h>
507c478bd9Sstevel@tonic-gate #include <vm/seg.h>
517c478bd9Sstevel@tonic-gate #include <vm/faultcode.h>
527c478bd9Sstevel@tonic-gate #include <vm/hat.h>
537c478bd9Sstevel@tonic-gate #include <vm/seg_map.h>
547c478bd9Sstevel@tonic-gate #include <sys/fs/cachefs_fs.h>
557c478bd9Sstevel@tonic-gate #include <sys/fs/cachefs_dir.h>
567c478bd9Sstevel@tonic-gate #include <sys/fs/cachefs_log.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /* forward declarations */
597c478bd9Sstevel@tonic-gate static int cachefs_dir_getentrys(struct cnode *, u_offset_t, u_offset_t *,
607c478bd9Sstevel@tonic-gate     uint_t *, uint_t, caddr_t, int *);
617c478bd9Sstevel@tonic-gate static int cachefs_dir_stuff(cnode_t *dcp, uint_t count, caddr_t buf,
627c478bd9Sstevel@tonic-gate     vnode_t *frontvp, u_offset_t *offsetp, u_offset_t *fsizep);
637c478bd9Sstevel@tonic-gate static int cachefs_dir_extend(cnode_t *, u_offset_t *, int incr_frontblks);
647c478bd9Sstevel@tonic-gate static int cachefs_dir_fill_common(cnode_t *dcp, cred_t *cr,
657c478bd9Sstevel@tonic-gate     vnode_t *frontvp, vnode_t *backvp, u_offset_t *frontsize);
667c478bd9Sstevel@tonic-gate static int cachefs_dir_complete(fscache_t *fscp, vnode_t *backvp,
677c478bd9Sstevel@tonic-gate     vnode_t *frontvp, cred_t *cr, int acltoo);
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate  * cachefs_dir_look() called mainly by lookup (and create), looks up the cached
737c478bd9Sstevel@tonic-gate  * directory for an entry and returns the information there. If the directory
747c478bd9Sstevel@tonic-gate  * entry doesn't exist return ENOENT, if it is incomplete, return EINVAL.
757c478bd9Sstevel@tonic-gate  * Should only call this routine if the dir is populated.
767c478bd9Sstevel@tonic-gate  * Returns ENOTDIR if dir gets nuked because of front file problems.
777c478bd9Sstevel@tonic-gate  */
787c478bd9Sstevel@tonic-gate int
cachefs_dir_look(cnode_t * dcp,char * nm,fid_t * cookiep,uint_t * flagp,u_offset_t * d_offsetp,cfs_cid_t * cidp)797c478bd9Sstevel@tonic-gate cachefs_dir_look(cnode_t *dcp, char *nm, fid_t *cookiep, uint_t *flagp,
807c478bd9Sstevel@tonic-gate     u_offset_t *d_offsetp, cfs_cid_t *cidp)
817c478bd9Sstevel@tonic-gate {
827c478bd9Sstevel@tonic-gate 	int error;
837c478bd9Sstevel@tonic-gate 	struct vattr va;
847c478bd9Sstevel@tonic-gate 	u_offset_t blockoff = 0LL;
857c478bd9Sstevel@tonic-gate 	uint_t offset = 0; /* offset inside the block of size MAXBSIZE */
867c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
877c478bd9Sstevel@tonic-gate 	struct fscache *fscp = C_TO_FSCACHE(dcp);
887c478bd9Sstevel@tonic-gate 	cachefscache_t *cachep = fscp->fs_cache;
897c478bd9Sstevel@tonic-gate 	int nmlen;
907c478bd9Sstevel@tonic-gate 	struct fbuf *fbp;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
937c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
947c478bd9Sstevel@tonic-gate 		printf("cachefs_dir_look: ENTER dcp %p nm %s\n", (void *)dcp,
957c478bd9Sstevel@tonic-gate 									nm);
967c478bd9Sstevel@tonic-gate #endif
977c478bd9Sstevel@tonic-gate 	ASSERT(CTOV(dcp)->v_type == VDIR);
987c478bd9Sstevel@tonic-gate 	ASSERT(dcp->c_metadata.md_flags & MD_POPULATED);
997c478bd9Sstevel@tonic-gate 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	if (dcp->c_frontvp == NULL)
1027c478bd9Sstevel@tonic-gate 		(void) cachefs_getfrontfile(dcp);
1037c478bd9Sstevel@tonic-gate 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
1047c478bd9Sstevel@tonic-gate 		error = ENOTDIR;
1057c478bd9Sstevel@tonic-gate 		goto out;
1067c478bd9Sstevel@tonic-gate 	}
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	dvp = dcp->c_frontvp;
1097c478bd9Sstevel@tonic-gate 	va.va_mask = AT_SIZE;		/* XXX should save dir size */
110*da6c28aaSamw 	error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
1117c478bd9Sstevel@tonic-gate 	if (error) {
1127c478bd9Sstevel@tonic-gate 		cachefs_inval_object(dcp);
1137c478bd9Sstevel@tonic-gate 		error = ENOTDIR;
1147c478bd9Sstevel@tonic-gate 		goto out;
1157c478bd9Sstevel@tonic-gate 	}
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	ASSERT(va.va_size != 0LL);
1187c478bd9Sstevel@tonic-gate 	nmlen = (int)strlen(nm);
1197c478bd9Sstevel@tonic-gate 	while (blockoff < va.va_size) {
1207c478bd9Sstevel@tonic-gate 		offset = 0;
1217c478bd9Sstevel@tonic-gate 		error =
1227c478bd9Sstevel@tonic-gate 		    fbread(dvp, (offset_t)blockoff, MAXBSIZE, S_OTHER, &fbp);
1237c478bd9Sstevel@tonic-gate 		if (error)
1247c478bd9Sstevel@tonic-gate 			goto out;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 		while (offset < MAXBSIZE && (blockoff + offset) < va.va_size) {
1277c478bd9Sstevel@tonic-gate 			struct c_dirent *dep;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 			dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr +
1307c478bd9Sstevel@tonic-gate 								offset);
1317c478bd9Sstevel@tonic-gate 			if ((dep->d_flag & CDE_VALID) &&
1327c478bd9Sstevel@tonic-gate 				(nmlen == dep->d_namelen) &&
1337c478bd9Sstevel@tonic-gate 				strcmp(dep->d_name, nm) == 0) {
1347c478bd9Sstevel@tonic-gate 				if (dep->d_flag & CDE_COMPLETE) {
1357c478bd9Sstevel@tonic-gate 					if (cookiep) {
1367c478bd9Sstevel@tonic-gate 						CACHEFS_FID_COPY(&dep->d_cookie,
1377c478bd9Sstevel@tonic-gate 							cookiep);
1387c478bd9Sstevel@tonic-gate 					}
1397c478bd9Sstevel@tonic-gate 					if (flagp)
1407c478bd9Sstevel@tonic-gate 						*flagp = dep->d_flag;
1417c478bd9Sstevel@tonic-gate 					error = 0;
1427c478bd9Sstevel@tonic-gate 				} else {
1437c478bd9Sstevel@tonic-gate 					error = EINVAL;
1447c478bd9Sstevel@tonic-gate 				}
1457c478bd9Sstevel@tonic-gate 				if (cidp)
1467c478bd9Sstevel@tonic-gate 					*cidp = dep->d_id;
1477c478bd9Sstevel@tonic-gate 				if (d_offsetp)
1487c478bd9Sstevel@tonic-gate 					*d_offsetp = offset + blockoff;
1497c478bd9Sstevel@tonic-gate 				fbrelse(fbp, S_OTHER);
1507c478bd9Sstevel@tonic-gate 				goto out;
1517c478bd9Sstevel@tonic-gate 			}
1527c478bd9Sstevel@tonic-gate 			ASSERT(dep->d_length != 0);
1537c478bd9Sstevel@tonic-gate 			offset += dep->d_length;
1547c478bd9Sstevel@tonic-gate 		}
1557c478bd9Sstevel@tonic-gate 		fbrelse(fbp, S_OTHER);
1567c478bd9Sstevel@tonic-gate 		blockoff += MAXBSIZE;
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 	error = ENOENT;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate out:
1617c478bd9Sstevel@tonic-gate 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_RFDIR))
1627c478bd9Sstevel@tonic-gate 		cachefs_log_rfdir(cachep, error, fscp->fs_cfsvfsp,
1637c478bd9Sstevel@tonic-gate 		    &dcp->c_metadata.md_cookie, dcp->c_id.cid_fileno, 0);
1647c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
1657c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
1667c478bd9Sstevel@tonic-gate 		printf("c_dir_look: EXIT error = %d\n", error);
1677c478bd9Sstevel@tonic-gate #endif
1687c478bd9Sstevel@tonic-gate 	return (error);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate /*
1727c478bd9Sstevel@tonic-gate  * creates a new directory and populates it with "." and ".."
1737c478bd9Sstevel@tonic-gate  */
1747c478bd9Sstevel@tonic-gate int
cachefs_dir_new(cnode_t * dcp,cnode_t * cp)1757c478bd9Sstevel@tonic-gate cachefs_dir_new(cnode_t *dcp, cnode_t *cp)
1767c478bd9Sstevel@tonic-gate {
1777c478bd9Sstevel@tonic-gate 	int		error = 0;
1787c478bd9Sstevel@tonic-gate 	struct c_dirent	*dep;
1797c478bd9Sstevel@tonic-gate 	u_offset_t	size;
1807c478bd9Sstevel@tonic-gate 	int len;
1817c478bd9Sstevel@tonic-gate 	struct fbuf	*fbp;
1827c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
1837c478bd9Sstevel@tonic-gate 	struct vattr	va;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
1867c478bd9Sstevel@tonic-gate 		printf("c_dir_new: ENTER dcp %p cp %p\n", (void *)dcp,
1877c478bd9Sstevel@tonic-gate 							(void *)cp);
1887c478bd9Sstevel@tonic-gate #endif
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cp->c_statelock));
1917c478bd9Sstevel@tonic-gate 	ASSERT(CTOV(cp)->v_type == VDIR);
1927c478bd9Sstevel@tonic-gate 	ASSERT((cp->c_flags & CN_ASYNC_POPULATE) == 0);
1937c478bd9Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(dcp)) == 0);
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	if (cp->c_frontvp == NULL) {
1967c478bd9Sstevel@tonic-gate 		error = cachefs_getfrontfile(cp);
1977c478bd9Sstevel@tonic-gate 		if (error)
1987c478bd9Sstevel@tonic-gate 			goto out;
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
2027c478bd9Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
203*da6c28aaSamw 	error = VOP_GETATTR(cp->c_frontvp, &va, 0, kcred, NULL);
2047c478bd9Sstevel@tonic-gate 	if (error)
2057c478bd9Sstevel@tonic-gate 		goto out;
2067c478bd9Sstevel@tonic-gate 	ASSERT(va.va_size == 0);
2077c478bd9Sstevel@tonic-gate #endif
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	/*
2107c478bd9Sstevel@tonic-gate 	 * Extend the directory by one MAXBSIZE chunk
2117c478bd9Sstevel@tonic-gate 	 */
2127c478bd9Sstevel@tonic-gate 	size = 0LL;
2137c478bd9Sstevel@tonic-gate 	error = cachefs_dir_extend(cp, &size, 1);
2147c478bd9Sstevel@tonic-gate 	if (error != 0)
2157c478bd9Sstevel@tonic-gate 		goto out;
2167c478bd9Sstevel@tonic-gate 	error = fbread(cp->c_frontvp, (offset_t)0, MAXBSIZE, S_OTHER, &fbp);
2177c478bd9Sstevel@tonic-gate 	if (error)
2187c478bd9Sstevel@tonic-gate 		goto out;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	/*
2217c478bd9Sstevel@tonic-gate 	 * Insert "." and ".."
2227c478bd9Sstevel@tonic-gate 	 */
2237c478bd9Sstevel@tonic-gate 	len = (int)CDE_SIZE(".");
2247c478bd9Sstevel@tonic-gate 	dep = (struct c_dirent *)fbp->fb_addr;
2257c478bd9Sstevel@tonic-gate 	dep->d_length = len;
2267c478bd9Sstevel@tonic-gate 	dep->d_offset = (offset_t)len;
2277c478bd9Sstevel@tonic-gate 	dep->d_flag = CDE_VALID | CDE_COMPLETE;
2287c478bd9Sstevel@tonic-gate 	CACHEFS_FID_COPY(&cp->c_cookie, &dep->d_cookie);
2297c478bd9Sstevel@tonic-gate 	dep->d_id = cp->c_id;
2307c478bd9Sstevel@tonic-gate 	dep->d_namelen = 1;
2317c478bd9Sstevel@tonic-gate 	bcopy(".", dep->d_name, 2);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + len);
2347c478bd9Sstevel@tonic-gate 	dep->d_length = MAXBSIZE - len;
2357c478bd9Sstevel@tonic-gate 	dep->d_offset = MAXBSIZE;
2367c478bd9Sstevel@tonic-gate 	dep->d_flag = CDE_VALID | CDE_COMPLETE;
2377c478bd9Sstevel@tonic-gate 	CACHEFS_FID_COPY(&dcp->c_cookie, &dep->d_cookie);
2387c478bd9Sstevel@tonic-gate 	dep->d_id = dcp->c_id;
2397c478bd9Sstevel@tonic-gate 	dep->d_namelen = 2;
2407c478bd9Sstevel@tonic-gate 	bcopy("..", dep->d_name, 3);
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	(void) fbdwrite(fbp);
2437c478bd9Sstevel@tonic-gate #ifdef INVALREADDIR
2447c478bd9Sstevel@tonic-gate 	cp->c_metadata.md_flags |= MD_POPULATED | MD_INVALREADDIR;
2457c478bd9Sstevel@tonic-gate #else
2467c478bd9Sstevel@tonic-gate 	cp->c_metadata.md_flags |= MD_POPULATED;
2477c478bd9Sstevel@tonic-gate #endif
2487c478bd9Sstevel@tonic-gate 	cp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
2497c478bd9Sstevel@tonic-gate out:
2507c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
2517c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
2527c478bd9Sstevel@tonic-gate 		printf("cachefs_dir_new: EXIT error = %d\n", error);
2537c478bd9Sstevel@tonic-gate #endif
2547c478bd9Sstevel@tonic-gate 	return (error);
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate  * cachefs_dir_enter adds a new directory entry. Takes as input a fid,
2597c478bd9Sstevel@tonic-gate  * fileno and a sync flag. Most of the time, the caller is content with the
2607c478bd9Sstevel@tonic-gate  * write to the (front) directory being done async. The exception being - for
2617c478bd9Sstevel@tonic-gate  * local files, we should make sure that the directory entry is made
2627c478bd9Sstevel@tonic-gate  * synchronously. That is notified by the caller.
2637c478bd9Sstevel@tonic-gate  * 		issync == 0 || issync == SM_ASYNC !
2647c478bd9Sstevel@tonic-gate  *
2657c478bd9Sstevel@tonic-gate  * The new entry is inserted at the end, so that we can generate local offsets
2667c478bd9Sstevel@tonic-gate  * which are compatible with the backfs offsets (which are used when
2677c478bd9Sstevel@tonic-gate  * disconnected.
2687c478bd9Sstevel@tonic-gate  */
2697c478bd9Sstevel@tonic-gate int
cachefs_dir_enter(cnode_t * dcp,char * nm,fid_t * cookiep,cfs_cid_t * cidp,int issync)2707c478bd9Sstevel@tonic-gate cachefs_dir_enter(cnode_t *dcp, char *nm, fid_t *cookiep, cfs_cid_t *cidp,
2717c478bd9Sstevel@tonic-gate     int issync)
2727c478bd9Sstevel@tonic-gate {
2737c478bd9Sstevel@tonic-gate 	struct vattr	va;
2747c478bd9Sstevel@tonic-gate 	int offset;
2757c478bd9Sstevel@tonic-gate 	u_offset_t blockoff = 0LL;
2767c478bd9Sstevel@tonic-gate 	u_offset_t	prev_offset;
2777c478bd9Sstevel@tonic-gate 	int		error = 0;
2787c478bd9Sstevel@tonic-gate 	vnode_t		*dvp;
2797c478bd9Sstevel@tonic-gate 	struct c_dirent	*dep;
2807c478bd9Sstevel@tonic-gate 	uint_t		esize;
2817c478bd9Sstevel@tonic-gate 	u_offset_t	dirsize;
2827c478bd9Sstevel@tonic-gate 	struct fbuf	*fbp;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
2857c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
2867c478bd9Sstevel@tonic-gate 		printf("c_dir_enter: ENTER dcp %p nm %s dirflg %x\n",
2877c478bd9Sstevel@tonic-gate 			(void *)dcp, nm, dcp->c_metadata.md_flags);
2887c478bd9Sstevel@tonic-gate #endif
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dcp->c_statelock));
2917c478bd9Sstevel@tonic-gate 	ASSERT(dcp->c_metadata.md_flags & MD_POPULATED);
2927c478bd9Sstevel@tonic-gate 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
2937c478bd9Sstevel@tonic-gate 	ASSERT(CTOV(dcp)->v_type == VDIR);
2947c478bd9Sstevel@tonic-gate 	ASSERT(issync == 0 || issync == SM_ASYNC);
2957c478bd9Sstevel@tonic-gate 	ASSERT(strlen(nm) <= MAXNAMELEN);
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	if (dcp->c_frontvp == NULL)
2987c478bd9Sstevel@tonic-gate 		(void) cachefs_getfrontfile(dcp);
2997c478bd9Sstevel@tonic-gate 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
3007c478bd9Sstevel@tonic-gate 		error = ENOTDIR;
3017c478bd9Sstevel@tonic-gate 		goto out;
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 	dvp = dcp->c_frontvp;
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	/*
3067c478bd9Sstevel@tonic-gate 	 * Get the current EOF for the directory(data file)
3077c478bd9Sstevel@tonic-gate 	 */
3087c478bd9Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
309*da6c28aaSamw 	error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
3107c478bd9Sstevel@tonic-gate 	if (error) {
3117c478bd9Sstevel@tonic-gate 		cachefs_inval_object(dcp);
3127c478bd9Sstevel@tonic-gate 		error = ENOTDIR;
3137c478bd9Sstevel@tonic-gate 		goto out;
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	/*
3177c478bd9Sstevel@tonic-gate 	 * Get the last block of the directory
3187c478bd9Sstevel@tonic-gate 	 */
3197c478bd9Sstevel@tonic-gate 	dirsize = va.va_size;
3207c478bd9Sstevel@tonic-gate 	ASSERT(dirsize != 0LL);
3217c478bd9Sstevel@tonic-gate 	ASSERT(!(dirsize & MAXBOFFSET));
3227c478bd9Sstevel@tonic-gate 	ASSERT(dirsize <= MAXOFF_T);
3237c478bd9Sstevel@tonic-gate 	blockoff = dirsize - MAXBSIZE;
3247c478bd9Sstevel@tonic-gate 	error = fbread(dvp, (offset_t)blockoff, MAXBSIZE, S_OTHER, &fbp);
3257c478bd9Sstevel@tonic-gate 	if (error)
3267c478bd9Sstevel@tonic-gate 		goto out;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	/*
3297c478bd9Sstevel@tonic-gate 	 * Find the last entry
3307c478bd9Sstevel@tonic-gate 	 */
3317c478bd9Sstevel@tonic-gate 	offset = 0;
3327c478bd9Sstevel@tonic-gate 	prev_offset = blockoff;
3337c478bd9Sstevel@tonic-gate 	for (;;) {
3347c478bd9Sstevel@tonic-gate 		dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + offset);
3357c478bd9Sstevel@tonic-gate 		if (offset + dep->d_length == MAXBSIZE)
3367c478bd9Sstevel@tonic-gate 			break;
3377c478bd9Sstevel@tonic-gate 		prev_offset = dep->d_offset;
3387c478bd9Sstevel@tonic-gate 		offset += dep->d_length;
3397c478bd9Sstevel@tonic-gate 		ASSERT(offset < MAXBSIZE);
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 	esize = C_DIRSIZ(dep);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	if (dep->d_length - esize >= CDE_SIZE(nm)) {
3447c478bd9Sstevel@tonic-gate 		/*
3457c478bd9Sstevel@tonic-gate 		 * It has room. If the entry is not valid, we can just use
3467c478bd9Sstevel@tonic-gate 		 * it. Otherwise, we need to adjust its length and offset
3477c478bd9Sstevel@tonic-gate 		 */
3487c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
3497c478bd9Sstevel@tonic-gate 		CFS_DEBUG(CFSDEBUG_DIR) {
3507c478bd9Sstevel@tonic-gate 			if (prev_offset >= dep->d_offset) {
3517c478bd9Sstevel@tonic-gate 				printf("cachefs_dir_enter: looks like "
3527c478bd9Sstevel@tonic-gate 				    "we might fail the assert\n");
3537c478bd9Sstevel@tonic-gate 				printf("addr %p, offset %x, "
3547c478bd9Sstevel@tonic-gate 				    "prev_offset %llx, dep->d_offset %llx\n",
3557c478bd9Sstevel@tonic-gate 				    (void *)fbp->fb_addr, offset, prev_offset,
3567c478bd9Sstevel@tonic-gate 				    dep->d_offset);
3577c478bd9Sstevel@tonic-gate 				offset = 0;
3587c478bd9Sstevel@tonic-gate 				prev_offset = blockoff;
3597c478bd9Sstevel@tonic-gate 				for (;;) {
3607c478bd9Sstevel@tonic-gate 					dep = (struct c_dirent *)
3617c478bd9Sstevel@tonic-gate 					    ((uintptr_t)fbp->fb_addr + offset);
3627c478bd9Sstevel@tonic-gate 					printf("offset %x, prev_offset %llx\n",
3637c478bd9Sstevel@tonic-gate 					    offset, prev_offset);
3647c478bd9Sstevel@tonic-gate 					printf("dep->d_offset %llx, "
3657c478bd9Sstevel@tonic-gate 					    "dep->d_length %x\n",
3667c478bd9Sstevel@tonic-gate 					    dep->d_offset, dep->d_length);
3677c478bd9Sstevel@tonic-gate 					if (offset + dep->d_length == MAXBSIZE)
3687c478bd9Sstevel@tonic-gate 						break;
3697c478bd9Sstevel@tonic-gate 					prev_offset = dep->d_offset;
3707c478bd9Sstevel@tonic-gate 					offset += dep->d_length;
3717c478bd9Sstevel@tonic-gate 				}
3727c478bd9Sstevel@tonic-gate 			}
3737c478bd9Sstevel@tonic-gate 		}
3747c478bd9Sstevel@tonic-gate #endif /* CFSDEBUG */
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 		if (offset)
3777c478bd9Sstevel@tonic-gate 			ASSERT(prev_offset < dep->d_offset);
3787c478bd9Sstevel@tonic-gate 		if (dep->d_flag & CDE_VALID) {
3797c478bd9Sstevel@tonic-gate 			dep->d_length = esize;
3807c478bd9Sstevel@tonic-gate 			dep->d_offset = prev_offset + (u_offset_t)esize;
3817c478bd9Sstevel@tonic-gate 			dep = (struct c_dirent *)((uintptr_t)dep + esize);
3827c478bd9Sstevel@tonic-gate 		}
3837c478bd9Sstevel@tonic-gate 		dep->d_length = (int)((offset_t)MAXBSIZE -
3847c478bd9Sstevel@tonic-gate 				((uintptr_t)dep - (uintptr_t)fbp->fb_addr));
3857c478bd9Sstevel@tonic-gate 	} else {
3867c478bd9Sstevel@tonic-gate 		/*
3877c478bd9Sstevel@tonic-gate 		 * No room - so extend the file by one more
3887c478bd9Sstevel@tonic-gate 		 * MAXBSIZE chunk, and fit the entry there.
3897c478bd9Sstevel@tonic-gate 		 */
3907c478bd9Sstevel@tonic-gate 		fbrelse(fbp, S_OTHER);
3917c478bd9Sstevel@tonic-gate 		error = cachefs_dir_extend(dcp, &dirsize, 1);
3927c478bd9Sstevel@tonic-gate 		if (error != 0)
3937c478bd9Sstevel@tonic-gate 			goto out;
3947c478bd9Sstevel@tonic-gate 		error =
3957c478bd9Sstevel@tonic-gate 		    fbread(dvp, (offset_t)va.va_size, MAXBSIZE, S_OTHER, &fbp);
3967c478bd9Sstevel@tonic-gate 		if (error)
3977c478bd9Sstevel@tonic-gate 			goto out;
3987c478bd9Sstevel@tonic-gate 		dep = (struct c_dirent *)fbp->fb_addr;
3997c478bd9Sstevel@tonic-gate 		dep->d_length = MAXBSIZE;
4007c478bd9Sstevel@tonic-gate 	}
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	/*
4037c478bd9Sstevel@tonic-gate 	 * Fill in the rest of the new entry
4047c478bd9Sstevel@tonic-gate 	 */
4057c478bd9Sstevel@tonic-gate 	dep->d_offset = dirsize;
4067c478bd9Sstevel@tonic-gate 	dep->d_flag = CDE_VALID;
4077c478bd9Sstevel@tonic-gate 	if (cookiep) {
4087c478bd9Sstevel@tonic-gate 		dep->d_flag |= CDE_COMPLETE;
4097c478bd9Sstevel@tonic-gate 		CACHEFS_FID_COPY(cookiep, &dep->d_cookie);
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 	dep->d_id = *cidp;
4127c478bd9Sstevel@tonic-gate 	dep->d_namelen = (ushort_t)strlen(nm);
4137c478bd9Sstevel@tonic-gate 	(void) bcopy(nm, dep->d_name, dep->d_namelen + 1);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate #ifdef INVALREADDIR
4167c478bd9Sstevel@tonic-gate 	dcp->c_metadata.md_flags |= MD_INVALREADDIR;
4177c478bd9Sstevel@tonic-gate #endif
4187c478bd9Sstevel@tonic-gate 	dcp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
4197c478bd9Sstevel@tonic-gate 	if (issync)
4207c478bd9Sstevel@tonic-gate 		(void) fbwrite(fbp);
4217c478bd9Sstevel@tonic-gate 	else
4227c478bd9Sstevel@tonic-gate 		(void) fbdwrite(fbp);
4237c478bd9Sstevel@tonic-gate out:
4247c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
4257c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
4267c478bd9Sstevel@tonic-gate 		printf("cachefs_dir_enter: EXIT error = %d\n", error);
4277c478bd9Sstevel@tonic-gate #endif
4287c478bd9Sstevel@tonic-gate 	return (error);
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate /*
4327c478bd9Sstevel@tonic-gate  * Quite simple, if the deleted entry is the first in the MAXBSIZE block,
4337c478bd9Sstevel@tonic-gate  * we simply mark it invalid. Otherwise, the deleted entries d_length is
4347c478bd9Sstevel@tonic-gate  * just added to the previous entry.
4357c478bd9Sstevel@tonic-gate  */
4367c478bd9Sstevel@tonic-gate int
cachefs_dir_rmentry(cnode_t * dcp,char * nm)4377c478bd9Sstevel@tonic-gate cachefs_dir_rmentry(cnode_t *dcp, char *nm)
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate 	u_offset_t blockoff = 0LL;
4407c478bd9Sstevel@tonic-gate 	int offset = 0;
4417c478bd9Sstevel@tonic-gate 	struct vattr va;
4427c478bd9Sstevel@tonic-gate 	int error = ENOENT;
4437c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
4447c478bd9Sstevel@tonic-gate 	int nmlen;
4457c478bd9Sstevel@tonic-gate 	struct fbuf *fbp;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
4487c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
4497c478bd9Sstevel@tonic-gate 		printf("cachefs_dir_rmentry: ENTER dcp %p nm %s\n",
4507c478bd9Sstevel@tonic-gate 		    (void *)dcp, nm);
4517c478bd9Sstevel@tonic-gate #endif
4527c478bd9Sstevel@tonic-gate 	ASSERT(dcp->c_metadata.md_flags & MD_POPULATED);
4537c478bd9Sstevel@tonic-gate 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	if (dcp->c_frontvp == NULL)
4567c478bd9Sstevel@tonic-gate 		(void) cachefs_getfrontfile(dcp);
4577c478bd9Sstevel@tonic-gate 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
4587c478bd9Sstevel@tonic-gate 		error = ENOTDIR;
4597c478bd9Sstevel@tonic-gate 		goto out;
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate 	dvp = dcp->c_frontvp;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	ASSERT(CTOV(dcp)->v_type == VDIR);
4647c478bd9Sstevel@tonic-gate 	ASSERT((dcp->c_flags & CN_NOCACHE) == 0);
4657c478bd9Sstevel@tonic-gate 	ASSERT(dvp != NULL);
4667c478bd9Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
467*da6c28aaSamw 	error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
4687c478bd9Sstevel@tonic-gate 	if (error) {
4697c478bd9Sstevel@tonic-gate 		cachefs_inval_object(dcp);
4707c478bd9Sstevel@tonic-gate 		error = ENOTDIR;
4717c478bd9Sstevel@tonic-gate 		goto out;
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate 	ASSERT(va.va_size != 0LL);
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	nmlen = (int)strlen(nm);
4767c478bd9Sstevel@tonic-gate 	while (blockoff < va.va_size) {
4777c478bd9Sstevel@tonic-gate 		uint_t *last_len;
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 		offset = 0;
4807c478bd9Sstevel@tonic-gate 		last_len = NULL;
4817c478bd9Sstevel@tonic-gate 		error =
4827c478bd9Sstevel@tonic-gate 		    fbread(dvp, (offset_t)blockoff, MAXBSIZE, S_OTHER, &fbp);
4837c478bd9Sstevel@tonic-gate 		if (error)
4847c478bd9Sstevel@tonic-gate 			goto out;
4857c478bd9Sstevel@tonic-gate 		while (offset < MAXBSIZE && (blockoff + offset) < va.va_size) {
4867c478bd9Sstevel@tonic-gate 			struct c_dirent *dep;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 			dep  = (struct c_dirent *)((uintptr_t)fbp->fb_addr +
4897c478bd9Sstevel@tonic-gate 								offset);
4907c478bd9Sstevel@tonic-gate 			if ((dep->d_flag & CDE_VALID) &&
4917c478bd9Sstevel@tonic-gate 				(nmlen == dep->d_namelen) &&
4927c478bd9Sstevel@tonic-gate 				strcmp(dep->d_name, nm) == 0) {
4937c478bd9Sstevel@tonic-gate 				/*
4947c478bd9Sstevel@tonic-gate 				 * Found the entry. If this was the first entry
4957c478bd9Sstevel@tonic-gate 				 * in the MAXBSIZE block, Mark it invalid. Else
4967c478bd9Sstevel@tonic-gate 				 * add it's length to the previous entry's
4977c478bd9Sstevel@tonic-gate 				 * length.
4987c478bd9Sstevel@tonic-gate 				 */
4997c478bd9Sstevel@tonic-gate 				if (last_len == NULL) {
5007c478bd9Sstevel@tonic-gate 					ASSERT(offset == 0);
5017c478bd9Sstevel@tonic-gate 					dep->d_flag = 0;
5027c478bd9Sstevel@tonic-gate 				} else
5037c478bd9Sstevel@tonic-gate 					*last_len += dep->d_length;
5047c478bd9Sstevel@tonic-gate 				(void) fbdwrite(fbp);
5057c478bd9Sstevel@tonic-gate 				dcp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
5067c478bd9Sstevel@tonic-gate 				goto out;
5077c478bd9Sstevel@tonic-gate 			}
5087c478bd9Sstevel@tonic-gate 			last_len = &dep->d_length;
5097c478bd9Sstevel@tonic-gate 			offset += dep->d_length;
5107c478bd9Sstevel@tonic-gate 		}
5117c478bd9Sstevel@tonic-gate 		fbrelse(fbp, S_OTHER);
5127c478bd9Sstevel@tonic-gate 		blockoff += MAXBSIZE;
5137c478bd9Sstevel@tonic-gate 	}
5147c478bd9Sstevel@tonic-gate 	error = ENOENT;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate out:
5177c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
5187c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
5197c478bd9Sstevel@tonic-gate 		printf("cachefs_dir_rmentry: EXIT error = %d\n", error);
5207c478bd9Sstevel@tonic-gate #endif
5217c478bd9Sstevel@tonic-gate 	return (error);
5227c478bd9Sstevel@tonic-gate }
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate #if 0
5257c478bd9Sstevel@tonic-gate /*
5267c478bd9Sstevel@tonic-gate  * This function is used only in cachefs_lookup_back() routine but
5277c478bd9Sstevel@tonic-gate  * is inside #if 0 directive in this routine. So I am keeping this
5287c478bd9Sstevel@tonic-gate  * routine also in #if 0 directive.
5297c478bd9Sstevel@tonic-gate  */
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate /*
5327c478bd9Sstevel@tonic-gate  * This function fills in the cookie and file no of the directory entry
5337c478bd9Sstevel@tonic-gate  * at the offset specified by offset - In other words, makes the entry
5347c478bd9Sstevel@tonic-gate  * "complete".
5357c478bd9Sstevel@tonic-gate  */
5367c478bd9Sstevel@tonic-gate int
5377c478bd9Sstevel@tonic-gate cachefs_dir_modentry(cnode_t *dcp, u_offset_t offset, fid_t *cookiep,
5387c478bd9Sstevel@tonic-gate     cfs_cid_t *cidp)
5397c478bd9Sstevel@tonic-gate {
5407c478bd9Sstevel@tonic-gate 	struct c_dirent *dep;
5417c478bd9Sstevel@tonic-gate 	u_offset_t blockoff = (offset & (offset_t)MAXBMASK);
5427c478bd9Sstevel@tonic-gate 	uint_t off = (uint_t)(offset & (offset_t)MAXBOFFSET);
5437c478bd9Sstevel@tonic-gate 	struct fbuf *fbp;
5447c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
5457c478bd9Sstevel@tonic-gate 	int error = 0;
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
5487c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
5497c478bd9Sstevel@tonic-gate 		printf("cachefs_dir_modentry: ENTER dcp %p offset %lld\n",
5507c478bd9Sstevel@tonic-gate 			(void *)dcp, offset);
5517c478bd9Sstevel@tonic-gate #endif
5527c478bd9Sstevel@tonic-gate 	ASSERT(CTOV(dcp)->v_type == VDIR);
5537c478bd9Sstevel@tonic-gate 	ASSERT(dcp->c_metadata.md_flags & MD_POPULATED);
5547c478bd9Sstevel@tonic-gate 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	if (dcp->c_frontvp == NULL)
5577c478bd9Sstevel@tonic-gate 		(void) cachefs_getfrontfile(dcp);
5587c478bd9Sstevel@tonic-gate 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
5597c478bd9Sstevel@tonic-gate 		return;
5607c478bd9Sstevel@tonic-gate 	}
5617c478bd9Sstevel@tonic-gate 	dvp = dcp->c_frontvp;
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	error = fbread(dvp, (offset_t)blockoff, MAXBSIZE, S_OTHER, &fbp);
5647c478bd9Sstevel@tonic-gate 	if (error)
5657c478bd9Sstevel@tonic-gate 		goto out;
5667c478bd9Sstevel@tonic-gate 	dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + off);
5677c478bd9Sstevel@tonic-gate 	if (cookiep) {
5687c478bd9Sstevel@tonic-gate 		dep->d_flag |= CDE_COMPLETE;
5697c478bd9Sstevel@tonic-gate 		CACHEFS_FID_COPY(cookiep, &dep->d_cookie);
5707c478bd9Sstevel@tonic-gate 	}
5717c478bd9Sstevel@tonic-gate 	if (cidp)
5727c478bd9Sstevel@tonic-gate 		dep->d_id = *cidp;
5737c478bd9Sstevel@tonic-gate 	(void) fbdwrite(fbp);
5747c478bd9Sstevel@tonic-gate 	dcp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate out:
5777c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
5787c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
5797c478bd9Sstevel@tonic-gate 		printf("cachefs_dir_modentry: EXIT\n");
5807c478bd9Sstevel@tonic-gate #endif
5817c478bd9Sstevel@tonic-gate 	return (error);
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate #endif  /* of #if 0 */
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate /*
5877c478bd9Sstevel@tonic-gate  * Called by cachefs_read_dir(). Gets a bunch if directory entries into buf and
5887c478bd9Sstevel@tonic-gate  * packs them into buf.
5897c478bd9Sstevel@tonic-gate  */
5907c478bd9Sstevel@tonic-gate static int
cachefs_dir_getentrys(struct cnode * dcp,u_offset_t beg_off,u_offset_t * last_offp,uint_t * cntp,uint_t bufsize,caddr_t buf,int * eofp)5917c478bd9Sstevel@tonic-gate cachefs_dir_getentrys(struct cnode *dcp, u_offset_t beg_off,
5927c478bd9Sstevel@tonic-gate 		u_offset_t *last_offp, uint_t *cntp, uint_t bufsize,
5937c478bd9Sstevel@tonic-gate 				caddr_t buf, int *eofp)
5947c478bd9Sstevel@tonic-gate {
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate #define	DIR_ENDOFF	0x7fffffffLL
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	struct vattr va;
5997c478bd9Sstevel@tonic-gate 	struct c_dirent *dep;
6007c478bd9Sstevel@tonic-gate 	struct fbuf *fbp = NULL;
6017c478bd9Sstevel@tonic-gate 	struct dirent64 *gdp;
6027c478bd9Sstevel@tonic-gate 	u_offset_t blockoff;
6037c478bd9Sstevel@tonic-gate 	uint_t off;
6047c478bd9Sstevel@tonic-gate 	int error;
6057c478bd9Sstevel@tonic-gate 	vnode_t *dvp = dcp->c_frontvp;
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
6087c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
6097c478bd9Sstevel@tonic-gate 	printf("cachefs_dir_getentrys: "
6107c478bd9Sstevel@tonic-gate 	    "ENTER dcp %p beg_off %lld mdflags %x cflags %x\n",
6117c478bd9Sstevel@tonic-gate 	    dcp, beg_off, dcp->c_metadata.md_flags, dcp->c_flags);
6127c478bd9Sstevel@tonic-gate #endif
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	/*
6177c478bd9Sstevel@tonic-gate 	 * blockoff has the offset of the MAXBSIZE block that contains the
6187c478bd9Sstevel@tonic-gate 	 * entry  to start with. off contains the offset relative to the
6197c478bd9Sstevel@tonic-gate 	 * begining of the MAXBSIZE block.
6207c478bd9Sstevel@tonic-gate 	 */
6217c478bd9Sstevel@tonic-gate 	if (eofp)
6227c478bd9Sstevel@tonic-gate 		*eofp = 0;
6237c478bd9Sstevel@tonic-gate 	gdp = (struct dirent64 *)buf;
6247c478bd9Sstevel@tonic-gate 	*cntp = bufsize;
6257c478bd9Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
626*da6c28aaSamw 	error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
6277c478bd9Sstevel@tonic-gate 	if (error) {
6287c478bd9Sstevel@tonic-gate 		*cntp = 0;
6297c478bd9Sstevel@tonic-gate 		*last_offp = 0;
6307c478bd9Sstevel@tonic-gate 		if (eofp)
6317c478bd9Sstevel@tonic-gate 			*eofp = 1;
6327c478bd9Sstevel@tonic-gate 		goto out;
6337c478bd9Sstevel@tonic-gate 	}
6347c478bd9Sstevel@tonic-gate 	ASSERT(va.va_size != 0LL);
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	if (beg_off == DIR_ENDOFF) {
6377c478bd9Sstevel@tonic-gate 		*cntp = 0;
6387c478bd9Sstevel@tonic-gate 		*last_offp = DIR_ENDOFF;
6397c478bd9Sstevel@tonic-gate 		if (eofp)
6407c478bd9Sstevel@tonic-gate 			*eofp = 1;
6417c478bd9Sstevel@tonic-gate 		goto out;
6427c478bd9Sstevel@tonic-gate 	}
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	/*
6457c478bd9Sstevel@tonic-gate 	 * locate the offset where we start reading.
6467c478bd9Sstevel@tonic-gate 	 */
6477c478bd9Sstevel@tonic-gate 	for (blockoff = 0; blockoff < va.va_size; blockoff += MAXBSIZE) {
6487c478bd9Sstevel@tonic-gate 		error =
6497c478bd9Sstevel@tonic-gate 		    fbread(dvp, (offset_t)blockoff, MAXBSIZE, S_OTHER, &fbp);
6507c478bd9Sstevel@tonic-gate 		if (error)
6517c478bd9Sstevel@tonic-gate 			goto out;
6527c478bd9Sstevel@tonic-gate 		dep = (struct c_dirent *)fbp->fb_addr;
6537c478bd9Sstevel@tonic-gate 		off = 0;
6547c478bd9Sstevel@tonic-gate 		while (off < MAXBSIZE && dep->d_offset <= beg_off) {
6557c478bd9Sstevel@tonic-gate 			off += dep->d_length;
6567c478bd9Sstevel@tonic-gate 			dep =
6577c478bd9Sstevel@tonic-gate 			    (struct c_dirent *)((uintptr_t)fbp->fb_addr + off);
6587c478bd9Sstevel@tonic-gate 		}
6597c478bd9Sstevel@tonic-gate 		if (off < MAXBSIZE)
6607c478bd9Sstevel@tonic-gate 			break;
6617c478bd9Sstevel@tonic-gate 		fbrelse(fbp, S_OTHER);
6627c478bd9Sstevel@tonic-gate 		fbp = NULL;
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	if (blockoff >= va.va_size) {
6667c478bd9Sstevel@tonic-gate 		*cntp = 0;
6677c478bd9Sstevel@tonic-gate 		*last_offp = DIR_ENDOFF;
6687c478bd9Sstevel@tonic-gate 		if (eofp)
6697c478bd9Sstevel@tonic-gate 			*eofp = 1;
6707c478bd9Sstevel@tonic-gate 		goto out;
6717c478bd9Sstevel@tonic-gate 	}
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	/*
6747c478bd9Sstevel@tonic-gate 	 * Just load up the buffer with directory entries.
6757c478bd9Sstevel@tonic-gate 	 */
6767c478bd9Sstevel@tonic-gate 	for (;;) {
6777c478bd9Sstevel@tonic-gate 		uint_t size;
6787c478bd9Sstevel@tonic-gate 		int this_reclen;
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 		ASSERT((uintptr_t)dep < ((uintptr_t)fbp->fb_addr + MAXBSIZE));
6817c478bd9Sstevel@tonic-gate 		if (dep->d_flag & CDE_VALID) {
6827c478bd9Sstevel@tonic-gate 			this_reclen = DIRENT64_RECLEN(dep->d_namelen);
6837c478bd9Sstevel@tonic-gate 			size = C_DIRSIZ(dep);
6847c478bd9Sstevel@tonic-gate 			ASSERT(size < MAXBSIZE);
6857c478bd9Sstevel@tonic-gate 			if (this_reclen > bufsize)
6867c478bd9Sstevel@tonic-gate 				break;
6877c478bd9Sstevel@tonic-gate 			ASSERT(dep->d_namelen <= MAXNAMELEN);
6887c478bd9Sstevel@tonic-gate 			ASSERT(dep->d_offset > (*last_offp));
6897c478bd9Sstevel@tonic-gate 			gdp->d_ino = dep->d_id.cid_fileno;
6907c478bd9Sstevel@tonic-gate 			gdp->d_off = dep->d_offset;
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 			/* use strncpy(9f) to zero out uninitialized bytes */
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 			ASSERT(strlen(dep->d_name) + 1 <=
6957c478bd9Sstevel@tonic-gate 			    DIRENT64_NAMELEN(this_reclen));
6967c478bd9Sstevel@tonic-gate 			(void) strncpy(gdp->d_name, dep->d_name,
6977c478bd9Sstevel@tonic-gate 			    DIRENT64_NAMELEN(this_reclen));
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 			gdp->d_reclen = (ushort_t)this_reclen;
7007c478bd9Sstevel@tonic-gate 			bufsize -= this_reclen;
7017c478bd9Sstevel@tonic-gate 			gdp = (struct dirent64 *)((uintptr_t)gdp +
7027c478bd9Sstevel@tonic-gate 				gdp->d_reclen);
7037c478bd9Sstevel@tonic-gate 			*last_offp = dep->d_offset;
7047c478bd9Sstevel@tonic-gate 		}
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 		/*
7077c478bd9Sstevel@tonic-gate 		 * Increment the offset. If we've hit EOF, fill in
7087c478bd9Sstevel@tonic-gate 		 * the lastoff and current entries d_off field.
7097c478bd9Sstevel@tonic-gate 		 */
7107c478bd9Sstevel@tonic-gate 		off += dep->d_length;
7117c478bd9Sstevel@tonic-gate 		ASSERT(off <= MAXBSIZE);
7127c478bd9Sstevel@tonic-gate 		if ((blockoff + off) >= va.va_size) {
7137c478bd9Sstevel@tonic-gate 			*last_offp = DIR_ENDOFF;
7147c478bd9Sstevel@tonic-gate 			if (eofp)
7157c478bd9Sstevel@tonic-gate 				*eofp = 1;
7167c478bd9Sstevel@tonic-gate 			break;
7177c478bd9Sstevel@tonic-gate 		}
7187c478bd9Sstevel@tonic-gate 		/*
7197c478bd9Sstevel@tonic-gate 		 * If off == MAXBSIZE, then we need to adjust our
7207c478bd9Sstevel@tonic-gate 		 * window to the next MAXBSIZE block of the directory.
7217c478bd9Sstevel@tonic-gate 		 * Adjust blockoff, off and map it in. Also, increment
7227c478bd9Sstevel@tonic-gate 		 * the directory and buffer pointers.
7237c478bd9Sstevel@tonic-gate 		 */
7247c478bd9Sstevel@tonic-gate 		if (off == MAXBSIZE) {
7257c478bd9Sstevel@tonic-gate 			fbrelse(fbp, S_OTHER);
7267c478bd9Sstevel@tonic-gate 			fbp = NULL;
7277c478bd9Sstevel@tonic-gate 			off = 0;
7287c478bd9Sstevel@tonic-gate 			blockoff += MAXBSIZE;
7297c478bd9Sstevel@tonic-gate 			error = fbread(dvp, (offset_t)blockoff, MAXBSIZE,
7307c478bd9Sstevel@tonic-gate 								S_OTHER, &fbp);
7317c478bd9Sstevel@tonic-gate 			if (error)
7327c478bd9Sstevel@tonic-gate 				goto out;
7337c478bd9Sstevel@tonic-gate 		}
7347c478bd9Sstevel@tonic-gate 		dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + off);
7357c478bd9Sstevel@tonic-gate 	}
7367c478bd9Sstevel@tonic-gate 	*cntp -= bufsize;
7377c478bd9Sstevel@tonic-gate out:
7387c478bd9Sstevel@tonic-gate 	/*
7397c478bd9Sstevel@tonic-gate 	 * Release any buffer and maping that may exist.
7407c478bd9Sstevel@tonic-gate 	 */
7417c478bd9Sstevel@tonic-gate 	if (fbp)
7427c478bd9Sstevel@tonic-gate 		(void) fbrelse(fbp, S_OTHER);
7437c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
7447c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
7457c478bd9Sstevel@tonic-gate 		printf("ccachefs_dir_getentrys: EXIT error = %d\n", error);
7467c478bd9Sstevel@tonic-gate #endif
7477c478bd9Sstevel@tonic-gate 	return (error);
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate /*
7517c478bd9Sstevel@tonic-gate  * Called by cachefs_readdir(). Fills a directory request from the cache
7527c478bd9Sstevel@tonic-gate  */
7537c478bd9Sstevel@tonic-gate int
cachefs_dir_read(struct cnode * dcp,struct uio * uiop,int * eofp)7547c478bd9Sstevel@tonic-gate cachefs_dir_read(struct cnode *dcp, struct uio *uiop, int *eofp)
7557c478bd9Sstevel@tonic-gate {
7567c478bd9Sstevel@tonic-gate 	int error;
7577c478bd9Sstevel@tonic-gate 	uint_t count;
7587c478bd9Sstevel@tonic-gate 	uint_t size;
7597c478bd9Sstevel@tonic-gate 	caddr_t buf;
7607c478bd9Sstevel@tonic-gate 	u_offset_t next = uiop->uio_loffset;
7617c478bd9Sstevel@tonic-gate 	struct fscache *fscp = C_TO_FSCACHE(dcp);
7627c478bd9Sstevel@tonic-gate 	cachefscache_t *cachep = fscp->fs_cache;
7637c478bd9Sstevel@tonic-gate 	caddr_t chrp, end;
7647c478bd9Sstevel@tonic-gate 	dirent64_t *de;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	ASSERT(CTOV(dcp)->v_type == VDIR);
7677c478bd9Sstevel@tonic-gate 	ASSERT(RW_READ_HELD(&dcp->c_rwlock));
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	ASSERT(next <= MAXOFF_T);
7707c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
7717c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
7727c478bd9Sstevel@tonic-gate 		printf("cachefs_dir_read: ENTER dcp %p\n", (void *)dcp);
7737c478bd9Sstevel@tonic-gate #endif
7747c478bd9Sstevel@tonic-gate 	ASSERT((dcp->c_metadata.md_flags & (MD_FILE|MD_POPULATED)) ==
7757c478bd9Sstevel@tonic-gate 	    (MD_FILE|MD_POPULATED));
7767c478bd9Sstevel@tonic-gate 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	if (dcp->c_frontvp == NULL)
7797c478bd9Sstevel@tonic-gate 		(void) cachefs_getfrontfile(dcp);
7807c478bd9Sstevel@tonic-gate 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
7817c478bd9Sstevel@tonic-gate 		error = ENOTDIR;
7827c478bd9Sstevel@tonic-gate 		goto out;
7837c478bd9Sstevel@tonic-gate 	}
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	size = (uint_t)uiop->uio_resid;
7867c478bd9Sstevel@tonic-gate 	buf = cachefs_kmem_alloc(size, KM_SLEEP);
7877c478bd9Sstevel@tonic-gate 	error = cachefs_dir_getentrys(dcp, next, &next, &count, size,
7887c478bd9Sstevel@tonic-gate 	    buf, eofp);
7897c478bd9Sstevel@tonic-gate 	if (error == 0 && (int)count > 0) {
7907c478bd9Sstevel@tonic-gate 		ASSERT(count <= size);
7917c478bd9Sstevel@tonic-gate 		if (fscp->fs_inum_size > 0) {
7927c478bd9Sstevel@tonic-gate 			ino64_t newinum;
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 			mutex_exit(&dcp->c_statelock);
7957c478bd9Sstevel@tonic-gate 			mutex_enter(&fscp->fs_fslock);
7967c478bd9Sstevel@tonic-gate 			end = (caddr_t)((uintptr_t)buf + count);
7977c478bd9Sstevel@tonic-gate 			for (chrp = buf; chrp < end; chrp += de->d_reclen) {
7987c478bd9Sstevel@tonic-gate 				de = (dirent64_t *)chrp;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 				newinum = cachefs_inum_real2fake(fscp,
8017c478bd9Sstevel@tonic-gate 				    de->d_ino);
8027c478bd9Sstevel@tonic-gate 				if (newinum == 0)
8037c478bd9Sstevel@tonic-gate 					newinum = cachefs_fileno_conflict(fscp,
8047c478bd9Sstevel@tonic-gate 					    de->d_ino);
8057c478bd9Sstevel@tonic-gate 				de->d_ino = newinum;
8067c478bd9Sstevel@tonic-gate 			}
8077c478bd9Sstevel@tonic-gate 			mutex_exit(&fscp->fs_fslock);
8087c478bd9Sstevel@tonic-gate 			mutex_enter(&dcp->c_statelock);
8097c478bd9Sstevel@tonic-gate 		}
8107c478bd9Sstevel@tonic-gate 		error = uiomove(buf, count, UIO_READ, uiop);
8117c478bd9Sstevel@tonic-gate 		if (error == 0)
8127c478bd9Sstevel@tonic-gate 			uiop->uio_loffset = next;
8137c478bd9Sstevel@tonic-gate 	}
8147c478bd9Sstevel@tonic-gate 	(void) cachefs_kmem_free(buf, size);
8157c478bd9Sstevel@tonic-gate out:
8167c478bd9Sstevel@tonic-gate 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_RFDIR))
8177c478bd9Sstevel@tonic-gate 		cachefs_log_rfdir(cachep, error, fscp->fs_cfsvfsp,
8187c478bd9Sstevel@tonic-gate 		    &dcp->c_metadata.md_cookie, dcp->c_id.cid_fileno, 0);
8197c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
8207c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
8217c478bd9Sstevel@tonic-gate 		printf("cachefs_dir_read: EXIT error = %d\n", error);
8227c478bd9Sstevel@tonic-gate #endif
8237c478bd9Sstevel@tonic-gate 	return (error);
8247c478bd9Sstevel@tonic-gate }
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate /*
8277c478bd9Sstevel@tonic-gate  * Fully (including cookie) populates the directory from the back filesystem.
8287c478bd9Sstevel@tonic-gate  */
8297c478bd9Sstevel@tonic-gate int
cachefs_dir_fill(cnode_t * dcp,cred_t * cr)8307c478bd9Sstevel@tonic-gate cachefs_dir_fill(cnode_t *dcp, cred_t *cr)
8317c478bd9Sstevel@tonic-gate {
8327c478bd9Sstevel@tonic-gate 	int error = 0;
8337c478bd9Sstevel@tonic-gate 	u_offset_t frontsize;
8347c478bd9Sstevel@tonic-gate 	struct fscache *fscp = C_TO_FSCACHE(dcp);
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
8377c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
8387c478bd9Sstevel@tonic-gate 		printf("cachefs_dir_fill: ENTER dcp %p\n", (void *)dcp);
8397c478bd9Sstevel@tonic-gate #endif
8407c478bd9Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
8417c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dcp->c_statelock));
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	/* XXX for now return success if async populate is scheduled */
8447c478bd9Sstevel@tonic-gate 	if (dcp->c_flags & CN_ASYNC_POPULATE)
8457c478bd9Sstevel@tonic-gate 		goto out;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	/* get the back vp */
8487c478bd9Sstevel@tonic-gate 	if (dcp->c_backvp == NULL) {
8497c478bd9Sstevel@tonic-gate 		error = cachefs_getbackvp(fscp, dcp);
8507c478bd9Sstevel@tonic-gate 		if (error) {
8517c478bd9Sstevel@tonic-gate 			goto out;
8527c478bd9Sstevel@tonic-gate 		}
8537c478bd9Sstevel@tonic-gate 	}
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	/* get the front file vp */
8567c478bd9Sstevel@tonic-gate 	if (dcp->c_frontvp == NULL)
8577c478bd9Sstevel@tonic-gate 		(void) cachefs_getfrontfile(dcp);
8587c478bd9Sstevel@tonic-gate 	if (dcp->c_flags & CN_NOCACHE) {
8597c478bd9Sstevel@tonic-gate 		error = ENOTDIR;
8607c478bd9Sstevel@tonic-gate 		goto out;
8617c478bd9Sstevel@tonic-gate 	}
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	/* if dir was modified, toss old contents */
8647c478bd9Sstevel@tonic-gate 	if (dcp->c_metadata.md_flags & MD_INVALREADDIR) {
8657c478bd9Sstevel@tonic-gate 		cachefs_inval_object(dcp);
8667c478bd9Sstevel@tonic-gate 		if (dcp->c_flags & CN_NOCACHE) {
8677c478bd9Sstevel@tonic-gate 			error = ENOTDIR;
8687c478bd9Sstevel@tonic-gate 			goto out;
8697c478bd9Sstevel@tonic-gate 		}
8707c478bd9Sstevel@tonic-gate 	}
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	error = cachefs_dir_fill_common(dcp, cr,
8737c478bd9Sstevel@tonic-gate 	    dcp->c_frontvp, dcp->c_backvp, &frontsize);
8747c478bd9Sstevel@tonic-gate 	if (error == 0)
8757c478bd9Sstevel@tonic-gate 		error = cachefs_dir_complete(fscp, dcp->c_backvp,
8767c478bd9Sstevel@tonic-gate 		    dcp->c_frontvp, cr, 0);
8777c478bd9Sstevel@tonic-gate 	if (error != 0)
8787c478bd9Sstevel@tonic-gate 		goto out;
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	/*
8817c478bd9Sstevel@tonic-gate 	 * Mark the directory as not empty. Also bang the flag that says that
8827c478bd9Sstevel@tonic-gate 	 * this directory needs to be sync'ed on inactive.
8837c478bd9Sstevel@tonic-gate 	 */
8847c478bd9Sstevel@tonic-gate 	dcp->c_metadata.md_flags |= MD_POPULATED;
8857c478bd9Sstevel@tonic-gate 	dcp->c_metadata.md_flags &= ~MD_INVALREADDIR;
8867c478bd9Sstevel@tonic-gate 	dcp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
8877c478bd9Sstevel@tonic-gate 	/*LINTED alignment okay*/
8887c478bd9Sstevel@tonic-gate 	dcp->c_metadata.md_frontblks = frontsize / MAXBSIZE;
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate out:
8917c478bd9Sstevel@tonic-gate 	if (error) {
8927c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
8937c478bd9Sstevel@tonic-gate 		CFS_DEBUG(CFSDEBUG_INVALIDATE)
8947c478bd9Sstevel@tonic-gate 			printf("c_dir_fill: invalidating %llu\n",
8957c478bd9Sstevel@tonic-gate 			    (u_longlong_t)dcp->c_id.cid_fileno);
8967c478bd9Sstevel@tonic-gate #endif
8977c478bd9Sstevel@tonic-gate 		cachefs_inval_object(dcp);
8987c478bd9Sstevel@tonic-gate 	}
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	return (error);
9017c478bd9Sstevel@tonic-gate }
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate /*
9047c478bd9Sstevel@tonic-gate  * Does work of populating directory.
9057c478bd9Sstevel@tonic-gate  * Must be called while holding dcp->c_statelock
9067c478bd9Sstevel@tonic-gate  */
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate static int
cachefs_dir_fill_common(cnode_t * dcp,cred_t * cr,vnode_t * frontvp,vnode_t * backvp,u_offset_t * frontsize)9097c478bd9Sstevel@tonic-gate cachefs_dir_fill_common(cnode_t *dcp, cred_t *cr,
9107c478bd9Sstevel@tonic-gate     vnode_t *frontvp, vnode_t *backvp, u_offset_t *frontsize)
9117c478bd9Sstevel@tonic-gate {
9127c478bd9Sstevel@tonic-gate 	int error = 0;
9137c478bd9Sstevel@tonic-gate 	struct uio uio;
9147c478bd9Sstevel@tonic-gate 	struct iovec iov;
9157c478bd9Sstevel@tonic-gate 	caddr_t buf = NULL;
9167c478bd9Sstevel@tonic-gate 	int count;
9177c478bd9Sstevel@tonic-gate 	int eof = 0;
9187c478bd9Sstevel@tonic-gate 	u_offset_t frontoff;
9197c478bd9Sstevel@tonic-gate 	struct fscache *fscp = C_TO_FSCACHE(dcp);
9207c478bd9Sstevel@tonic-gate 	cachefscache_t *cachep = fscp->fs_cache;
9217c478bd9Sstevel@tonic-gate #ifdef DEBUG
9227c478bd9Sstevel@tonic-gate 	int loop_count = 0;
9237c478bd9Sstevel@tonic-gate #endif
9247c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
9257c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
9267c478bd9Sstevel@tonic-gate 		printf("cachefs_dir_fill_common: ENTER dcp %p\n", (void *)dcp);
9277c478bd9Sstevel@tonic-gate #endif
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dcp->c_statelock));
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	frontoff = *frontsize = 0LL;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	buf = cachefs_kmem_alloc(MAXBSIZE, KM_SLEEP);
9347c478bd9Sstevel@tonic-gate 	uio.uio_iov = &iov;
9357c478bd9Sstevel@tonic-gate 	uio.uio_iovcnt = 1;
9367c478bd9Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
9377c478bd9Sstevel@tonic-gate 	uio.uio_fmode = 0;
9387c478bd9Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_CACHED;
9397c478bd9Sstevel@tonic-gate 	uio.uio_loffset = 0;
9407c478bd9Sstevel@tonic-gate 	for (;;) {
9417c478bd9Sstevel@tonic-gate #ifdef DEBUG
9427c478bd9Sstevel@tonic-gate 		loop_count++;
9437c478bd9Sstevel@tonic-gate #endif
9447c478bd9Sstevel@tonic-gate 		/*
9457c478bd9Sstevel@tonic-gate 		 * Read in a buffer's worth of dirents and enter them in to the
9467c478bd9Sstevel@tonic-gate 		 * directory.
9477c478bd9Sstevel@tonic-gate 		 */
9487c478bd9Sstevel@tonic-gate 		uio.uio_resid = MAXBSIZE;
9497c478bd9Sstevel@tonic-gate 		iov.iov_base = buf;
9507c478bd9Sstevel@tonic-gate 		iov.iov_len = MAXBSIZE;
9517c478bd9Sstevel@tonic-gate 		(void) VOP_RWLOCK(backvp, V_WRITELOCK_FALSE, NULL);
952*da6c28aaSamw 		error = VOP_READDIR(backvp, &uio, cr, &eof, NULL, 0);
9537c478bd9Sstevel@tonic-gate 		VOP_RWUNLOCK(backvp, V_WRITELOCK_FALSE, NULL);
9547c478bd9Sstevel@tonic-gate 		if (error)
9557c478bd9Sstevel@tonic-gate 			goto out;
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 		/*LINTED alignment okay*/
9587c478bd9Sstevel@tonic-gate 		count = MAXBSIZE - (int)uio.uio_resid;
9597c478bd9Sstevel@tonic-gate 		ASSERT(count >= 0);
9607c478bd9Sstevel@tonic-gate 		if (count > 0) {
9617c478bd9Sstevel@tonic-gate 			if (error = cachefs_dir_stuff(dcp, count, buf,
9627c478bd9Sstevel@tonic-gate 			    frontvp, &frontoff, frontsize))
9637c478bd9Sstevel@tonic-gate 				goto out;
9647c478bd9Sstevel@tonic-gate 			ASSERT((*frontsize) != 0LL);
9657c478bd9Sstevel@tonic-gate 		}
9667c478bd9Sstevel@tonic-gate 		if (eof || count == 0)
9677c478bd9Sstevel@tonic-gate 			break;
9687c478bd9Sstevel@tonic-gate 	}
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	if (*frontsize == 0LL) {
9717c478bd9Sstevel@tonic-gate 		/* keep us from caching an empty directory */
9727c478bd9Sstevel@tonic-gate 		error = EINVAL;
9737c478bd9Sstevel@tonic-gate 		goto out;
9747c478bd9Sstevel@tonic-gate 	}
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate out:
9777c478bd9Sstevel@tonic-gate 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_FILLDIR))
9787c478bd9Sstevel@tonic-gate 		cachefs_log_filldir(cachep, error, fscp->fs_cfsvfsp,
9797c478bd9Sstevel@tonic-gate 		    &dcp->c_metadata.md_cookie, dcp->c_id.cid_fileno,
9807c478bd9Sstevel@tonic-gate 		    *frontsize);
9817c478bd9Sstevel@tonic-gate 	if (buf)
9827c478bd9Sstevel@tonic-gate 		cachefs_kmem_free(buf, (uint_t)MAXBSIZE);
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
9857c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
9867c478bd9Sstevel@tonic-gate 		printf("cachefs_dir_fill: EXIT error = %d\n", error);
9877c478bd9Sstevel@tonic-gate #endif
9887c478bd9Sstevel@tonic-gate 	return (error);
9897c478bd9Sstevel@tonic-gate }
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate /*
9927c478bd9Sstevel@tonic-gate  * If the directory contains only the elements "." and "..", then this returns
9937c478bd9Sstevel@tonic-gate  * 0, otherwise returns an error.
9947c478bd9Sstevel@tonic-gate  */
9957c478bd9Sstevel@tonic-gate int
cachefs_dir_empty(cnode_t * dcp)9967c478bd9Sstevel@tonic-gate cachefs_dir_empty(cnode_t *dcp)
9977c478bd9Sstevel@tonic-gate {
9987c478bd9Sstevel@tonic-gate 	struct vattr va;
9997c478bd9Sstevel@tonic-gate 	u_offset_t blockoff = 0;
10007c478bd9Sstevel@tonic-gate 	int offset;
10017c478bd9Sstevel@tonic-gate 	struct fbuf *fbp;
10027c478bd9Sstevel@tonic-gate 	int error;
10037c478bd9Sstevel@tonic-gate 	vnode_t *dvp = dcp->c_frontvp;
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
10067c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
10077c478bd9Sstevel@tonic-gate 		printf("cachefs_dir_empty: ENTER dcp %p\n", (void *)dcp);
10087c478bd9Sstevel@tonic-gate #endif
10097c478bd9Sstevel@tonic-gate 	ASSERT(CTOV(dcp)->v_type == VDIR);
10107c478bd9Sstevel@tonic-gate 	ASSERT(dcp->c_metadata.md_flags & MD_POPULATED);
10117c478bd9Sstevel@tonic-gate 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	if (dcp->c_frontvp == NULL)
10147c478bd9Sstevel@tonic-gate 		(void) cachefs_getfrontfile(dcp);
10157c478bd9Sstevel@tonic-gate 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0)
10167c478bd9Sstevel@tonic-gate 		return (ENOTDIR);
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
1019*da6c28aaSamw 	error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
10207c478bd9Sstevel@tonic-gate 	if (error)
10217c478bd9Sstevel@tonic-gate 		return (ENOTDIR);
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate 	ASSERT(va.va_size != 0LL);
10247c478bd9Sstevel@tonic-gate 	while (blockoff < va.va_size) {
10257c478bd9Sstevel@tonic-gate 		offset = 0;
10267c478bd9Sstevel@tonic-gate 		error =
10277c478bd9Sstevel@tonic-gate 		    fbread(dvp, (offset_t)blockoff, MAXBSIZE, S_OTHER, &fbp);
10287c478bd9Sstevel@tonic-gate 		if (error)
10297c478bd9Sstevel@tonic-gate 			return (error);
10307c478bd9Sstevel@tonic-gate 		while (offset < MAXBSIZE && (blockoff + offset) < va.va_size) {
10317c478bd9Sstevel@tonic-gate 			struct c_dirent *dep;
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 			dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr +
10347c478bd9Sstevel@tonic-gate 								offset);
10357c478bd9Sstevel@tonic-gate 			if ((dep->d_flag & CDE_VALID) &&
10367c478bd9Sstevel@tonic-gate 				((strcmp(dep->d_name, ".") != 0) &&
10377c478bd9Sstevel@tonic-gate 				(strcmp(dep->d_name, "..") != 0))) {
10387c478bd9Sstevel@tonic-gate 				(void) fbrelse(fbp, S_OTHER);
10397c478bd9Sstevel@tonic-gate 				return (0);
10407c478bd9Sstevel@tonic-gate 			}
10417c478bd9Sstevel@tonic-gate 			offset += dep->d_length;
10427c478bd9Sstevel@tonic-gate 		}
10437c478bd9Sstevel@tonic-gate 		(void) fbrelse(fbp, S_OTHER);
10447c478bd9Sstevel@tonic-gate 		blockoff += MAXBSIZE;
10457c478bd9Sstevel@tonic-gate 	}
10467c478bd9Sstevel@tonic-gate 	return (EEXIST);
10477c478bd9Sstevel@tonic-gate }
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate /*
10507c478bd9Sstevel@tonic-gate  * Called by cachefs_dir_fill() to stuff a buffer of dir entries into
10517c478bd9Sstevel@tonic-gate  * a front file.  This is more efficient than repeated calls to
10527c478bd9Sstevel@tonic-gate  * cachefs_dir_enter, and it also allows us to maintain entries in backfs
10537c478bd9Sstevel@tonic-gate  * order (readdir requires that entry offsets be ascending).
10547c478bd9Sstevel@tonic-gate  */
10557c478bd9Sstevel@tonic-gate static int
cachefs_dir_stuff(cnode_t * dcp,uint_t count,caddr_t buf,vnode_t * frontvp,u_offset_t * offsetp,u_offset_t * fsizep)10567c478bd9Sstevel@tonic-gate cachefs_dir_stuff(cnode_t *dcp, uint_t count, caddr_t buf,
10577c478bd9Sstevel@tonic-gate     vnode_t *frontvp, u_offset_t *offsetp, u_offset_t *fsizep)
10587c478bd9Sstevel@tonic-gate {
10597c478bd9Sstevel@tonic-gate 	int error = 0;
10607c478bd9Sstevel@tonic-gate 	struct fbuf *fbp;
10617c478bd9Sstevel@tonic-gate 	struct c_dirent *cdep, *last;
10627c478bd9Sstevel@tonic-gate 	struct dirent64 *dep;
10637c478bd9Sstevel@tonic-gate 	int inblk, entsize;
10647c478bd9Sstevel@tonic-gate 	u_offset_t blockoff = (*offsetp & (offset_t)MAXBMASK);
10657c478bd9Sstevel@tonic-gate 	/*LINTED alignment okay*/
10667c478bd9Sstevel@tonic-gate 	uint_t off = (uint_t)(*offsetp & (offset_t)MAXBOFFSET);
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	/*LINTED want count != 0*/
10697c478bd9Sstevel@tonic-gate 	ASSERT(count > 0);
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	if (*offsetp >= *fsizep) {
10727c478bd9Sstevel@tonic-gate 		error = cachefs_dir_extend(dcp, fsizep, 0);
10737c478bd9Sstevel@tonic-gate 		if (error)
10747c478bd9Sstevel@tonic-gate 			return (error);
10757c478bd9Sstevel@tonic-gate 	}
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 	ASSERT(*fsizep != 0LL);
10787c478bd9Sstevel@tonic-gate 	last = NULL;
10797c478bd9Sstevel@tonic-gate 	error = fbread(frontvp, (offset_t)blockoff, MAXBSIZE, S_OTHER, &fbp);
10807c478bd9Sstevel@tonic-gate 	if (error)
10817c478bd9Sstevel@tonic-gate 		return (error);
10827c478bd9Sstevel@tonic-gate 	cdep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + off);
10837c478bd9Sstevel@tonic-gate 	inblk = MAXBSIZE-off;
10847c478bd9Sstevel@tonic-gate 	if (*offsetp != 0) {
10857c478bd9Sstevel@tonic-gate 		ASSERT(cdep->d_length == inblk);
10867c478bd9Sstevel@tonic-gate 		inblk -= C_DIRSIZ(cdep);
10877c478bd9Sstevel@tonic-gate 		last = cdep;
10887c478bd9Sstevel@tonic-gate 		last->d_length -= inblk;
10897c478bd9Sstevel@tonic-gate 		off += last->d_length;
10907c478bd9Sstevel@tonic-gate 		cdep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + off);
10917c478bd9Sstevel@tonic-gate 	}
10927c478bd9Sstevel@tonic-gate 	dep = (struct dirent64 *)buf;
10937c478bd9Sstevel@tonic-gate 	/*LINTED want count != 0*/
10947c478bd9Sstevel@tonic-gate 	while (count > 0) {
10957c478bd9Sstevel@tonic-gate 		if (last) {
10967c478bd9Sstevel@tonic-gate 			ASSERT(dep->d_off > last->d_offset);
10977c478bd9Sstevel@tonic-gate 		}
10987c478bd9Sstevel@tonic-gate 		entsize = (int)CDE_SIZE(dep->d_name);
10997c478bd9Sstevel@tonic-gate 		if (entsize > inblk) {
11007c478bd9Sstevel@tonic-gate 			if (last) {
11017c478bd9Sstevel@tonic-gate 				last->d_length += inblk;
11027c478bd9Sstevel@tonic-gate 			}
11037c478bd9Sstevel@tonic-gate 			(void) fbwrite(fbp);
11047c478bd9Sstevel@tonic-gate 			error = cachefs_dir_extend(dcp, fsizep, 0);
11057c478bd9Sstevel@tonic-gate 			if (error)
11067c478bd9Sstevel@tonic-gate 				return (error);
11077c478bd9Sstevel@tonic-gate 			ASSERT(*fsizep != 0LL);
11087c478bd9Sstevel@tonic-gate 			blockoff += MAXBSIZE;
11097c478bd9Sstevel@tonic-gate 			error = fbread(frontvp, (offset_t)blockoff, MAXBSIZE,
11107c478bd9Sstevel@tonic-gate 							S_OTHER, &fbp);
11117c478bd9Sstevel@tonic-gate 			if (error)
11127c478bd9Sstevel@tonic-gate 				return (error);
11137c478bd9Sstevel@tonic-gate 			off = 0;
11147c478bd9Sstevel@tonic-gate 			cdep = (struct c_dirent *)fbp->fb_addr;
11157c478bd9Sstevel@tonic-gate 			inblk = MAXBSIZE;
11167c478bd9Sstevel@tonic-gate 			last = NULL;
11177c478bd9Sstevel@tonic-gate 		}
11187c478bd9Sstevel@tonic-gate 		cdep->d_length = entsize;
11197c478bd9Sstevel@tonic-gate 		cdep->d_id.cid_fileno = dep->d_ino;
11207c478bd9Sstevel@tonic-gate 		cdep->d_id.cid_flags = 0;
11217c478bd9Sstevel@tonic-gate 		cdep->d_namelen = (ushort_t)strlen(dep->d_name);
11227c478bd9Sstevel@tonic-gate 		cdep->d_flag = CDE_VALID;
11237c478bd9Sstevel@tonic-gate 		bcopy(dep->d_name, cdep->d_name, cdep->d_namelen+1);
11247c478bd9Sstevel@tonic-gate 		cdep->d_offset = dep->d_off;
11257c478bd9Sstevel@tonic-gate 		inblk -= entsize;
11267c478bd9Sstevel@tonic-gate 		count -= dep->d_reclen;
11277c478bd9Sstevel@tonic-gate 		dep = (struct dirent64 *)((uintptr_t)dep + dep->d_reclen);
11287c478bd9Sstevel@tonic-gate 		*offsetp = blockoff + (u_offset_t)off;
11297c478bd9Sstevel@tonic-gate 		off += entsize;
11307c478bd9Sstevel@tonic-gate 		last = cdep;
11317c478bd9Sstevel@tonic-gate 		cdep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + off);
11327c478bd9Sstevel@tonic-gate 	}
11337c478bd9Sstevel@tonic-gate 	if (last) {
11347c478bd9Sstevel@tonic-gate 		last->d_length += inblk;
11357c478bd9Sstevel@tonic-gate 	}
11367c478bd9Sstevel@tonic-gate 	(void) fbwrite(fbp);
11377c478bd9Sstevel@tonic-gate 	return (error);
11387c478bd9Sstevel@tonic-gate }
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate static int
cachefs_dir_extend(cnode_t * dcp,u_offset_t * cursize,int incr_frontblks)11417c478bd9Sstevel@tonic-gate cachefs_dir_extend(cnode_t *dcp, u_offset_t *cursize, int incr_frontblks)
11427c478bd9Sstevel@tonic-gate {
11437c478bd9Sstevel@tonic-gate 	struct vattr va;
11447c478bd9Sstevel@tonic-gate 	cachefscache_t *cachep = C_TO_FSCACHE(dcp)->fs_cache;
11457c478bd9Sstevel@tonic-gate 	int error = 0;
11467c478bd9Sstevel@tonic-gate 	struct fscache *fscp = VFS_TO_FSCACHE(CTOV(dcp)->v_vfsp);
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dcp->c_statelock));
11497c478bd9Sstevel@tonic-gate 	ASSERT(((*cursize) & (MAXBSIZE-1)) == 0);
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
11527c478bd9Sstevel@tonic-gate 	va.va_size = (u_offset_t)(*cursize + MAXBSIZE);
11537c478bd9Sstevel@tonic-gate 	error = cachefs_allocblocks(cachep, 1, dcp->c_metadata.md_rltype);
11547c478bd9Sstevel@tonic-gate 	if (error)
11557c478bd9Sstevel@tonic-gate 		return (error);
11567c478bd9Sstevel@tonic-gate 	error = VOP_SETATTR(dcp->c_frontvp, &va, 0, kcred, NULL);
11577c478bd9Sstevel@tonic-gate 	if (error) {
11587c478bd9Sstevel@tonic-gate 		cachefs_freeblocks(cachep, 1, dcp->c_metadata.md_rltype);
11597c478bd9Sstevel@tonic-gate 		return (error);
11607c478bd9Sstevel@tonic-gate 	}
11617c478bd9Sstevel@tonic-gate 	if (incr_frontblks)
11627c478bd9Sstevel@tonic-gate 		dcp->c_metadata.md_frontblks++;
11637c478bd9Sstevel@tonic-gate 	if (fscp->fs_cdconnected != CFS_CD_CONNECTED) {
11647c478bd9Sstevel@tonic-gate 		dcp->c_size += MAXBSIZE;
11657c478bd9Sstevel@tonic-gate 		dcp->c_attr.va_size = dcp->c_size;
11667c478bd9Sstevel@tonic-gate 	}
11677c478bd9Sstevel@tonic-gate 	*cursize += MAXBSIZE;
11687c478bd9Sstevel@tonic-gate 	ASSERT(*cursize != 0LL);
11697c478bd9Sstevel@tonic-gate 	if (incr_frontblks)
11707c478bd9Sstevel@tonic-gate 		dcp->c_flags |= CN_UPDATED;
11717c478bd9Sstevel@tonic-gate 	return (0);
11727c478bd9Sstevel@tonic-gate }
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate int
cachefs_async_populate_dir(struct cachefs_populate_req * pop,cred_t * cr,vnode_t * backvp,vnode_t * frontvp)11757c478bd9Sstevel@tonic-gate cachefs_async_populate_dir(struct cachefs_populate_req *pop, cred_t *cr,
11767c478bd9Sstevel@tonic-gate     vnode_t *backvp, vnode_t *frontvp)
11777c478bd9Sstevel@tonic-gate {
11787c478bd9Sstevel@tonic-gate 	vnode_t *dvp = pop->cpop_vp;
11797c478bd9Sstevel@tonic-gate 	struct cnode *dcp = VTOC(dvp);
11807c478bd9Sstevel@tonic-gate 	u_offset_t frontsize;
11817c478bd9Sstevel@tonic-gate 	int error = 0;
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
11847c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
11857c478bd9Sstevel@tonic-gate 		printf("cachefs_async_populate_dir: ENTER dvp %p\n",
11867c478bd9Sstevel@tonic-gate 								(void *)dvp);
11877c478bd9Sstevel@tonic-gate #endif
11887c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dcp->c_statelock));
11897c478bd9Sstevel@tonic-gate 	ASSERT(dvp->v_type == VDIR);
11907c478bd9Sstevel@tonic-gate 	ASSERT((dcp->c_metadata.md_flags & MD_POPULATED) == 0);
11917c478bd9Sstevel@tonic-gate 	ASSERT(dcp->c_frontvp == frontvp);
11927c478bd9Sstevel@tonic-gate 	ASSERT(dcp->c_backvp == backvp);
11937c478bd9Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(dcp)) == 0);
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 	/* if dir was modified, toss old contents */
11967c478bd9Sstevel@tonic-gate 	if (dcp->c_metadata.md_flags & MD_INVALREADDIR) {
11977c478bd9Sstevel@tonic-gate 		cachefs_inval_object(dcp);
11987c478bd9Sstevel@tonic-gate 		if (dcp->c_flags & CN_NOCACHE) {
11997c478bd9Sstevel@tonic-gate 			error = ENOTDIR;
12007c478bd9Sstevel@tonic-gate 			goto out;
12017c478bd9Sstevel@tonic-gate 		} else {
12027c478bd9Sstevel@tonic-gate 			dcp->c_metadata.md_flags &= ~MD_INVALREADDIR;
12037c478bd9Sstevel@tonic-gate 		}
12047c478bd9Sstevel@tonic-gate 	}
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 	error = cachefs_dir_fill_common(dcp, cr, frontvp, backvp, &frontsize);
12087c478bd9Sstevel@tonic-gate 	if (error != 0)
12097c478bd9Sstevel@tonic-gate 		goto out;
12107c478bd9Sstevel@tonic-gate 	ASSERT(frontsize != 0LL);
12117c478bd9Sstevel@tonic-gate 	mutex_exit(&dcp->c_statelock);
12127c478bd9Sstevel@tonic-gate 	/*
12137c478bd9Sstevel@tonic-gate 	 * I don't like to break lock here but cachefs_dir_complete()
12147c478bd9Sstevel@tonic-gate 	 * needs it.
12157c478bd9Sstevel@tonic-gate 	 */
12167c478bd9Sstevel@tonic-gate 	error = cachefs_dir_complete(C_TO_FSCACHE(dcp), backvp,
12177c478bd9Sstevel@tonic-gate 	    frontvp, cr, 1);
12187c478bd9Sstevel@tonic-gate 	mutex_enter(&dcp->c_statelock);
12197c478bd9Sstevel@tonic-gate 	if (error != 0)
12207c478bd9Sstevel@tonic-gate 		goto out;
12217c478bd9Sstevel@tonic-gate 	/* if went nocache while lock was dropped, get out */
12227c478bd9Sstevel@tonic-gate 	if ((dcp->c_flags & CN_NOCACHE) || (dcp->c_frontvp == NULL)) {
12237c478bd9Sstevel@tonic-gate 		error = EINVAL;
12247c478bd9Sstevel@tonic-gate 	} else {
12257c478bd9Sstevel@tonic-gate 		/* allocfile and allocblocks have already happened. */
12267c478bd9Sstevel@tonic-gate 		dcp->c_metadata.md_frontblks = frontsize / MAXBSIZE;
12277c478bd9Sstevel@tonic-gate 	}
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate out:
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
12327c478bd9Sstevel@tonic-gate 	CFS_DEBUG(CFSDEBUG_DIR)
12337c478bd9Sstevel@tonic-gate 		printf("cachefs_async_populate_dir: EXIT error = %d\n", error);
12347c478bd9Sstevel@tonic-gate #endif
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	return (error);
12377c478bd9Sstevel@tonic-gate }
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate static int
cachefs_dir_complete(fscache_t * fscp,vnode_t * backvp,vnode_t * frontvp,cred_t * cr,int acltoo)12407c478bd9Sstevel@tonic-gate cachefs_dir_complete(fscache_t *fscp, vnode_t *backvp, vnode_t *frontvp,
12417c478bd9Sstevel@tonic-gate     cred_t *cr, int acltoo)
12427c478bd9Sstevel@tonic-gate {
12437c478bd9Sstevel@tonic-gate 	struct c_dirent *dep;
12447c478bd9Sstevel@tonic-gate 	caddr_t buf = kmem_alloc(MAXBSIZE, KM_SLEEP);
12457c478bd9Sstevel@tonic-gate 	struct vattr va;
12467c478bd9Sstevel@tonic-gate 	u_offset_t blockoff;
12477c478bd9Sstevel@tonic-gate 	int offset;
12487c478bd9Sstevel@tonic-gate 	u_offset_t dir_size;
12497c478bd9Sstevel@tonic-gate 	struct fbuf *fbp;
12507c478bd9Sstevel@tonic-gate 	cnode_t *cp;
12517c478bd9Sstevel@tonic-gate 	fid_t cookie;
12527c478bd9Sstevel@tonic-gate 	vnode_t *entry_vp;
12537c478bd9Sstevel@tonic-gate 	int error = 0;
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	/*
12567c478bd9Sstevel@tonic-gate 	 * note: caller better not hold a c_statelock if acltoo is set.
12577c478bd9Sstevel@tonic-gate 	 */
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
1260*da6c28aaSamw 	error = VOP_GETATTR(frontvp, &va, 0, cr, NULL);
12617c478bd9Sstevel@tonic-gate 	if (error)
12627c478bd9Sstevel@tonic-gate 		goto out;
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 	ASSERT(va.va_size != 0LL);
12657c478bd9Sstevel@tonic-gate 	dir_size = va.va_size;
12667c478bd9Sstevel@tonic-gate 	ASSERT(dir_size <= MAXOFF_T);
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 	for (blockoff = 0; blockoff < dir_size; blockoff += MAXBSIZE) {
12697c478bd9Sstevel@tonic-gate 		if (error = fbread(frontvp, (offset_t)blockoff,
12707c478bd9Sstevel@tonic-gate 		    MAXBSIZE, S_OTHER, &fbp))
12717c478bd9Sstevel@tonic-gate 			goto out;
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 		/*
12747c478bd9Sstevel@tonic-gate 		 * We cannot hold any page locks across the below VOP
12757c478bd9Sstevel@tonic-gate 		 * operations. We thus copy the directory entries into a
12767c478bd9Sstevel@tonic-gate 		 * staging buffer, and release the page lock on the directory
12777c478bd9Sstevel@tonic-gate 		 * by calling fbrelse().  Once any necessary cnodes have
12787c478bd9Sstevel@tonic-gate 		 * been created, we'll reacquire the page lock with fbread()
12797c478bd9Sstevel@tonic-gate 		 * and copy the staging buffer back into the frontvp at
12807c478bd9Sstevel@tonic-gate 		 * blockoff.
12817c478bd9Sstevel@tonic-gate 		 */
12827c478bd9Sstevel@tonic-gate 		bcopy(fbp->fb_addr, buf, MAXBSIZE);
12837c478bd9Sstevel@tonic-gate 		fbrelse(fbp, S_OTHER);
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 		for (offset = 0;
12867c478bd9Sstevel@tonic-gate 		    offset < MAXBSIZE &&
12877c478bd9Sstevel@tonic-gate 		    (blockoff + (u_offset_t)offset) < dir_size;
12887c478bd9Sstevel@tonic-gate 		    offset += dep->d_length) {
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 			dep = (struct c_dirent *)((uintptr_t)buf + offset);
12917c478bd9Sstevel@tonic-gate 			ASSERT(dep->d_length != 0);
12927c478bd9Sstevel@tonic-gate 			if ((dep->d_flag & (CDE_VALID | CDE_COMPLETE)) !=
12937c478bd9Sstevel@tonic-gate 			    CDE_VALID)
12947c478bd9Sstevel@tonic-gate 				continue;
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 			error = VOP_LOOKUP(backvp, dep->d_name,
12977c478bd9Sstevel@tonic-gate 			    &entry_vp, (struct pathname *)NULL, 0,
1298*da6c28aaSamw 			    (vnode_t *)NULL, cr, NULL, NULL, NULL);
12997c478bd9Sstevel@tonic-gate 			if (error) {
13007c478bd9Sstevel@tonic-gate 				/* lookup on .. in / on coc gets ENOENT */
13017c478bd9Sstevel@tonic-gate 				if (error == ENOENT) {
13027c478bd9Sstevel@tonic-gate 					error = 0;
13037c478bd9Sstevel@tonic-gate 					continue;
13047c478bd9Sstevel@tonic-gate 				}
13057c478bd9Sstevel@tonic-gate 				goto out;
13067c478bd9Sstevel@tonic-gate 			}
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 			error = cachefs_getcookie(entry_vp, &cookie, NULL, cr,
13097c478bd9Sstevel@tonic-gate 				TRUE);
13107c478bd9Sstevel@tonic-gate 			if (error) {
13117c478bd9Sstevel@tonic-gate #ifdef CFSDEBUG
13127c478bd9Sstevel@tonic-gate 				CFS_DEBUG(CFSDEBUG_DIR)
13137c478bd9Sstevel@tonic-gate 					printf("\t%s: getcookie error\n",
13147c478bd9Sstevel@tonic-gate 					    dep->d_name);
13157c478bd9Sstevel@tonic-gate #endif /* CFSDEBUG */
13167c478bd9Sstevel@tonic-gate 				VN_RELE(entry_vp);
13177c478bd9Sstevel@tonic-gate 				goto out;
13187c478bd9Sstevel@tonic-gate 			}
13197c478bd9Sstevel@tonic-gate 			CACHEFS_FID_COPY(&cookie, &dep->d_cookie);
13207c478bd9Sstevel@tonic-gate 			dep->d_flag |= CDE_COMPLETE;
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate 			if ((! acltoo) ||
13237c478bd9Sstevel@tonic-gate 			    (! cachefs_vtype_aclok(entry_vp)) ||
13247c478bd9Sstevel@tonic-gate 			    (fscp->fs_info.fi_mntflags & CFS_NOACL)) {
13257c478bd9Sstevel@tonic-gate 				VN_RELE(entry_vp);
13267c478bd9Sstevel@tonic-gate 				continue;
13277c478bd9Sstevel@tonic-gate 			}
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 			error = cachefs_cnode_make(&dep->d_id, fscp, &cookie,
13307c478bd9Sstevel@tonic-gate 			    NULL, entry_vp, cr, 0, &cp);
13317c478bd9Sstevel@tonic-gate 			VN_RELE(entry_vp);
13327c478bd9Sstevel@tonic-gate 			if (error != 0)
13337c478bd9Sstevel@tonic-gate 				goto out;
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 			ASSERT(cp != NULL);
13367c478bd9Sstevel@tonic-gate 			mutex_enter(&cp->c_statelock);
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 			if ((cp->c_flags & CN_NOCACHE) ||
13397c478bd9Sstevel@tonic-gate 			    (cp->c_metadata.md_flags & MD_ACL)) {
13407c478bd9Sstevel@tonic-gate 				mutex_exit(&cp->c_statelock);
13417c478bd9Sstevel@tonic-gate 				VN_RELE(CTOV(cp));
13427c478bd9Sstevel@tonic-gate 				continue;
13437c478bd9Sstevel@tonic-gate 			}
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 			(void) cachefs_cacheacl(cp, NULL);
13467c478bd9Sstevel@tonic-gate 			mutex_exit(&cp->c_statelock);
13477c478bd9Sstevel@tonic-gate 			VN_RELE(CTOV(cp));
13487c478bd9Sstevel@tonic-gate 		}
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 		/*
13517c478bd9Sstevel@tonic-gate 		 * We must now re-lock the page corresponding to the frontvp,
13527c478bd9Sstevel@tonic-gate 		 * and copy our staging buffer onto it.
13537c478bd9Sstevel@tonic-gate 		 */
13547c478bd9Sstevel@tonic-gate 		if (error = fbread(frontvp, (offset_t)blockoff,
13557c478bd9Sstevel@tonic-gate 		    MAXBSIZE, S_OTHER, &fbp))
13567c478bd9Sstevel@tonic-gate 			goto out;
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 		bcopy(buf, fbp->fb_addr, MAXBSIZE);
13597c478bd9Sstevel@tonic-gate 		(void) fbdwrite(fbp);
13607c478bd9Sstevel@tonic-gate 	}
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate out:
13637c478bd9Sstevel@tonic-gate 	kmem_free(buf, MAXBSIZE);
13647c478bd9Sstevel@tonic-gate 	return (error);
13657c478bd9Sstevel@tonic-gate }
1366