Home | History | Annotate | Download | only in cachefs
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     26 
     27 #include <sys/param.h>
     28 #include <sys/types.h>
     29 #include <sys/systm.h>
     30 #include <sys/cred.h>
     31 #include <sys/proc.h>
     32 #include <sys/user.h>
     33 #include <sys/vfs.h>
     34 #include <sys/vnode.h>
     35 #include <sys/pathname.h>
     36 #include <sys/uio.h>
     37 #include <sys/tiuser.h>
     38 #include <sys/sysmacros.h>
     39 #include <sys/kmem.h>
     40 #include <sys/ioctl.h>
     41 #include <sys/statvfs.h>
     42 #include <sys/errno.h>
     43 #include <sys/debug.h>
     44 #include <sys/cmn_err.h>
     45 #include <sys/utsname.h>
     46 #include <sys/modctl.h>
     47 #include <sys/dirent.h>
     48 #include <sys/fbuf.h>
     49 #include <rpc/types.h>
     50 #include <vm/seg.h>
     51 #include <vm/faultcode.h>
     52 #include <vm/hat.h>
     53 #include <vm/seg_map.h>
     54 #include <sys/fs/cachefs_fs.h>
     55 #include <sys/fs/cachefs_dir.h>
     56 #include <sys/fs/cachefs_log.h>
     57 
     58 /* forward declarations */
     59 static int cachefs_dir_getentrys(struct cnode *, u_offset_t, u_offset_t *,
     60     uint_t *, uint_t, caddr_t, int *);
     61 static int cachefs_dir_stuff(cnode_t *dcp, uint_t count, caddr_t buf,
     62     vnode_t *frontvp, u_offset_t *offsetp, u_offset_t *fsizep);
     63 static int cachefs_dir_extend(cnode_t *, u_offset_t *, int incr_frontblks);
     64 static int cachefs_dir_fill_common(cnode_t *dcp, cred_t *cr,
     65     vnode_t *frontvp, vnode_t *backvp, u_offset_t *frontsize);
     66 static int cachefs_dir_complete(fscache_t *fscp, vnode_t *backvp,
     67     vnode_t *frontvp, cred_t *cr, int acltoo);
     68 
     69 
     70 
     71 /*
     72  * cachefs_dir_look() called mainly by lookup (and create), looks up the cached
     73  * directory for an entry and returns the information there. If the directory
     74  * entry doesn't exist return ENOENT, if it is incomplete, return EINVAL.
     75  * Should only call this routine if the dir is populated.
     76  * Returns ENOTDIR if dir gets nuked because of front file problems.
     77  */
     78 int
     79 cachefs_dir_look(cnode_t *dcp, char *nm, fid_t *cookiep, uint_t *flagp,
     80     u_offset_t *d_offsetp, cfs_cid_t *cidp)
     81 {
     82 	int error;
     83 	struct vattr va;
     84 	u_offset_t blockoff = 0LL;
     85 	uint_t offset = 0; /* offset inside the block of size MAXBSIZE */
     86 	vnode_t *dvp;
     87 	struct fscache *fscp = C_TO_FSCACHE(dcp);
     88 	cachefscache_t *cachep = fscp->fs_cache;
     89 	int nmlen;
     90 	struct fbuf *fbp;
     91 
     92 #ifdef CFSDEBUG
     93 	CFS_DEBUG(CFSDEBUG_DIR)
     94 		printf("cachefs_dir_look: ENTER dcp %p nm %s\n", (void *)dcp,
     95 									nm);
     96 #endif
     97 	ASSERT(CTOV(dcp)->v_type == VDIR);
     98 	ASSERT(dcp->c_metadata.md_flags & MD_POPULATED);
     99 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
    100 
    101 	if (dcp->c_frontvp == NULL)
    102 		(void) cachefs_getfrontfile(dcp);
    103 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
    104 		error = ENOTDIR;
    105 		goto out;
    106 	}
    107 
    108 	dvp = dcp->c_frontvp;
    109 	va.va_mask = AT_SIZE;		/* XXX should save dir size */
    110 	error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
    111 	if (error) {
    112 		cachefs_inval_object(dcp);
    113 		error = ENOTDIR;
    114 		goto out;
    115 	}
    116 
    117 	ASSERT(va.va_size != 0LL);
    118 	nmlen = (int)strlen(nm);
    119 	while (blockoff < va.va_size) {
    120 		offset = 0;
    121 		error =
    122 		    fbread(dvp, (offset_t)blockoff, MAXBSIZE, S_OTHER, &fbp);
    123 		if (error)
    124 			goto out;
    125 
    126 		while (offset < MAXBSIZE && (blockoff + offset) < va.va_size) {
    127 			struct c_dirent *dep;
    128 
    129 			dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr +
    130 								offset);
    131 			if ((dep->d_flag & CDE_VALID) &&
    132 				(nmlen == dep->d_namelen) &&
    133 				strcmp(dep->d_name, nm) == 0) {
    134 				if (dep->d_flag & CDE_COMPLETE) {
    135 					if (cookiep) {
    136 						CACHEFS_FID_COPY(&dep->d_cookie,
    137 							cookiep);
    138 					}
    139 					if (flagp)
    140 						*flagp = dep->d_flag;
    141 					error = 0;
    142 				} else {
    143 					error = EINVAL;
    144 				}
    145 				if (cidp)
    146 					*cidp = dep->d_id;
    147 				if (d_offsetp)
    148 					*d_offsetp = offset + blockoff;
    149 				fbrelse(fbp, S_OTHER);
    150 				goto out;
    151 			}
    152 			ASSERT(dep->d_length != 0);
    153 			offset += dep->d_length;
    154 		}
    155 		fbrelse(fbp, S_OTHER);
    156 		blockoff += MAXBSIZE;
    157 	}
    158 	error = ENOENT;
    159 
    160 out:
    161 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_RFDIR))
    162 		cachefs_log_rfdir(cachep, error, fscp->fs_cfsvfsp,
    163 		    &dcp->c_metadata.md_cookie, dcp->c_id.cid_fileno, 0);
    164 #ifdef CFSDEBUG
    165 	CFS_DEBUG(CFSDEBUG_DIR)
    166 		printf("c_dir_look: EXIT error = %d\n", error);
    167 #endif
    168 	return (error);
    169 }
    170 
    171 /*
    172  * creates a new directory and populates it with "." and ".."
    173  */
    174 int
    175 cachefs_dir_new(cnode_t *dcp, cnode_t *cp)
    176 {
    177 	int		error = 0;
    178 	struct c_dirent	*dep;
    179 	u_offset_t	size;
    180 	int len;
    181 	struct fbuf	*fbp;
    182 #ifdef CFSDEBUG
    183 	struct vattr	va;
    184 
    185 	CFS_DEBUG(CFSDEBUG_DIR)
    186 		printf("c_dir_new: ENTER dcp %p cp %p\n", (void *)dcp,
    187 							(void *)cp);
    188 #endif
    189 
    190 	ASSERT(MUTEX_HELD(&cp->c_statelock));
    191 	ASSERT(CTOV(cp)->v_type == VDIR);
    192 	ASSERT((cp->c_flags & CN_ASYNC_POPULATE) == 0);
    193 	ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(dcp)) == 0);
    194 
    195 	if (cp->c_frontvp == NULL) {
    196 		error = cachefs_getfrontfile(cp);
    197 		if (error)
    198 			goto out;
    199 	}
    200 
    201 #ifdef CFSDEBUG
    202 	va.va_mask = AT_SIZE;
    203 	error = VOP_GETATTR(cp->c_frontvp, &va, 0, kcred, NULL);
    204 	if (error)
    205 		goto out;
    206 	ASSERT(va.va_size == 0);
    207 #endif
    208 
    209 	/*
    210 	 * Extend the directory by one MAXBSIZE chunk
    211 	 */
    212 	size = 0LL;
    213 	error = cachefs_dir_extend(cp, &size, 1);
    214 	if (error != 0)
    215 		goto out;
    216 	error = fbread(cp->c_frontvp, (offset_t)0, MAXBSIZE, S_OTHER, &fbp);
    217 	if (error)
    218 		goto out;
    219 
    220 	/*
    221 	 * Insert "." and ".."
    222 	 */
    223 	len = (int)CDE_SIZE(".");
    224 	dep = (struct c_dirent *)fbp->fb_addr;
    225 	dep->d_length = len;
    226 	dep->d_offset = (offset_t)len;
    227 	dep->d_flag = CDE_VALID | CDE_COMPLETE;
    228 	CACHEFS_FID_COPY(&cp->c_cookie, &dep->d_cookie);
    229 	dep->d_id = cp->c_id;
    230 	dep->d_namelen = 1;
    231 	bcopy(".", dep->d_name, 2);
    232 
    233 	dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + len);
    234 	dep->d_length = MAXBSIZE - len;
    235 	dep->d_offset = MAXBSIZE;
    236 	dep->d_flag = CDE_VALID | CDE_COMPLETE;
    237 	CACHEFS_FID_COPY(&dcp->c_cookie, &dep->d_cookie);
    238 	dep->d_id = dcp->c_id;
    239 	dep->d_namelen = 2;
    240 	bcopy("..", dep->d_name, 3);
    241 
    242 	(void) fbdwrite(fbp);
    243 #ifdef INVALREADDIR
    244 	cp->c_metadata.md_flags |= MD_POPULATED | MD_INVALREADDIR;
    245 #else
    246 	cp->c_metadata.md_flags |= MD_POPULATED;
    247 #endif
    248 	cp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
    249 out:
    250 #ifdef CFSDEBUG
    251 	CFS_DEBUG(CFSDEBUG_DIR)
    252 		printf("cachefs_dir_new: EXIT error = %d\n", error);
    253 #endif
    254 	return (error);
    255 }
    256 
    257 /*
    258  * cachefs_dir_enter adds a new directory entry. Takes as input a fid,
    259  * fileno and a sync flag. Most of the time, the caller is content with the
    260  * write to the (front) directory being done async. The exception being - for
    261  * local files, we should make sure that the directory entry is made
    262  * synchronously. That is notified by the caller.
    263  * 		issync == 0 || issync == SM_ASYNC !
    264  *
    265  * The new entry is inserted at the end, so that we can generate local offsets
    266  * which are compatible with the backfs offsets (which are used when
    267  * disconnected.
    268  */
    269 int
    270 cachefs_dir_enter(cnode_t *dcp, char *nm, fid_t *cookiep, cfs_cid_t *cidp,
    271     int issync)
    272 {
    273 	struct vattr	va;
    274 	int offset;
    275 	u_offset_t blockoff = 0LL;
    276 	u_offset_t	prev_offset;
    277 	int		error = 0;
    278 	vnode_t		*dvp;
    279 	struct c_dirent	*dep;
    280 	uint_t		esize;
    281 	u_offset_t	dirsize;
    282 	struct fbuf	*fbp;
    283 
    284 #ifdef CFSDEBUG
    285 	CFS_DEBUG(CFSDEBUG_DIR)
    286 		printf("c_dir_enter: ENTER dcp %p nm %s dirflg %x\n",
    287 			(void *)dcp, nm, dcp->c_metadata.md_flags);
    288 #endif
    289 
    290 	ASSERT(MUTEX_HELD(&dcp->c_statelock));
    291 	ASSERT(dcp->c_metadata.md_flags & MD_POPULATED);
    292 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
    293 	ASSERT(CTOV(dcp)->v_type == VDIR);
    294 	ASSERT(issync == 0 || issync == SM_ASYNC);
    295 	ASSERT(strlen(nm) <= MAXNAMELEN);
    296 
    297 	if (dcp->c_frontvp == NULL)
    298 		(void) cachefs_getfrontfile(dcp);
    299 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
    300 		error = ENOTDIR;
    301 		goto out;
    302 	}
    303 	dvp = dcp->c_frontvp;
    304 
    305 	/*
    306 	 * Get the current EOF for the directory(data file)
    307 	 */
    308 	va.va_mask = AT_SIZE;
    309 	error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
    310 	if (error) {
    311 		cachefs_inval_object(dcp);
    312 		error = ENOTDIR;
    313 		goto out;
    314 	}
    315 
    316 	/*
    317 	 * Get the last block of the directory
    318 	 */
    319 	dirsize = va.va_size;
    320 	ASSERT(dirsize != 0LL);
    321 	ASSERT(!(dirsize & MAXBOFFSET));
    322 	ASSERT(dirsize <= MAXOFF_T);
    323 	blockoff = dirsize - MAXBSIZE;
    324 	error = fbread(dvp, (offset_t)blockoff, MAXBSIZE, S_OTHER, &fbp);
    325 	if (error)
    326 		goto out;
    327 
    328 	/*
    329 	 * Find the last entry
    330 	 */
    331 	offset = 0;
    332 	prev_offset = blockoff;
    333 	for (;;) {
    334 		dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + offset);
    335 		if (offset + dep->d_length == MAXBSIZE)
    336 			break;
    337 		prev_offset = dep->d_offset;
    338 		offset += dep->d_length;
    339 		ASSERT(offset < MAXBSIZE);
    340 	}
    341 	esize = C_DIRSIZ(dep);
    342 
    343 	if (dep->d_length - esize >= CDE_SIZE(nm)) {
    344 		/*
    345 		 * It has room. If the entry is not valid, we can just use
    346 		 * it. Otherwise, we need to adjust its length and offset
    347 		 */
    348 #ifdef CFSDEBUG
    349 		CFS_DEBUG(CFSDEBUG_DIR) {
    350 			if (prev_offset >= dep->d_offset) {
    351 				printf("cachefs_dir_enter: looks like "
    352 				    "we might fail the assert\n");
    353 				printf("addr %p, offset %x, "
    354 				    "prev_offset %llx, dep->d_offset %llx\n",
    355 				    (void *)fbp->fb_addr, offset, prev_offset,
    356 				    dep->d_offset);
    357 				offset = 0;
    358 				prev_offset = blockoff;
    359 				for (;;) {
    360 					dep = (struct c_dirent *)
    361 					    ((uintptr_t)fbp->fb_addr + offset);
    362 					printf("offset %x, prev_offset %llx\n",
    363 					    offset, prev_offset);
    364 					printf("dep->d_offset %llx, "
    365 					    "dep->d_length %x\n",
    366 					    dep->d_offset, dep->d_length);
    367 					if (offset + dep->d_length == MAXBSIZE)
    368 						break;
    369 					prev_offset = dep->d_offset;
    370 					offset += dep->d_length;
    371 				}
    372 			}
    373 		}
    374 #endif /* CFSDEBUG */
    375 
    376 		if (offset)
    377 			ASSERT(prev_offset < dep->d_offset);
    378 		if (dep->d_flag & CDE_VALID) {
    379 			dep->d_length = esize;
    380 			dep->d_offset = prev_offset + (u_offset_t)esize;
    381 			dep = (struct c_dirent *)((uintptr_t)dep + esize);
    382 		}
    383 		dep->d_length = (int)((offset_t)MAXBSIZE -
    384 				((uintptr_t)dep - (uintptr_t)fbp->fb_addr));
    385 	} else {
    386 		/*
    387 		 * No room - so extend the file by one more
    388 		 * MAXBSIZE chunk, and fit the entry there.
    389 		 */
    390 		fbrelse(fbp, S_OTHER);
    391 		error = cachefs_dir_extend(dcp, &dirsize, 1);
    392 		if (error != 0)
    393 			goto out;
    394 		error =
    395 		    fbread(dvp, (offset_t)va.va_size, MAXBSIZE, S_OTHER, &fbp);
    396 		if (error)
    397 			goto out;
    398 		dep = (struct c_dirent *)fbp->fb_addr;
    399 		dep->d_length = MAXBSIZE;
    400 	}
    401 
    402 	/*
    403 	 * Fill in the rest of the new entry
    404 	 */
    405 	dep->d_offset = dirsize;
    406 	dep->d_flag = CDE_VALID;
    407 	if (cookiep) {
    408 		dep->d_flag |= CDE_COMPLETE;
    409 		CACHEFS_FID_COPY(cookiep, &dep->d_cookie);
    410 	}
    411 	dep->d_id = *cidp;
    412 	dep->d_namelen = (ushort_t)strlen(nm);
    413 	(void) bcopy(nm, dep->d_name, dep->d_namelen + 1);
    414 
    415 #ifdef INVALREADDIR
    416 	dcp->c_metadata.md_flags |= MD_INVALREADDIR;
    417 #endif
    418 	dcp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
    419 	if (issync)
    420 		(void) fbwrite(fbp);
    421 	else
    422 		(void) fbdwrite(fbp);
    423 out:
    424 #ifdef CFSDEBUG
    425 	CFS_DEBUG(CFSDEBUG_DIR)
    426 		printf("cachefs_dir_enter: EXIT error = %d\n", error);
    427 #endif
    428 	return (error);
    429 }
    430 
    431 /*
    432  * Quite simple, if the deleted entry is the first in the MAXBSIZE block,
    433  * we simply mark it invalid. Otherwise, the deleted entries d_length is
    434  * just added to the previous entry.
    435  */
    436 int
    437 cachefs_dir_rmentry(cnode_t *dcp, char *nm)
    438 {
    439 	u_offset_t blockoff = 0LL;
    440 	int offset = 0;
    441 	struct vattr va;
    442 	int error = ENOENT;
    443 	vnode_t *dvp;
    444 	int nmlen;
    445 	struct fbuf *fbp;
    446 
    447 #ifdef CFSDEBUG
    448 	CFS_DEBUG(CFSDEBUG_DIR)
    449 		printf("cachefs_dir_rmentry: ENTER dcp %p nm %s\n",
    450 		    (void *)dcp, nm);
    451 #endif
    452 	ASSERT(dcp->c_metadata.md_flags & MD_POPULATED);
    453 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
    454 
    455 	if (dcp->c_frontvp == NULL)
    456 		(void) cachefs_getfrontfile(dcp);
    457 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
    458 		error = ENOTDIR;
    459 		goto out;
    460 	}
    461 	dvp = dcp->c_frontvp;
    462 
    463 	ASSERT(CTOV(dcp)->v_type == VDIR);
    464 	ASSERT((dcp->c_flags & CN_NOCACHE) == 0);
    465 	ASSERT(dvp != NULL);
    466 	va.va_mask = AT_SIZE;
    467 	error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
    468 	if (error) {
    469 		cachefs_inval_object(dcp);
    470 		error = ENOTDIR;
    471 		goto out;
    472 	}
    473 	ASSERT(va.va_size != 0LL);
    474 
    475 	nmlen = (int)strlen(nm);
    476 	while (blockoff < va.va_size) {
    477 		uint_t *last_len;
    478 
    479 		offset = 0;
    480 		last_len = NULL;
    481 		error =
    482 		    fbread(dvp, (offset_t)blockoff, MAXBSIZE, S_OTHER, &fbp);
    483 		if (error)
    484 			goto out;
    485 		while (offset < MAXBSIZE && (blockoff + offset) < va.va_size) {
    486 			struct c_dirent *dep;
    487 
    488 			dep  = (struct c_dirent *)((uintptr_t)fbp->fb_addr +
    489 								offset);
    490 			if ((dep->d_flag & CDE_VALID) &&
    491 				(nmlen == dep->d_namelen) &&
    492 				strcmp(dep->d_name, nm) == 0) {
    493 				/*
    494 				 * Found the entry. If this was the first entry
    495 				 * in the MAXBSIZE block, Mark it invalid. Else
    496 				 * add it's length to the previous entry's
    497 				 * length.
    498 				 */
    499 				if (last_len == NULL) {
    500 					ASSERT(offset == 0);
    501 					dep->d_flag = 0;
    502 				} else
    503 					*last_len += dep->d_length;
    504 				(void) fbdwrite(fbp);
    505 				dcp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
    506 				goto out;
    507 			}
    508 			last_len = &dep->d_length;
    509 			offset += dep->d_length;
    510 		}
    511 		fbrelse(fbp, S_OTHER);
    512 		blockoff += MAXBSIZE;
    513 	}
    514 	error = ENOENT;
    515 
    516 out:
    517 #ifdef CFSDEBUG
    518 	CFS_DEBUG(CFSDEBUG_DIR)
    519 		printf("cachefs_dir_rmentry: EXIT error = %d\n", error);
    520 #endif
    521 	return (error);
    522 }
    523 
    524 #if 0
    525 /*
    526  * This function is used only in cachefs_lookup_back() routine but
    527  * is inside #if 0 directive in this routine. So I am keeping this
    528  * routine also in #if 0 directive.
    529  */
    530 
    531 /*
    532  * This function fills in the cookie and file no of the directory entry
    533  * at the offset specified by offset - In other words, makes the entry
    534  * "complete".
    535  */
    536 int
    537 cachefs_dir_modentry(cnode_t *dcp, u_offset_t offset, fid_t *cookiep,
    538     cfs_cid_t *cidp)
    539 {
    540 	struct c_dirent *dep;
    541 	u_offset_t blockoff = (offset & (offset_t)MAXBMASK);
    542 	uint_t off = (uint_t)(offset & (offset_t)MAXBOFFSET);
    543 	struct fbuf *fbp;
    544 	vnode_t *dvp;
    545 	int error = 0;
    546 
    547 #ifdef CFSDEBUG
    548 	CFS_DEBUG(CFSDEBUG_DIR)
    549 		printf("cachefs_dir_modentry: ENTER dcp %p offset %lld\n",
    550 			(void *)dcp, offset);
    551 #endif
    552 	ASSERT(CTOV(dcp)->v_type == VDIR);
    553 	ASSERT(dcp->c_metadata.md_flags & MD_POPULATED);
    554 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
    555 
    556 	if (dcp->c_frontvp == NULL)
    557 		(void) cachefs_getfrontfile(dcp);
    558 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
    559 		return;
    560 	}
    561 	dvp = dcp->c_frontvp;
    562 
    563 	error = fbread(dvp, (offset_t)blockoff, MAXBSIZE, S_OTHER, &fbp);
    564 	if (error)
    565 		goto out;
    566 	dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + off);
    567 	if (cookiep) {
    568 		dep->d_flag |= CDE_COMPLETE;
    569 		CACHEFS_FID_COPY(cookiep, &dep->d_cookie);
    570 	}
    571 	if (cidp)
    572 		dep->d_id = *cidp;
    573 	(void) fbdwrite(fbp);
    574 	dcp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
    575 
    576 out:
    577 #ifdef CFSDEBUG
    578 	CFS_DEBUG(CFSDEBUG_DIR)
    579 		printf("cachefs_dir_modentry: EXIT\n");
    580 #endif
    581 	return (error);
    582 }
    583 
    584 #endif  /* of #if 0 */
    585 
    586 /*
    587  * Called by cachefs_read_dir(). Gets a bunch if directory entries into buf and
    588  * packs them into buf.
    589  */
    590 static int
    591 cachefs_dir_getentrys(struct cnode *dcp, u_offset_t beg_off,
    592 		u_offset_t *last_offp, uint_t *cntp, uint_t bufsize,
    593 				caddr_t buf, int *eofp)
    594 {
    595 
    596 #define	DIR_ENDOFF	0x7fffffffLL
    597 
    598 	struct vattr va;
    599 	struct c_dirent *dep;
    600 	struct fbuf *fbp = NULL;
    601 	struct dirent64 *gdp;
    602 	u_offset_t blockoff;
    603 	uint_t off;
    604 	int error;
    605 	vnode_t *dvp = dcp->c_frontvp;
    606 
    607 #ifdef CFSDEBUG
    608 	CFS_DEBUG(CFSDEBUG_DIR)
    609 	printf("cachefs_dir_getentrys: "
    610 	    "ENTER dcp %p beg_off %lld mdflags %x cflags %x\n",
    611 	    dcp, beg_off, dcp->c_metadata.md_flags, dcp->c_flags);
    612 #endif
    613 
    614 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
    615 
    616 	/*
    617 	 * blockoff has the offset of the MAXBSIZE block that contains the
    618 	 * entry  to start with. off contains the offset relative to the
    619 	 * begining of the MAXBSIZE block.
    620 	 */
    621 	if (eofp)
    622 		*eofp = 0;
    623 	gdp = (struct dirent64 *)buf;
    624 	*cntp = bufsize;
    625 	va.va_mask = AT_SIZE;
    626 	error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
    627 	if (error) {
    628 		*cntp = 0;
    629 		*last_offp = 0;
    630 		if (eofp)
    631 			*eofp = 1;
    632 		goto out;
    633 	}
    634 	ASSERT(va.va_size != 0LL);
    635 
    636 	if (beg_off == DIR_ENDOFF) {
    637 		*cntp = 0;
    638 		*last_offp = DIR_ENDOFF;
    639 		if (eofp)
    640 			*eofp = 1;
    641 		goto out;
    642 	}
    643 
    644 	/*
    645 	 * locate the offset where we start reading.
    646 	 */
    647 	for (blockoff = 0; blockoff < va.va_size; blockoff += MAXBSIZE) {
    648 		error =
    649 		    fbread(dvp, (offset_t)blockoff, MAXBSIZE, S_OTHER, &fbp);
    650 		if (error)
    651 			goto out;
    652 		dep = (struct c_dirent *)fbp->fb_addr;
    653 		off = 0;
    654 		while (off < MAXBSIZE && dep->d_offset <= beg_off) {
    655 			off += dep->d_length;
    656 			dep =
    657 			    (struct c_dirent *)((uintptr_t)fbp->fb_addr + off);
    658 		}
    659 		if (off < MAXBSIZE)
    660 			break;
    661 		fbrelse(fbp, S_OTHER);
    662 		fbp = NULL;
    663 	}
    664 
    665 	if (blockoff >= va.va_size) {
    666 		*cntp = 0;
    667 		*last_offp = DIR_ENDOFF;
    668 		if (eofp)
    669 			*eofp = 1;
    670 		goto out;
    671 	}
    672 
    673 	/*
    674 	 * Just load up the buffer with directory entries.
    675 	 */
    676 	for (;;) {
    677 		uint_t size;
    678 		int this_reclen;
    679 
    680 		ASSERT((uintptr_t)dep < ((uintptr_t)fbp->fb_addr + MAXBSIZE));
    681 		if (dep->d_flag & CDE_VALID) {
    682 			this_reclen = DIRENT64_RECLEN(dep->d_namelen);
    683 			size = C_DIRSIZ(dep);
    684 			ASSERT(size < MAXBSIZE);
    685 			if (this_reclen > bufsize)
    686 				break;
    687 			ASSERT(dep->d_namelen <= MAXNAMELEN);
    688 			ASSERT(dep->d_offset > (*last_offp));
    689 			gdp->d_ino = dep->d_id.cid_fileno;
    690 			gdp->d_off = dep->d_offset;
    691 
    692 			/* use strncpy(9f) to zero out uninitialized bytes */
    693 
    694 			ASSERT(strlen(dep->d_name) + 1 <=
    695 			    DIRENT64_NAMELEN(this_reclen));
    696 			(void) strncpy(gdp->d_name, dep->d_name,
    697 			    DIRENT64_NAMELEN(this_reclen));
    698 
    699 			gdp->d_reclen = (ushort_t)this_reclen;
    700 			bufsize -= this_reclen;
    701 			gdp = (struct dirent64 *)((uintptr_t)gdp +
    702 				gdp->d_reclen);
    703 			*last_offp = dep->d_offset;
    704 		}
    705 
    706 		/*
    707 		 * Increment the offset. If we've hit EOF, fill in
    708 		 * the lastoff and current entries d_off field.
    709 		 */
    710 		off += dep->d_length;
    711 		ASSERT(off <= MAXBSIZE);
    712 		if ((blockoff + off) >= va.va_size) {
    713 			*last_offp = DIR_ENDOFF;
    714 			if (eofp)
    715 				*eofp = 1;
    716 			break;
    717 		}
    718 		/*
    719 		 * If off == MAXBSIZE, then we need to adjust our
    720 		 * window to the next MAXBSIZE block of the directory.
    721 		 * Adjust blockoff, off and map it in. Also, increment
    722 		 * the directory and buffer pointers.
    723 		 */
    724 		if (off == MAXBSIZE) {
    725 			fbrelse(fbp, S_OTHER);
    726 			fbp = NULL;
    727 			off = 0;
    728 			blockoff += MAXBSIZE;
    729 			error = fbread(dvp, (offset_t)blockoff, MAXBSIZE,
    730 								S_OTHER, &fbp);
    731 			if (error)
    732 				goto out;
    733 		}
    734 		dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + off);
    735 	}
    736 	*cntp -= bufsize;
    737 out:
    738 	/*
    739 	 * Release any buffer and maping that may exist.
    740 	 */
    741 	if (fbp)
    742 		(void) fbrelse(fbp, S_OTHER);
    743 #ifdef CFSDEBUG
    744 	CFS_DEBUG(CFSDEBUG_DIR)
    745 		printf("ccachefs_dir_getentrys: EXIT error = %d\n", error);
    746 #endif
    747 	return (error);
    748 }
    749 
    750 /*
    751  * Called by cachefs_readdir(). Fills a directory request from the cache
    752  */
    753 int
    754 cachefs_dir_read(struct cnode *dcp, struct uio *uiop, int *eofp)
    755 {
    756 	int error;
    757 	uint_t count;
    758 	uint_t size;
    759 	caddr_t buf;
    760 	u_offset_t next = uiop->uio_loffset;
    761 	struct fscache *fscp = C_TO_FSCACHE(dcp);
    762 	cachefscache_t *cachep = fscp->fs_cache;
    763 	caddr_t chrp, end;
    764 	dirent64_t *de;
    765 
    766 	ASSERT(CTOV(dcp)->v_type == VDIR);
    767 	ASSERT(RW_READ_HELD(&dcp->c_rwlock));
    768 
    769 	ASSERT(next <= MAXOFF_T);
    770 #ifdef CFSDEBUG
    771 	CFS_DEBUG(CFSDEBUG_DIR)
    772 		printf("cachefs_dir_read: ENTER dcp %p\n", (void *)dcp);
    773 #endif
    774 	ASSERT((dcp->c_metadata.md_flags & (MD_FILE|MD_POPULATED)) ==
    775 	    (MD_FILE|MD_POPULATED));
    776 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
    777 
    778 	if (dcp->c_frontvp == NULL)
    779 		(void) cachefs_getfrontfile(dcp);
    780 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
    781 		error = ENOTDIR;
    782 		goto out;
    783 	}
    784 
    785 	size = (uint_t)uiop->uio_resid;
    786 	buf = cachefs_kmem_alloc(size, KM_SLEEP);
    787 	error = cachefs_dir_getentrys(dcp, next, &next, &count, size,
    788 	    buf, eofp);
    789 	if (error == 0 && (int)count > 0) {
    790 		ASSERT(count <= size);
    791 		if (fscp->fs_inum_size > 0) {
    792 			ino64_t newinum;
    793 
    794 			mutex_exit(&dcp->c_statelock);
    795 			mutex_enter(&fscp->fs_fslock);
    796 			end = (caddr_t)((uintptr_t)buf + count);
    797 			for (chrp = buf; chrp < end; chrp += de->d_reclen) {
    798 				de = (dirent64_t *)chrp;
    799 
    800 				newinum = cachefs_inum_real2fake(fscp,
    801 				    de->d_ino);
    802 				if (newinum == 0)
    803 					newinum = cachefs_fileno_conflict(fscp,
    804 					    de->d_ino);
    805 				de->d_ino = newinum;
    806 			}
    807 			mutex_exit(&fscp->fs_fslock);
    808 			mutex_enter(&dcp->c_statelock);
    809 		}
    810 		error = uiomove(buf, count, UIO_READ, uiop);
    811 		if (error == 0)
    812 			uiop->uio_loffset = next;
    813 	}
    814 	(void) cachefs_kmem_free(buf, size);
    815 out:
    816 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_RFDIR))
    817 		cachefs_log_rfdir(cachep, error, fscp->fs_cfsvfsp,
    818 		    &dcp->c_metadata.md_cookie, dcp->c_id.cid_fileno, 0);
    819 #ifdef CFSDEBUG
    820 	CFS_DEBUG(CFSDEBUG_DIR)
    821 		printf("cachefs_dir_read: EXIT error = %d\n", error);
    822 #endif
    823 	return (error);
    824 }
    825 
    826 /*
    827  * Fully (including cookie) populates the directory from the back filesystem.
    828  */
    829 int
    830 cachefs_dir_fill(cnode_t *dcp, cred_t *cr)
    831 {
    832 	int error = 0;
    833 	u_offset_t frontsize;
    834 	struct fscache *fscp = C_TO_FSCACHE(dcp);
    835 
    836 #ifdef CFSDEBUG
    837 	CFS_DEBUG(CFSDEBUG_DIR)
    838 		printf("cachefs_dir_fill: ENTER dcp %p\n", (void *)dcp);
    839 #endif
    840 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
    841 	ASSERT(MUTEX_HELD(&dcp->c_statelock));
    842 
    843 	/* XXX for now return success if async populate is scheduled */
    844 	if (dcp->c_flags & CN_ASYNC_POPULATE)
    845 		goto out;
    846 
    847 	/* get the back vp */
    848 	if (dcp->c_backvp == NULL) {
    849 		error = cachefs_getbackvp(fscp, dcp);
    850 		if (error) {
    851 			goto out;
    852 		}
    853 	}
    854 
    855 	/* get the front file vp */
    856 	if (dcp->c_frontvp == NULL)
    857 		(void) cachefs_getfrontfile(dcp);
    858 	if (dcp->c_flags & CN_NOCACHE) {
    859 		error = ENOTDIR;
    860 		goto out;
    861 	}
    862 
    863 	/* if dir was modified, toss old contents */
    864 	if (dcp->c_metadata.md_flags & MD_INVALREADDIR) {
    865 		cachefs_inval_object(dcp);
    866 		if (dcp->c_flags & CN_NOCACHE) {
    867 			error = ENOTDIR;
    868 			goto out;
    869 		}
    870 	}
    871 
    872 	error = cachefs_dir_fill_common(dcp, cr,
    873 	    dcp->c_frontvp, dcp->c_backvp, &frontsize);
    874 	if (error == 0)
    875 		error = cachefs_dir_complete(fscp, dcp->c_backvp,
    876 		    dcp->c_frontvp, cr, 0);
    877 	if (error != 0)
    878 		goto out;
    879 
    880 	/*
    881 	 * Mark the directory as not empty. Also bang the flag that says that
    882 	 * this directory needs to be sync'ed on inactive.
    883 	 */
    884 	dcp->c_metadata.md_flags |= MD_POPULATED;
    885 	dcp->c_metadata.md_flags &= ~MD_INVALREADDIR;
    886 	dcp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
    887 	/*LINTED alignment okay*/
    888 	dcp->c_metadata.md_frontblks = frontsize / MAXBSIZE;
    889 
    890 out:
    891 	if (error) {
    892 #ifdef CFSDEBUG
    893 		CFS_DEBUG(CFSDEBUG_INVALIDATE)
    894 			printf("c_dir_fill: invalidating %llu\n",
    895 			    (u_longlong_t)dcp->c_id.cid_fileno);
    896 #endif
    897 		cachefs_inval_object(dcp);
    898 	}
    899 
    900 	return (error);
    901 }
    902 
    903 /*
    904  * Does work of populating directory.
    905  * Must be called while holding dcp->c_statelock
    906  */
    907 
    908 static int
    909 cachefs_dir_fill_common(cnode_t *dcp, cred_t *cr,
    910     vnode_t *frontvp, vnode_t *backvp, u_offset_t *frontsize)
    911 {
    912 	int error = 0;
    913 	struct uio uio;
    914 	struct iovec iov;
    915 	caddr_t buf = NULL;
    916 	int count;
    917 	int eof = 0;
    918 	u_offset_t frontoff;
    919 	struct fscache *fscp = C_TO_FSCACHE(dcp);
    920 	cachefscache_t *cachep = fscp->fs_cache;
    921 #ifdef DEBUG
    922 	int loop_count = 0;
    923 #endif
    924 #ifdef CFSDEBUG
    925 	CFS_DEBUG(CFSDEBUG_DIR)
    926 		printf("cachefs_dir_fill_common: ENTER dcp %p\n", (void *)dcp);
    927 #endif
    928 
    929 	ASSERT(MUTEX_HELD(&dcp->c_statelock));
    930 
    931 	frontoff = *frontsize = 0LL;
    932 
    933 	buf = cachefs_kmem_alloc(MAXBSIZE, KM_SLEEP);
    934 	uio.uio_iov = &iov;
    935 	uio.uio_iovcnt = 1;
    936 	uio.uio_segflg = UIO_SYSSPACE;
    937 	uio.uio_fmode = 0;
    938 	uio.uio_extflg = UIO_COPY_CACHED;
    939 	uio.uio_loffset = 0;
    940 	for (;;) {
    941 #ifdef DEBUG
    942 		loop_count++;
    943 #endif
    944 		/*
    945 		 * Read in a buffer's worth of dirents and enter them in to the
    946 		 * directory.
    947 		 */
    948 		uio.uio_resid = MAXBSIZE;
    949 		iov.iov_base = buf;
    950 		iov.iov_len = MAXBSIZE;
    951 		(void) VOP_RWLOCK(backvp, V_WRITELOCK_FALSE, NULL);
    952 		error = VOP_READDIR(backvp, &uio, cr, &eof, NULL, 0);
    953 		VOP_RWUNLOCK(backvp, V_WRITELOCK_FALSE, NULL);
    954 		if (error)
    955 			goto out;
    956 
    957 		/*LINTED alignment okay*/
    958 		count = MAXBSIZE - (int)uio.uio_resid;
    959 		ASSERT(count >= 0);
    960 		if (count > 0) {
    961 			if (error = cachefs_dir_stuff(dcp, count, buf,
    962 			    frontvp, &frontoff, frontsize))
    963 				goto out;
    964 			ASSERT((*frontsize) != 0LL);
    965 		}
    966 		if (eof || count == 0)
    967 			break;
    968 	}
    969 
    970 	if (*frontsize == 0LL) {
    971 		/* keep us from caching an empty directory */
    972 		error = EINVAL;
    973 		goto out;
    974 	}
    975 
    976 out:
    977 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_FILLDIR))
    978 		cachefs_log_filldir(cachep, error, fscp->fs_cfsvfsp,
    979 		    &dcp->c_metadata.md_cookie, dcp->c_id.cid_fileno,
    980 		    *frontsize);
    981 	if (buf)
    982 		cachefs_kmem_free(buf, (uint_t)MAXBSIZE);
    983 
    984 #ifdef CFSDEBUG
    985 	CFS_DEBUG(CFSDEBUG_DIR)
    986 		printf("cachefs_dir_fill: EXIT error = %d\n", error);
    987 #endif
    988 	return (error);
    989 }
    990 
    991 /*
    992  * If the directory contains only the elements "." and "..", then this returns
    993  * 0, otherwise returns an error.
    994  */
    995 int
    996 cachefs_dir_empty(cnode_t *dcp)
    997 {
    998 	struct vattr va;
    999 	u_offset_t blockoff = 0;
   1000 	int offset;
   1001 	struct fbuf *fbp;
   1002 	int error;
   1003 	vnode_t *dvp = dcp->c_frontvp;
   1004 
   1005 #ifdef CFSDEBUG
   1006 	CFS_DEBUG(CFSDEBUG_DIR)
   1007 		printf("cachefs_dir_empty: ENTER dcp %p\n", (void *)dcp);
   1008 #endif
   1009 	ASSERT(CTOV(dcp)->v_type == VDIR);
   1010 	ASSERT(dcp->c_metadata.md_flags & MD_POPULATED);
   1011 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
   1012 
   1013 	if (dcp->c_frontvp == NULL)
   1014 		(void) cachefs_getfrontfile(dcp);
   1015 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0)
   1016 		return (ENOTDIR);
   1017 
   1018 	va.va_mask = AT_SIZE;
   1019 	error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
   1020 	if (error)
   1021 		return (ENOTDIR);
   1022 
   1023 	ASSERT(va.va_size != 0LL);
   1024 	while (blockoff < va.va_size) {
   1025 		offset = 0;
   1026 		error =
   1027 		    fbread(dvp, (offset_t)blockoff, MAXBSIZE, S_OTHER, &fbp);
   1028 		if (error)
   1029 			return (error);
   1030 		while (offset < MAXBSIZE && (blockoff + offset) < va.va_size) {
   1031 			struct c_dirent *dep;
   1032 
   1033 			dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr +
   1034 								offset);
   1035 			if ((dep->d_flag & CDE_VALID) &&
   1036 				((strcmp(dep->d_name, ".") != 0) &&
   1037 				(strcmp(dep->d_name, "..") != 0))) {
   1038 				(void) fbrelse(fbp, S_OTHER);
   1039 				return (0);
   1040 			}
   1041 			offset += dep->d_length;
   1042 		}
   1043 		(void) fbrelse(fbp, S_OTHER);
   1044 		blockoff += MAXBSIZE;
   1045 	}
   1046 	return (EEXIST);
   1047 }
   1048 
   1049 /*
   1050  * Called by cachefs_dir_fill() to stuff a buffer of dir entries into
   1051  * a front file.  This is more efficient than repeated calls to
   1052  * cachefs_dir_enter, and it also allows us to maintain entries in backfs
   1053  * order (readdir requires that entry offsets be ascending).
   1054  */
   1055 static int
   1056 cachefs_dir_stuff(cnode_t *dcp, uint_t count, caddr_t buf,
   1057     vnode_t *frontvp, u_offset_t *offsetp, u_offset_t *fsizep)
   1058 {
   1059 	int error = 0;
   1060 	struct fbuf *fbp;
   1061 	struct c_dirent *cdep, *last;
   1062 	struct dirent64 *dep;
   1063 	int inblk, entsize;
   1064 	u_offset_t blockoff = (*offsetp & (offset_t)MAXBMASK);
   1065 	/*LINTED alignment okay*/
   1066 	uint_t off = (uint_t)(*offsetp & (offset_t)MAXBOFFSET);
   1067 
   1068 	/*LINTED want count != 0*/
   1069 	ASSERT(count > 0);
   1070 
   1071 	if (*offsetp >= *fsizep) {
   1072 		error = cachefs_dir_extend(dcp, fsizep, 0);
   1073 		if (error)
   1074 			return (error);
   1075 	}
   1076 
   1077 	ASSERT(*fsizep != 0LL);
   1078 	last = NULL;
   1079 	error = fbread(frontvp, (offset_t)blockoff, MAXBSIZE, S_OTHER, &fbp);
   1080 	if (error)
   1081 		return (error);
   1082 	cdep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + off);
   1083 	inblk = MAXBSIZE-off;
   1084 	if (*offsetp != 0) {
   1085 		ASSERT(cdep->d_length == inblk);
   1086 		inblk -= C_DIRSIZ(cdep);
   1087 		last = cdep;
   1088 		last->d_length -= inblk;
   1089 		off += last->d_length;
   1090 		cdep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + off);
   1091 	}
   1092 	dep = (struct dirent64 *)buf;
   1093 	/*LINTED want count != 0*/
   1094 	while (count > 0) {
   1095 		if (last) {
   1096 			ASSERT(dep->d_off > last->d_offset);
   1097 		}
   1098 		entsize = (int)CDE_SIZE(dep->d_name);
   1099 		if (entsize > inblk) {
   1100 			if (last) {
   1101 				last->d_length += inblk;
   1102 			}
   1103 			(void) fbwrite(fbp);
   1104 			error = cachefs_dir_extend(dcp, fsizep, 0);
   1105 			if (error)
   1106 				return (error);
   1107 			ASSERT(*fsizep != 0LL);
   1108 			blockoff += MAXBSIZE;
   1109 			error = fbread(frontvp, (offset_t)blockoff, MAXBSIZE,
   1110 							S_OTHER, &fbp);
   1111 			if (error)
   1112 				return (error);
   1113 			off = 0;
   1114 			cdep = (struct c_dirent *)fbp->fb_addr;
   1115 			inblk = MAXBSIZE;
   1116 			last = NULL;
   1117 		}
   1118 		cdep->d_length = entsize;
   1119 		cdep->d_id.cid_fileno = dep->d_ino;
   1120 		cdep->d_id.cid_flags = 0;
   1121 		cdep->d_namelen = (ushort_t)strlen(dep->d_name);
   1122 		cdep->d_flag = CDE_VALID;
   1123 		bcopy(dep->d_name, cdep->d_name, cdep->d_namelen+1);
   1124 		cdep->d_offset = dep->d_off;
   1125 		inblk -= entsize;
   1126 		count -= dep->d_reclen;
   1127 		dep = (struct dirent64 *)((uintptr_t)dep + dep->d_reclen);
   1128 		*offsetp = blockoff + (u_offset_t)off;
   1129 		off += entsize;
   1130 		last = cdep;
   1131 		cdep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + off);
   1132 	}
   1133 	if (last) {
   1134 		last->d_length += inblk;
   1135 	}
   1136 	(void) fbwrite(fbp);
   1137 	return (error);
   1138 }
   1139 
   1140 static int
   1141 cachefs_dir_extend(cnode_t *dcp, u_offset_t *cursize, int incr_frontblks)
   1142 {
   1143 	struct vattr va;
   1144 	cachefscache_t *cachep = C_TO_FSCACHE(dcp)->fs_cache;
   1145 	int error = 0;
   1146 	struct fscache *fscp = VFS_TO_FSCACHE(CTOV(dcp)->v_vfsp);
   1147 
   1148 	ASSERT(MUTEX_HELD(&dcp->c_statelock));
   1149 	ASSERT(((*cursize) & (MAXBSIZE-1)) == 0);
   1150 
   1151 	va.va_mask = AT_SIZE;
   1152 	va.va_size = (u_offset_t)(*cursize + MAXBSIZE);
   1153 	error = cachefs_allocblocks(cachep, 1, dcp->c_metadata.md_rltype);
   1154 	if (error)
   1155 		return (error);
   1156 	error = VOP_SETATTR(dcp->c_frontvp, &va, 0, kcred, NULL);
   1157 	if (error) {
   1158 		cachefs_freeblocks(cachep, 1, dcp->c_metadata.md_rltype);
   1159 		return (error);
   1160 	}
   1161 	if (incr_frontblks)
   1162 		dcp->c_metadata.md_frontblks++;
   1163 	if (fscp->fs_cdconnected != CFS_CD_CONNECTED) {
   1164 		dcp->c_size += MAXBSIZE;
   1165 		dcp->c_attr.va_size = dcp->c_size;
   1166 	}
   1167 	*cursize += MAXBSIZE;
   1168 	ASSERT(*cursize != 0LL);
   1169 	if (incr_frontblks)
   1170 		dcp->c_flags |= CN_UPDATED;
   1171 	return (0);
   1172 }
   1173 
   1174 int
   1175 cachefs_async_populate_dir(struct cachefs_populate_req *pop, cred_t *cr,
   1176     vnode_t *backvp, vnode_t *frontvp)
   1177 {
   1178 	vnode_t *dvp = pop->cpop_vp;
   1179 	struct cnode *dcp = VTOC(dvp);
   1180 	u_offset_t frontsize;
   1181 	int error = 0;
   1182 
   1183 #ifdef CFSDEBUG
   1184 	CFS_DEBUG(CFSDEBUG_DIR)
   1185 		printf("cachefs_async_populate_dir: ENTER dvp %p\n",
   1186 								(void *)dvp);
   1187 #endif
   1188 	ASSERT(MUTEX_HELD(&dcp->c_statelock));
   1189 	ASSERT(dvp->v_type == VDIR);
   1190 	ASSERT((dcp->c_metadata.md_flags & MD_POPULATED) == 0);
   1191 	ASSERT(dcp->c_frontvp == frontvp);
   1192 	ASSERT(dcp->c_backvp == backvp);
   1193 	ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(dcp)) == 0);
   1194 
   1195 	/* if dir was modified, toss old contents */
   1196 	if (dcp->c_metadata.md_flags & MD_INVALREADDIR) {
   1197 		cachefs_inval_object(dcp);
   1198 		if (dcp->c_flags & CN_NOCACHE) {
   1199 			error = ENOTDIR;
   1200 			goto out;
   1201 		} else {
   1202 			dcp->c_metadata.md_flags &= ~MD_INVALREADDIR;
   1203 		}
   1204 	}
   1205 
   1206 
   1207 	error = cachefs_dir_fill_common(dcp, cr, frontvp, backvp, &frontsize);
   1208 	if (error != 0)
   1209 		goto out;
   1210 	ASSERT(frontsize != 0LL);
   1211 	mutex_exit(&dcp->c_statelock);
   1212 	/*
   1213 	 * I don't like to break lock here but cachefs_dir_complete()
   1214 	 * needs it.
   1215 	 */
   1216 	error = cachefs_dir_complete(C_TO_FSCACHE(dcp), backvp,
   1217 	    frontvp, cr, 1);
   1218 	mutex_enter(&dcp->c_statelock);
   1219 	if (error != 0)
   1220 		goto out;
   1221 	/* if went nocache while lock was dropped, get out */
   1222 	if ((dcp->c_flags & CN_NOCACHE) || (dcp->c_frontvp == NULL)) {
   1223 		error = EINVAL;
   1224 	} else {
   1225 		/* allocfile and allocblocks have already happened. */
   1226 		dcp->c_metadata.md_frontblks = frontsize / MAXBSIZE;
   1227 	}
   1228 
   1229 out:
   1230 
   1231 #ifdef CFSDEBUG
   1232 	CFS_DEBUG(CFSDEBUG_DIR)
   1233 		printf("cachefs_async_populate_dir: EXIT error = %d\n", error);
   1234 #endif
   1235 
   1236 	return (error);
   1237 }
   1238 
   1239 static int
   1240 cachefs_dir_complete(fscache_t *fscp, vnode_t *backvp, vnode_t *frontvp,
   1241     cred_t *cr, int acltoo)
   1242 {
   1243 	struct c_dirent *dep;
   1244 	caddr_t buf = kmem_alloc(MAXBSIZE, KM_SLEEP);
   1245 	struct vattr va;
   1246 	u_offset_t blockoff;
   1247 	int offset;
   1248 	u_offset_t dir_size;
   1249 	struct fbuf *fbp;
   1250 	cnode_t *cp;
   1251 	fid_t cookie;
   1252 	vnode_t *entry_vp;
   1253 	int error = 0;
   1254 
   1255 	/*
   1256 	 * note: caller better not hold a c_statelock if acltoo is set.
   1257 	 */
   1258 
   1259 	va.va_mask = AT_SIZE;
   1260 	error = VOP_GETATTR(frontvp, &va, 0, cr, NULL);
   1261 	if (error)
   1262 		goto out;
   1263 
   1264 	ASSERT(va.va_size != 0LL);
   1265 	dir_size = va.va_size;
   1266 	ASSERT(dir_size <= MAXOFF_T);
   1267 
   1268 	for (blockoff = 0; blockoff < dir_size; blockoff += MAXBSIZE) {
   1269 		if (error = fbread(frontvp, (offset_t)blockoff,
   1270 		    MAXBSIZE, S_OTHER, &fbp))
   1271 			goto out;
   1272 
   1273 		/*
   1274 		 * We cannot hold any page locks across the below VOP
   1275 		 * operations. We thus copy the directory entries into a
   1276 		 * staging buffer, and release the page lock on the directory
   1277 		 * by calling fbrelse().  Once any necessary cnodes have
   1278 		 * been created, we'll reacquire the page lock with fbread()
   1279 		 * and copy the staging buffer back into the frontvp at
   1280 		 * blockoff.
   1281 		 */
   1282 		bcopy(fbp->fb_addr, buf, MAXBSIZE);
   1283 		fbrelse(fbp, S_OTHER);
   1284 
   1285 		for (offset = 0;
   1286 		    offset < MAXBSIZE &&
   1287 		    (blockoff + (u_offset_t)offset) < dir_size;
   1288 		    offset += dep->d_length) {
   1289 
   1290 			dep = (struct c_dirent *)((uintptr_t)buf + offset);
   1291 			ASSERT(dep->d_length != 0);
   1292 			if ((dep->d_flag & (CDE_VALID | CDE_COMPLETE)) !=
   1293 			    CDE_VALID)
   1294 				continue;
   1295 
   1296 			error = VOP_LOOKUP(backvp, dep->d_name,
   1297 			    &entry_vp, (struct pathname *)NULL, 0,
   1298 			    (vnode_t *)NULL, cr, NULL, NULL, NULL);
   1299 			if (error) {
   1300 				/* lookup on .. in / on coc gets ENOENT */
   1301 				if (error == ENOENT) {
   1302 					error = 0;
   1303 					continue;
   1304 				}
   1305 				goto out;
   1306 			}
   1307 
   1308 			error = cachefs_getcookie(entry_vp, &cookie, NULL, cr,
   1309 				TRUE);
   1310 			if (error) {
   1311 #ifdef CFSDEBUG
   1312 				CFS_DEBUG(CFSDEBUG_DIR)
   1313 					printf("\t%s: getcookie error\n",
   1314 					    dep->d_name);
   1315 #endif /* CFSDEBUG */
   1316 				VN_RELE(entry_vp);
   1317 				goto out;
   1318 			}
   1319 			CACHEFS_FID_COPY(&cookie, &dep->d_cookie);
   1320 			dep->d_flag |= CDE_COMPLETE;
   1321 
   1322 			if ((! acltoo) ||
   1323 			    (! cachefs_vtype_aclok(entry_vp)) ||
   1324 			    (fscp->fs_info.fi_mntflags & CFS_NOACL)) {
   1325 				VN_RELE(entry_vp);
   1326 				continue;
   1327 			}
   1328 
   1329 			error = cachefs_cnode_make(&dep->d_id, fscp, &cookie,
   1330 			    NULL, entry_vp, cr, 0, &cp);
   1331 			VN_RELE(entry_vp);
   1332 			if (error != 0)
   1333 				goto out;
   1334 
   1335 			ASSERT(cp != NULL);
   1336 			mutex_enter(&cp->c_statelock);
   1337 
   1338 			if ((cp->c_flags & CN_NOCACHE) ||
   1339 			    (cp->c_metadata.md_flags & MD_ACL)) {
   1340 				mutex_exit(&cp->c_statelock);
   1341 				VN_RELE(CTOV(cp));
   1342 				continue;
   1343 			}
   1344 
   1345 			(void) cachefs_cacheacl(cp, NULL);
   1346 			mutex_exit(&cp->c_statelock);
   1347 			VN_RELE(CTOV(cp));
   1348 		}
   1349 
   1350 		/*
   1351 		 * We must now re-lock the page corresponding to the frontvp,
   1352 		 * and copy our staging buffer onto it.
   1353 		 */
   1354 		if (error = fbread(frontvp, (offset_t)blockoff,
   1355 		    MAXBSIZE, S_OTHER, &fbp))
   1356 			goto out;
   1357 
   1358 		bcopy(buf, fbp->fb_addr, MAXBSIZE);
   1359 		(void) fbdwrite(fbp);
   1360 	}
   1361 
   1362 out:
   1363 	kmem_free(buf, MAXBSIZE);
   1364 	return (error);
   1365 }
   1366