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/time.h>
     34 #include <sys/vnode.h>
     35 #include <sys/vfs.h>
     36 #include <sys/file.h>
     37 #include <sys/filio.h>
     38 #include <sys/uio.h>
     39 #include <sys/buf.h>
     40 #include <sys/mman.h>
     41 #include <sys/tiuser.h>
     42 #include <sys/pathname.h>
     43 #include <sys/dirent.h>
     44 #include <sys/conf.h>
     45 #include <sys/debug.h>
     46 #include <sys/vmsystm.h>
     47 #include <sys/fcntl.h>
     48 #include <sys/flock.h>
     49 #include <sys/fbuf.h>
     50 #include <sys/swap.h>
     51 #include <sys/errno.h>
     52 #include <sys/sysmacros.h>
     53 #include <sys/disp.h>
     54 #include <sys/kmem.h>
     55 #include <sys/cmn_err.h>
     56 #include <sys/vtrace.h>
     57 #include <sys/mount.h>
     58 #include <sys/dnlc.h>
     59 #include <sys/stat.h>
     60 #include <rpc/types.h>
     61 
     62 #include <vm/hat.h>
     63 #include <vm/as.h>
     64 #include <vm/page.h>
     65 #include <vm/pvn.h>
     66 #include <vm/seg.h>
     67 #include <vm/seg_map.h>
     68 #include <vm/seg_vn.h>
     69 #include <vm/rm.h>
     70 #include <sys/fs/cachefs_fs.h>
     71 #include <sys/fs/cachefs_dlog.h>
     72 #include <sys/fs/cachefs_ioctl.h>
     73 #include <sys/fs/cachefs_dir.h>
     74 #include <sys/fs/cachefs_dlog.h>
     75 #include "fs/fs_subr.h"
     76 
     77 void cachefs_addhash(struct cnode *);
     78 
     79 
     80 /*
     81  * Local functions
     82  */
     83 static void sync_metadata(cnode_t *);
     84 static void drop_backvp(cnode_t *);
     85 static void allow_pendrm(cnode_t *cp);
     86 static int cachefs_unpack_common(vnode_t *vp);
     87 static int cachefs_unpackall_list(cachefscache_t *cachep,
     88     enum cachefs_rl_type type);
     89 static void cachefs_modified_fix(fscache_t *fscp);
     90 static void cachefs_iosetneedattrs(fscache_t *fscp, cfs_cid_t *cidp);
     91 
     92 #if (defined(_SYSCALL32_IMPL) || defined(_LP64))
     93 
     94 #define	CACHEFS_DECL(type, handle)					\
     95 	type	handle
     96 
     97 #define	CACHEFS_TMPPTR_SET(in_addr, tmp_addr, tmp_ptr, type)		\
     98 	tmp_ptr = (type *)(tmp_addr)
     99 
    100 #define	CACHEFS_FID_COPYOUT(in_fidp, out_fidp)				\
    101 	CACHEFS_FID_COPY((fid_t *)(in_fidp), (cfs_fid_t *)(out_fidp))
    102 
    103 #define	CACHEFS_FID_COPYIN(in_fidp, out_fidp)				\
    104 	CACHEFS_FID_COPY((cfs_fid_t *)(in_fidp), (fid_t *)(out_fidp))
    105 
    106 #define	CACHEFS_VATTR_COPYOUT(in_vattrp, out_vattrp, error)		\
    107 	if (!error) {							\
    108 		CACHEFS_VATTR_TO_CFS_VATTR_COPY((vattr_t *)(in_vattrp),	\
    109 			(cfs_vattr_t *)(out_vattrp), error);		\
    110 	}
    111 
    112 #define	CACHEFS_VATTR_COPYIN(in_vattrp, out_vattrp)			\
    113 	CACHEFS_CFS_VATTR_TO_VATTR_COPY((cfs_vattr_t *)(in_vattrp),	\
    114 			(vattr_t *)(out_vattrp))
    115 
    116 #else /* not _SYSCALL32_IMPL || _LP64 */
    117 
    118 #define	CACHEFS_DECL(type, handle)
    119 
    120 #define	CACHEFS_TMPPTR_SET(in_addr, tmp_addr, tmp_ptr, type)		\
    121 	tmp_ptr = (type *)(in_addr)
    122 
    123 #define	CACHEFS_FID_COPYOUT(in_fidp, out_fidp)
    124 
    125 #define	CACHEFS_FID_COPYIN(in_fidp, out_fidp)
    126 
    127 #define	CACHEFS_VATTR_COPYOUT(in_vattrp, out_vattrp, error)
    128 
    129 #define	CACHEFS_VATTR_COPYIN(in_vattrp, out_vattrp)
    130 
    131 #endif	/* _SYSCALL32_IMPL || _LP64 */
    132 
    133 /*
    134  * Conjure up a credential from the partial credential stored in
    135  * a file.  This is bogus and cachefs should really be fixed, but
    136  * this maintains maximum compatibility.
    137  * dl_cred *cr points to a basic credential followed directly by a buffer that
    138  * takes a number of groups.
    139  */
    140 
    141 static cred_t *
    142 conj_cred(dl_cred_t *cr)
    143 {
    144 	cred_t *newcr = crget();
    145 
    146 	(void) crsetresuid(newcr, cr->cr_ruid, cr->cr_uid, cr->cr_suid);
    147 	(void) crsetresgid(newcr, cr->cr_rgid, cr->cr_gid, cr->cr_sgid);
    148 
    149 	(void) crsetgroups(newcr, MIN(NGROUPS_MAX_DEFAULT, cr->cr_ngroups),
    150 		cr->cr_groups);
    151 
    152 	return (newcr);
    153 }
    154 /*
    155  * Pack a file in the cache
    156  *	dvp is the directory the file resides in.
    157  *	name is the name of the file.
    158  *	Returns 0 or an error if could not perform the operation.
    159  */
    160 int
    161 cachefs_pack(struct vnode *dvp, char *name, cred_t *cr)
    162 {
    163 	fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp));
    164 	int error = 0;
    165 	int connected = 0;
    166 	vnode_t *vp;
    167 
    168 	/*
    169 	 * Return if NFSv4 is the backfs (no caching).
    170 	 */
    171 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
    172 		goto out;
    173 	}
    174 
    175 	for (;;) {
    176 		/* get access to the file system */
    177 		error = cachefs_cd_access(fscp, connected, 0);
    178 		if (error)
    179 			break;
    180 
    181 		/* lookup the file name */
    182 		error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL,
    183 		    cr);
    184 		if (error == 0) {
    185 			error = cachefs_pack_common(vp, cr);
    186 			VN_RELE(vp);
    187 		}
    188 		if (CFS_TIMEOUT(fscp, error)) {
    189 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
    190 				cachefs_cd_release(fscp);
    191 				cachefs_cd_timedout(fscp);
    192 				connected = 0;
    193 				continue;
    194 			} else {
    195 				cachefs_cd_release(fscp);
    196 				connected = 1;
    197 				continue;
    198 			}
    199 		}
    200 		cachefs_cd_release(fscp);
    201 		break;
    202 	}
    203 
    204 out:
    205 	return (error);
    206 }
    207 /*
    208  * Packs the file belonging to the passed in vnode.
    209  */
    210 int
    211 cachefs_pack_common(vnode_t *vp, cred_t *cr)
    212 {
    213 	cnode_t *cp = VTOC(vp);
    214 	fscache_t *fscp = C_TO_FSCACHE(cp);
    215 	int error = 0;
    216 	offset_t off;
    217 	caddr_t buf;
    218 	int buflen;
    219 	rl_entry_t rl_ent;
    220 	u_offset_t cnode_size;
    221 
    222 	rw_enter(&cp->c_rwlock, RW_WRITER);
    223 	mutex_enter(&cp->c_statelock);
    224 
    225 	/* done if cannot write to cache */
    226 	if ((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0) {
    227 		error = EROFS;
    228 		goto out;
    229 	}
    230 
    231 	/* done if not usable */
    232 	if (cp->c_flags & (CN_STALE | CN_DESTROY)) {
    233 		error = ESTALE;
    234 		goto out;
    235 	}
    236 
    237 	/* make sure up to date */
    238 	error = CFSOP_CHECK_COBJECT(fscp, cp, C_BACK_CHECK, cr);
    239 	if (error)
    240 		goto out;
    241 
    242 	/* make it cachable */
    243 	cp->c_flags &= ~CN_NOCACHE;
    244 
    245 	/* get a metadata slot if we do not have one yet */
    246 	if (cp->c_flags & CN_ALLOC_PENDING) {
    247 		if (cp->c_filegrp->fg_flags & CFS_FG_ALLOC_ATTR) {
    248 			(void) filegrp_allocattr(cp->c_filegrp);
    249 		}
    250 		error = filegrp_create_metadata(cp->c_filegrp,
    251 		    &cp->c_metadata, &cp->c_id);
    252 		if (error)
    253 			goto out;
    254 		cp->c_flags &= ~CN_ALLOC_PENDING;
    255 		cp->c_flags |= CN_UPDATED;
    256 	}
    257 
    258 	/* cache the ACL if necessary */
    259 	if (((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0) &&
    260 	    (cachefs_vtype_aclok(vp)) &&
    261 	    ((cp->c_metadata.md_flags & MD_ACL) == 0)) {
    262 		error = cachefs_cacheacl(cp, NULL);
    263 		if (error != 0)
    264 			goto out;
    265 	}
    266 
    267 	/* directory */
    268 	if (vp->v_type == VDIR) {
    269 		if (cp->c_metadata.md_flags & MD_POPULATED)
    270 			goto out;
    271 
    272 		if (error = cachefs_dir_fill(cp, cr))
    273 			goto out;
    274 	}
    275 
    276 	/* regular file */
    277 	else if (vp->v_type == VREG) {
    278 		if (cp->c_metadata.md_flags & MD_POPULATED)
    279 			goto out;
    280 
    281 		if (cp->c_backvp == NULL) {
    282 			error = cachefs_getbackvp(fscp, cp);
    283 			if (error)
    284 				goto out;
    285 		}
    286 		if (cp->c_frontvp == NULL) {
    287 			error = cachefs_getfrontfile(cp);
    288 			if (error)
    289 				goto out;
    290 		}
    291 		/* populate the file */
    292 		off = (offset_t)0;
    293 		cnode_size = cp->c_attr.va_size;
    294 		while (off < cnode_size) {
    295 			if (!cachefs_check_allocmap(cp, off)) {
    296 				u_offset_t popoff;
    297 				size_t popsize;
    298 
    299 				cachefs_cluster_allocmap(off, &popoff,
    300 				    &popsize, (size_t)DEF_POP_SIZE, cp);
    301 				if (popsize != 0) {
    302 					error = cachefs_populate(cp, popoff,
    303 					    popsize, cp->c_frontvp,
    304 					    cp->c_backvp, cp->c_size, cr);
    305 					if (error)
    306 						goto out;
    307 					else
    308 						cp->c_flags |= (CN_UPDATED |
    309 						    CN_NEED_FRONT_SYNC |
    310 						    CN_POPULATION_PENDING);
    311 					popsize = popsize - (off - popoff);
    312 				}
    313 			}
    314 			off += PAGESIZE;
    315 		}
    316 	}
    317 
    318 	/* symbolic link */
    319 	else if (vp->v_type == VLNK) {
    320 		if (cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK))
    321 			goto out;
    322 
    323 		/* get the sym link contents from the back fs */
    324 		error = cachefs_readlink_back(cp, cr, &buf, &buflen);
    325 		if (error)
    326 			goto out;
    327 
    328 		/* try to cache the sym link */
    329 		error = cachefs_stuffsymlink(cp, buf, buflen);
    330 		cachefs_kmem_free(buf, MAXPATHLEN);
    331 	}
    332 
    333 	/* assume that all other types fit in the attributes */
    334 
    335 out:
    336 	/* get the rl slot if needed */
    337 	if ((error == 0) && (cp->c_metadata.md_rlno == 0)) {
    338 		rl_ent.rl_fileno = cp->c_id.cid_fileno;
    339 		rl_ent.rl_local = (cp->c_id.cid_flags & CFS_CID_LOCAL) ? 1 : 0;
    340 		rl_ent.rl_fsid = fscp->fs_cfsid;
    341 		rl_ent.rl_attrc = 0;
    342 		cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
    343 		error = cachefs_rl_alloc(fscp->fs_cache, &rl_ent,
    344 		    &cp->c_metadata.md_rlno);
    345 		if (error == 0)
    346 			error = filegrp_ffhold(cp->c_filegrp);
    347 	}
    348 
    349 	/* mark the file as packed */
    350 	if (error == 0) {
    351 		/* modified takes precedence over packed */
    352 		if (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) {
    353 			cachefs_rlent_moveto(fscp->fs_cache,
    354 			    CACHEFS_RL_PACKED, cp->c_metadata.md_rlno,
    355 			    cp->c_metadata.md_frontblks);
    356 			cp->c_metadata.md_rltype = CACHEFS_RL_PACKED;
    357 		}
    358 		cp->c_metadata.md_flags |= MD_PACKED;
    359 		cp->c_flags |= CN_UPDATED;
    360 	}
    361 
    362 	mutex_exit(&cp->c_statelock);
    363 	rw_exit(&cp->c_rwlock);
    364 
    365 	return (error);
    366 }
    367 
    368 /*
    369  * Unpack a file from the cache
    370  *	dvp is the directory the file resides in.
    371  *	name is the name of the file.
    372  *	Returns 0 or an error if could not perform the operation.
    373  */
    374 int
    375 cachefs_unpack(struct vnode *dvp, char *name, cred_t *cr)
    376 {
    377 	fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp));
    378 	int error = 0;
    379 	int connected = 0;
    380 	vnode_t *vp;
    381 
    382 	/* Return error if NFSv4 is the backfs (no caching) */
    383 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
    384 		goto out;
    385 	}
    386 
    387 	for (;;) {
    388 		/* get access to the file system */
    389 		error = cachefs_cd_access(fscp, connected, 0);
    390 		if (error)
    391 			break;
    392 
    393 		/* lookup the file name */
    394 		error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL,
    395 		    cr);
    396 		if (error == 0) {
    397 			error = cachefs_unpack_common(vp);
    398 			VN_RELE(vp);
    399 		}
    400 		if (CFS_TIMEOUT(fscp, error)) {
    401 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
    402 				cachefs_cd_release(fscp);
    403 				cachefs_cd_timedout(fscp);
    404 				connected = 0;
    405 				continue;
    406 			} else {
    407 				cachefs_cd_release(fscp);
    408 				connected = 1;
    409 				continue;
    410 			}
    411 		}
    412 		cachefs_cd_release(fscp);
    413 		break;
    414 	}
    415 out:
    416 	return (error);
    417 }
    418 
    419 /*
    420  * Unpacks the file belonging to the passed in vnode.
    421  */
    422 static int
    423 cachefs_unpack_common(vnode_t *vp)
    424 {
    425 	cnode_t *cp = VTOC(vp);
    426 	fscache_t *fscp = C_TO_FSCACHE(cp);
    427 	int error = 0;
    428 
    429 	mutex_enter(&cp->c_statelock);
    430 
    431 	/* nothing to do if not packed */
    432 	if ((cp->c_metadata.md_flags & MD_PACKED) == 0)
    433 		goto out;
    434 
    435 	/* nothing to do if cannot modify cache */
    436 	if ((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0) {
    437 		error = EROFS;
    438 		goto out;
    439 	}
    440 
    441 	/* mark file as no longer packed */
    442 	ASSERT(cp->c_metadata.md_rlno);
    443 	cp->c_metadata.md_flags &= ~MD_PACKED;
    444 	cp->c_flags |= CN_UPDATED;
    445 
    446 	/* done if file has been modified */
    447 	if (cp->c_metadata.md_rltype == CACHEFS_RL_MODIFIED)
    448 		goto out;
    449 
    450 	/* if there is no front file */
    451 	if ((cp->c_metadata.md_flags & MD_FILE) == 0) {
    452 		/* nuke front file resources */
    453 		filegrp_ffrele(cp->c_filegrp);
    454 		cachefs_rlent_moveto(fscp->fs_cache,
    455 		    CACHEFS_RL_FREE, cp->c_metadata.md_rlno, 0);
    456 		cp->c_metadata.md_rlno = 0;
    457 		cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
    458 	}
    459 
    460 	/* else move the front file to the active list */
    461 	else {
    462 		cachefs_rlent_moveto(fscp->fs_cache,
    463 		    CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno,
    464 		    cp->c_metadata.md_frontblks);
    465 		cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE;
    466 	}
    467 
    468 out:
    469 	mutex_exit(&cp->c_statelock);
    470 	return (error);
    471 }
    472 
    473 /*
    474  * Returns packing information on a file.
    475  *	dvp is the directory the file resides in.
    476  *	name is the name of the file.
    477  *	*statusp is set to the status of the file
    478  *	Returns 0 or an error if could not perform the operation.
    479  */
    480 int
    481 cachefs_packinfo(struct vnode *dvp, char *name, int *statusp, cred_t *cr)
    482 {
    483 	fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp));
    484 	struct vnode *vp;
    485 	struct cnode *cp;
    486 	int error;
    487 	int connected = 0;
    488 
    489 	*statusp = 0;
    490 
    491 	/*
    492 	 * Return if NFSv4 is the backfs (no caching).
    493 	 */
    494 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
    495 		goto out;
    496 	}
    497 
    498 	for (;;) {
    499 		/* get access to the file system */
    500 		error = cachefs_cd_access(fscp, connected, 0);
    501 		if (error)
    502 			break;
    503 
    504 		/* lookup the file name */
    505 		error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL,
    506 		    cr);
    507 		if (CFS_TIMEOUT(fscp, error)) {
    508 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
    509 				cachefs_cd_release(fscp);
    510 				cachefs_cd_timedout(fscp);
    511 				connected = 0;
    512 				continue;
    513 			} else {
    514 				cachefs_cd_release(fscp);
    515 				connected = 1;
    516 				continue;
    517 			}
    518 		}
    519 		if (error)
    520 			break;
    521 		cp = VTOC(vp);
    522 
    523 		mutex_enter(&cp->c_statelock);
    524 		if (cp->c_metadata.md_flags & MD_PACKED)
    525 			*statusp |= CACHEFS_PACKED_FILE;
    526 		if (cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK))
    527 			*statusp |= CACHEFS_PACKED_DATA;
    528 		else if ((vp->v_type != VREG) &&
    529 		    (vp->v_type != VDIR) &&
    530 		    (vp->v_type != VLNK))
    531 			*statusp |= CACHEFS_PACKED_DATA;
    532 		else if (cp->c_size == 0)
    533 			*statusp |= CACHEFS_PACKED_DATA;
    534 		if (cp->c_flags & CN_NOCACHE)
    535 			*statusp |= CACHEFS_PACKED_NOCACHE;
    536 		mutex_exit(&cp->c_statelock);
    537 
    538 		VN_RELE(vp);
    539 		cachefs_cd_release(fscp);
    540 		break;
    541 	}
    542 
    543 out:
    544 	return (error);
    545 }
    546 
    547 /*
    548  * Finds all packed files in the cache and unpacks them.
    549  */
    550 int
    551 cachefs_unpackall(vnode_t *vp)
    552 {
    553 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
    554 	cachefscache_t *cachep = fscp->fs_cache;
    555 	int error;
    556 
    557 	/*
    558 	 * Return if NFSv4 is the backfs (no caching).
    559 	 */
    560 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
    561 		goto out;
    562 	}
    563 
    564 	error = cachefs_unpackall_list(cachep, CACHEFS_RL_PACKED);
    565 	if (error)
    566 		goto out;
    567 	error = cachefs_unpackall_list(cachep, CACHEFS_RL_PACKED_PENDING);
    568 out:
    569 	return (error);
    570 }
    571 
    572 /*
    573  * Finds all packed files on the specified list and unpacks them.
    574  */
    575 static int
    576 cachefs_unpackall_list(cachefscache_t *cachep, enum cachefs_rl_type type)
    577 {
    578 	fscache_t *fscp = NULL;
    579 	cnode_t *cp;
    580 	int error = 0;
    581 	rl_entry_t rl_ent;
    582 	cfs_cid_t cid;
    583 
    584 	rl_ent.rl_current = type;
    585 	for (;;) {
    586 		/* get the next entry on the specified resource list */
    587 		error = cachefs_rlent_data(cachep, &rl_ent, NULL);
    588 		if (error) {
    589 			error = 0;
    590 			break;
    591 		}
    592 
    593 		/* if the fscp we have does not match */
    594 		if ((fscp == NULL) || (fscp->fs_cfsid != rl_ent.rl_fsid)) {
    595 			if (fscp) {
    596 				cachefs_cd_release(fscp);
    597 				fscache_rele(fscp);
    598 				fscp = NULL;
    599 			}
    600 
    601 			/* get the file system cache object for this fsid */
    602 			mutex_enter(&cachep->c_fslistlock);
    603 			fscp = fscache_list_find(cachep, rl_ent.rl_fsid);
    604 			if (fscp == NULL) {
    605 				fscp = fscache_create(cachep);
    606 				error = fscache_activate(fscp, rl_ent.rl_fsid,
    607 				    NULL, NULL, 0);
    608 				if (error) {
    609 					cmn_err(CE_WARN,
    610 					    "cachefs: cache error, run fsck\n");
    611 					fscache_destroy(fscp);
    612 					fscp = NULL;
    613 					mutex_exit(&cachep->c_fslistlock);
    614 					break;
    615 				}
    616 				fscache_list_add(cachep, fscp);
    617 			}
    618 			fscache_hold(fscp);
    619 			mutex_exit(&cachep->c_fslistlock);
    620 
    621 			/* get access to the file system */
    622 			error = cachefs_cd_access(fscp, 0, 0);
    623 			if (error) {
    624 				fscache_rele(fscp);
    625 				fscp = NULL;
    626 				break;
    627 			}
    628 		}
    629 
    630 		/* get the cnode for the file */
    631 		cid.cid_fileno = rl_ent.rl_fileno;
    632 		cid.cid_flags = rl_ent.rl_local ? CFS_CID_LOCAL : 0;
    633 		error = cachefs_cnode_make(&cid, fscp,
    634 		    NULL, NULL, NULL, kcred, 0, &cp);
    635 		if (error) {
    636 #ifdef CFSDEBUG
    637 			CFS_DEBUG(CFSDEBUG_IOCTL)
    638 				printf("cachefs: cul: could not find %llu\n",
    639 				    (u_longlong_t)cid.cid_fileno);
    640 			delay(5*hz);
    641 #endif
    642 			continue;
    643 		}
    644 
    645 		/* unpack the file */
    646 		(void) cachefs_unpack_common(CTOV(cp));
    647 		VN_RELE(CTOV(cp));
    648 	}
    649 
    650 	/* free up allocated resources */
    651 	if (fscp) {
    652 		cachefs_cd_release(fscp);
    653 		fscache_rele(fscp);
    654 	}
    655 	return (error);
    656 }
    657 
    658 /*
    659  * Identifies this process as the cachefsd.
    660  * Stays this way until close is done.
    661  */
    662 int
    663 /*ARGSUSED*/
    664 cachefs_io_daemonid(vnode_t *vp, void *dinp, void *doutp)
    665 {
    666 	int error = 0;
    667 
    668 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
    669 	cachefscache_t *cachep = fscp->fs_cache;
    670 
    671 	mutex_enter(&fscp->fs_cdlock);
    672 
    673 	/* can only do this on the root of the file system */
    674 	if (vp != fscp->fs_rootvp)
    675 		error = ENOENT;
    676 
    677 	/* else if there already is a daemon running */
    678 	else if (fscp->fs_cddaemonid)
    679 		error = EBUSY;
    680 
    681 	/* else use the pid to identify the daemon */
    682 	else {
    683 		fscp->fs_cddaemonid = ttoproc(curthread)->p_pid;
    684 		cv_broadcast(&fscp->fs_cdwaitcv);
    685 	}
    686 
    687 	mutex_exit(&fscp->fs_cdlock);
    688 
    689 	if (error == 0) {
    690 		/* the daemon that takes care of root is special */
    691 		if (fscp->fs_flags & CFS_FS_ROOTFS) {
    692 			mutex_enter(&cachep->c_contentslock);
    693 			ASSERT(cachep->c_rootdaemonid == 0);
    694 			cachep->c_rootdaemonid = fscp->fs_cddaemonid;
    695 			mutex_exit(&cachep->c_contentslock);
    696 		}
    697 	}
    698 	return (error);
    699 }
    700 
    701 /*
    702  * Returns the current state in doutp
    703  */
    704 int
    705 /*ARGSUSED*/
    706 cachefs_io_stateget(vnode_t *vp, void *dinp, void *doutp)
    707 {
    708 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
    709 	int *statep = (int *)doutp;
    710 	int state;
    711 
    712 	/*
    713 	 * Only called in support of disconnectable operation, so assert
    714 	 * that this is not called when NFSv4 is the backfilesytem.
    715 	 */
    716 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
    717 
    718 	mutex_enter(&fscp->fs_cdlock);
    719 	switch (fscp->fs_cdconnected) {
    720 	case CFS_CD_CONNECTED:
    721 		state = CFS_FS_CONNECTED;
    722 		break;
    723 	case CFS_CD_DISCONNECTED:
    724 		state = CFS_FS_DISCONNECTED;
    725 		break;
    726 	case CFS_CD_RECONNECTING:
    727 		state = CFS_FS_RECONNECTING;
    728 		break;
    729 	default:
    730 		ASSERT(0);
    731 		break;
    732 	}
    733 	mutex_exit(&fscp->fs_cdlock);
    734 
    735 	*statep = state;
    736 	return (0);
    737 }
    738 
    739 /*
    740  * Sets the state of the file system.
    741  */
    742 int
    743 /*ARGSUSED*/
    744 cachefs_io_stateset(vnode_t *vp, void *dinp, void *doutp)
    745 {
    746 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
    747 	int error = 0;
    748 	int nosig = 1;
    749 	int state = *(int *)dinp;
    750 
    751 	/*
    752 	 * State should not be changeable and always be connected if
    753 	 * NFSv4 is in use.
    754 	 */
    755 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
    756 
    757 	/* wait until the file system is quiet */
    758 	mutex_enter(&fscp->fs_cdlock);
    759 	if (fscp->fs_cdtransition == 1) {
    760 		/* if someone is already changing the state */
    761 		mutex_exit(&fscp->fs_cdlock);
    762 		return (0);
    763 	}
    764 	fscp->fs_cdtransition = 1;
    765 	while (nosig && (fscp->fs_cdrefcnt != 0)) {
    766 		nosig = cv_wait_sig(&fscp->fs_cdwaitcv, &fscp->fs_cdlock);
    767 	}
    768 	if (!nosig) {
    769 		fscp->fs_cdtransition = 0;
    770 		cv_broadcast(&fscp->fs_cdwaitcv);
    771 		mutex_exit(&fscp->fs_cdlock);
    772 		return (EINTR);
    773 	}
    774 	mutex_exit(&fscp->fs_cdlock);
    775 
    776 	switch (state) {
    777 	case CFS_FS_CONNECTED:
    778 		/* done if already in this state */
    779 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED)
    780 			break;
    781 
    782 		mutex_enter(&fscp->fs_cdlock);
    783 		fscp->fs_cdconnected = CFS_CD_CONNECTED;
    784 		mutex_exit(&fscp->fs_cdlock);
    785 
    786 		/* fix up modified files */
    787 		cachefs_modified_fix(fscp);
    788 
    789 #if 0
    790 		if (fscp->fs_hostname != NULL)
    791 			printf("\ncachefs:server          - %s",
    792 			    fscp->fs_hostname);
    793 		if (fscp->fs_mntpt != NULL)
    794 			printf("\ncachefs:mount point     - %s",
    795 			    fscp->fs_mntpt);
    796 		if (fscp->fs_backfsname != NULL)
    797 			printf("\ncachefs:back filesystem - %s",
    798 			    fscp->fs_backfsname);
    799 		printf("\nok\n");
    800 #else
    801 		if (fscp->fs_hostname && fscp->fs_backfsname)
    802 			printf("cachefs: %s:%s ok\n",
    803 			    fscp->fs_hostname, fscp->fs_backfsname);
    804 		else
    805 			printf("cachefs: server ok\n");
    806 #endif
    807 
    808 		/* allow deletion of renamed open files to proceed */
    809 		cachefs_cnode_traverse(fscp, allow_pendrm);
    810 		break;
    811 
    812 	case CFS_FS_DISCONNECTED:
    813 		/* done if already in this state */
    814 		if (fscp->fs_cdconnected == CFS_CD_DISCONNECTED)
    815 			break;
    816 
    817 		/* drop all back vps */
    818 		cachefs_cnode_traverse(fscp, drop_backvp);
    819 
    820 
    821 		mutex_enter(&fscp->fs_cdlock);
    822 		fscp->fs_cdconnected = CFS_CD_DISCONNECTED;
    823 		mutex_exit(&fscp->fs_cdlock);
    824 
    825 #if 0
    826 		if (fscp->fs_hostname != NULL)
    827 			printf("\ncachefs:server          - %s",
    828 			    fscp->fs_hostname);
    829 		if (fscp->fs_mntpt != NULL)
    830 			printf("\ncachefs:mount point     - %s",
    831 			    fscp->fs_mntpt);
    832 		if (fscp->fs_backfsname != NULL)
    833 			printf("\ncachefs:back filesystem - %s",
    834 			    fscp->fs_backfsname);
    835 		printf("\nnot responding still trying\n");
    836 #else
    837 		if (fscp->fs_hostname && fscp->fs_backfsname)
    838 			printf("cachefs: %s:%s not responding still trying\n",
    839 			    fscp->fs_hostname, fscp->fs_backfsname);
    840 		else
    841 			printf("cachefs: server not responding still trying\n");
    842 #endif
    843 		break;
    844 
    845 	case CFS_FS_RECONNECTING:
    846 		/* done if already in this state */
    847 		if (fscp->fs_cdconnected == CFS_CD_RECONNECTING)
    848 			break;
    849 
    850 		/*
    851 		 * Before we enter disconnected state we sync all metadata,
    852 		 * this allows us to read metadata directly in subsequent
    853 		 * calls so we don't need to allocate cnodes when
    854 		 * we just need metadata information.
    855 		 */
    856 		/* XXX bob: need to eliminate this */
    857 		cachefs_cnode_traverse(fscp, sync_metadata);
    858 
    859 		mutex_enter(&fscp->fs_cdlock);
    860 		fscp->fs_cdconnected = CFS_CD_RECONNECTING;
    861 		mutex_exit(&fscp->fs_cdlock);
    862 
    863 		/* no longer need dlog active */
    864 		cachefs_dlog_teardown(fscp);
    865 		break;
    866 
    867 	default:
    868 		error = ENOTTY;
    869 		break;
    870 	}
    871 
    872 	mutex_enter(&fscp->fs_cdlock);
    873 	fscp->fs_cdtransition = 0;
    874 	cv_broadcast(&fscp->fs_cdwaitcv);
    875 	mutex_exit(&fscp->fs_cdlock);
    876 	return (error);
    877 }
    878 
    879 /*
    880  * Blocks until the file system switches
    881  * out of the connected state.
    882  */
    883 int
    884 /*ARGSUSED*/
    885 cachefs_io_xwait(vnode_t *vp, void *dinp, void *doutp)
    886 {
    887 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
    888 	int nosig = 1;
    889 
    890 	/*
    891 	 * Only called in support of disconnectable operation, so assert
    892 	 * that this is not used when NFSv4 is the backfilesytem.
    893 	 */
    894 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
    895 
    896 	mutex_enter(&fscp->fs_cdlock);
    897 	while (nosig &&
    898 	    (fscp->fs_cdconnected == CFS_CD_CONNECTED)) {
    899 		nosig = cv_wait_sig(&fscp->fs_cdwaitcv, &fscp->fs_cdlock);
    900 	}
    901 	mutex_exit(&fscp->fs_cdlock);
    902 	if (!nosig)
    903 		return (EINTR);
    904 
    905 	return (0);
    906 }
    907 
    908 #define	RL_HEAD(cachep, type) \
    909 	(&(cachep->c_rlinfo.rl_items[CACHEFS_RL_INDEX(type)]))
    910 
    911 /*
    912  * Returns some statistics about the cache.
    913  */
    914 #define	CFS_STAT_FACTOR		(MAXBSIZE / 1024)
    915 int
    916 /*ARGSUSED*/
    917 cachefs_io_getstats(vnode_t *vp, void *dinp, void *doutp)
    918 {
    919 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
    920 	cachefscache_t *cachep = fscp->fs_cache;
    921 	struct statvfs64 sb;
    922 	fsblkcnt64_t avail = 0;
    923 	fsblkcnt64_t blocks;
    924 	int error;
    925 	cachefsio_getstats_t *gsp = (cachefsio_getstats_t *)doutp;
    926 
    927 	/* determine number of blocks available to the cache */
    928 	error = VFS_STATVFS(cachep->c_dirvp->v_vfsp, &sb);
    929 	if (error == 0) {
    930 		blocks = (fsblkcnt64_t)(cachep->c_label.cl_maxblks -
    931 		    cachep->c_usage.cu_blksused);
    932 		if ((longlong_t)blocks < (longlong_t)0)
    933 			blocks = (fsblkcnt64_t)0;
    934 		avail = (sb.f_bfree * sb.f_frsize) / MAXBSIZE;
    935 		if (blocks < avail)
    936 			avail = blocks;
    937 	}
    938 
    939 	gsp->gs_total = cachep->c_usage.cu_blksused * CFS_STAT_FACTOR;
    940 	gsp->gs_gc = RL_HEAD(cachep, CACHEFS_RL_GC)->rli_blkcnt *
    941 		CFS_STAT_FACTOR;
    942 	gsp->gs_active = RL_HEAD(cachep, CACHEFS_RL_ACTIVE)->rli_blkcnt *
    943 		CFS_STAT_FACTOR;
    944 	gsp->gs_packed = RL_HEAD(cachep, CACHEFS_RL_PACKED)->rli_blkcnt *
    945 		CFS_STAT_FACTOR;
    946 	gsp->gs_free = (long)(avail * CFS_STAT_FACTOR);
    947 	gsp->gs_gctime = cachep->c_rlinfo.rl_gctime;
    948 	return (0);
    949 }
    950 
    951 /*
    952  * This looks to see if the specified file exists in the cache.
    953  * 	0 is returned if it exists
    954  *	ENOENT is returned if it doesn't exist.
    955  */
    956 int
    957 /*ARGSUSED*/
    958 cachefs_io_exists(vnode_t *vp, void *dinp, void *doutp)
    959 {
    960 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
    961 	cnode_t *cp = NULL;
    962 	int error;
    963 	cfs_cid_t *cidp = (cfs_cid_t *)dinp;
    964 
    965 	/*
    966 	 * Only called in support of disconnectable operation, so assert
    967 	 * that this is not called when NFSv4 is the backfilesytem.
    968 	 */
    969 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
    970 
    971 	/* find the cnode of the file */
    972 	error = cachefs_cnode_make(cidp, fscp,
    973 	    NULL, NULL, NULL, kcred, 0, &cp);
    974 	if (error)
    975 		return (ENOENT);
    976 
    977 	if ((cp->c_flags & (CN_DESTROY | CN_NOCACHE)) ||
    978 	    !(cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK)))
    979 		error = ENOENT;
    980 
    981 	VN_RELE(CTOV(cp));
    982 	return	(error);
    983 
    984 }
    985 
    986 /*
    987  * Moves the specified file to the lost+found directory for the
    988  * cached file system.
    989  * Invalidates cached data and attributes.
    990  * Returns 0 or an error if could not perform operation.
    991  */
    992 int
    993 cachefs_io_lostfound(vnode_t *vp, void *dinp, void *doutp)
    994 {
    995 	int error;
    996 	cnode_t *cp = NULL;
    997 	fscache_t *fscp;
    998 	cachefscache_t *cachep;
    999 	cachefsio_lostfound_arg_t *lfp;
   1000 	cachefsio_lostfound_return_t *rp;
   1001 
   1002 	lfp = (cachefsio_lostfound_arg_t *)dinp;
   1003 	rp = (cachefsio_lostfound_return_t *)doutp;
   1004 
   1005 	fscp = C_TO_FSCACHE(VTOC(vp));
   1006 	cachep = fscp->fs_cache;
   1007 
   1008 	ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0);
   1009 
   1010 	/*
   1011 	 * Only called in support of disconnectable operation, so assert
   1012 	 * that this is not called when NFSv4 is the backfilesytem.
   1013 	 */
   1014 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1015 
   1016 	/* find the cnode of the file */
   1017 	error = cachefs_cnode_make(&lfp->lf_cid, fscp,
   1018 	    NULL, NULL, NULL, kcred, 0, &cp);
   1019 	if (error) {
   1020 		error = ENOENT;
   1021 		goto out;
   1022 	}
   1023 
   1024 	mutex_enter(&cp->c_statelock);
   1025 
   1026 	/* must be regular file and modified */
   1027 	if ((cp->c_attr.va_type != VREG) ||
   1028 	    (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED)) {
   1029 		mutex_exit(&cp->c_statelock);
   1030 		error = EINVAL;
   1031 		goto out;
   1032 	}
   1033 
   1034 	/* move to lost+found */
   1035 	error = cachefs_cnode_lostfound(cp, lfp->lf_name);
   1036 	mutex_exit(&cp->c_statelock);
   1037 
   1038 	if (error == 0)
   1039 		(void) strcpy(rp->lf_name, lfp->lf_name);
   1040 out:
   1041 	if (cp)
   1042 		VN_RELE(CTOV(cp));
   1043 
   1044 	return (error);
   1045 }
   1046 
   1047 /*
   1048  * Given a cid, returns info about the file in the cache.
   1049  */
   1050 int
   1051 cachefs_io_getinfo(vnode_t *vp, void *dinp, void *doutp)
   1052 {
   1053 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
   1054 	struct cnode *dcp = NULL;
   1055 	struct cnode *cp = NULL;
   1056 	struct vattr va;
   1057 	u_offset_t blockoff = 0;
   1058 	struct fbuf *fbp;
   1059 	int offset = 0;
   1060 	int error = 0;
   1061 	cfs_cid_t *fcidp;
   1062 	cachefsio_getinfo_t *infop;
   1063 
   1064 	/*
   1065 	 * Only called in support of disconnectable operation, so assert
   1066 	 * that this is not called when NFSv4 is the backfilesytem.
   1067 	 */
   1068 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1069 
   1070 	fcidp = (cfs_cid_t *)dinp;
   1071 	infop = (cachefsio_getinfo_t *)doutp;
   1072 
   1073 	/* find the cnode of the file */
   1074 	error = cachefs_cnode_make(fcidp, fscp, NULL, NULL, NULL,
   1075 	    kcred, 0, &cp);
   1076 	if (error) {
   1077 		error = ENOENT;
   1078 		goto out;
   1079 	}
   1080 
   1081 	infop->gi_cid = *fcidp;
   1082 	infop->gi_modified = (cp->c_metadata.md_rltype == CACHEFS_RL_MODIFIED);
   1083 	CACHEFS_VATTR_TO_CFS_VATTR_COPY(&cp->c_attr, &infop->gi_attr, error);
   1084 	infop->gi_pcid = cp->c_metadata.md_parent;
   1085 	infop->gi_name[0] = '\0';
   1086 	infop->gi_seq = cp->c_metadata.md_seq;
   1087 	if (error || (cp->c_metadata.md_parent.cid_fileno == 0))
   1088 		goto out;
   1089 
   1090 	/* try to get the cnode of the parent dir */
   1091 	error = cachefs_cnode_make(&cp->c_metadata.md_parent, fscp,
   1092 	    NULL, NULL, NULL, kcred, 0, &dcp);
   1093 	if (error) {
   1094 		error = 0;
   1095 		goto out;
   1096 	}
   1097 
   1098 	/* make sure a directory and populated */
   1099 	if ((((dcp->c_flags & CN_ASYNC_POPULATE) == 0) ||
   1100 	    ((dcp->c_metadata.md_flags & MD_POPULATED) == 0)) &&
   1101 	    (CTOV(dcp)->v_type == VDIR)) {
   1102 		error = 0;
   1103 		goto out;
   1104 	}
   1105 
   1106 	/* get the front file */
   1107 	if (dcp->c_frontvp == NULL) {
   1108 		mutex_enter(&dcp->c_statelock);
   1109 		error = cachefs_getfrontfile(dcp);
   1110 		mutex_exit(&dcp->c_statelock);
   1111 		if (error) {
   1112 			error = 0;
   1113 			goto out;
   1114 		}
   1115 
   1116 		/* make sure frontvp is still populated */
   1117 		if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
   1118 			error = 0;
   1119 			goto out;
   1120 		}
   1121 	}
   1122 
   1123 	/* Get the length of the directory */
   1124 	va.va_mask = AT_SIZE;
   1125 	error = VOP_GETATTR(dcp->c_frontvp, &va, 0, kcred, NULL);
   1126 	if (error) {
   1127 		error = 0;
   1128 		goto out;
   1129 	}
   1130 
   1131 	/* XXX bob: change this to use cachfs_dir_read */
   1132 	/* We have found the parent, now we open the dir and look for file */
   1133 	while (blockoff < va.va_size) {
   1134 		offset = 0;
   1135 		error = fbread(dcp->c_frontvp, (offset_t)blockoff, MAXBSIZE,
   1136 						S_OTHER, &fbp);
   1137 		if (error)
   1138 			goto out;
   1139 		while (offset < MAXBSIZE && (blockoff + offset) < va.va_size) {
   1140 			struct c_dirent	*dep;
   1141 			dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr +
   1142 									offset);
   1143 			if ((dep->d_flag & CDE_VALID) &&
   1144 			    (bcmp(&dep->d_id, &infop->gi_cid,
   1145 			    sizeof (cfs_cid_t)) == 0)) {
   1146 				/* found the name */
   1147 				(void) strcpy(infop->gi_name, dep->d_name);
   1148 				fbrelse(fbp, S_OTHER);
   1149 				goto out;
   1150 			}
   1151 			offset += dep->d_length;
   1152 		}
   1153 		fbrelse(fbp, S_OTHER);
   1154 		fbp = NULL;
   1155 		blockoff += MAXBSIZE;
   1156 
   1157 	}
   1158 out:
   1159 	if (cp)
   1160 		VN_RELE(CTOV(cp));
   1161 	if (dcp)
   1162 		VN_RELE(CTOV(dcp));
   1163 	return (error);
   1164 }
   1165 
   1166 /*
   1167  * Given a file number, this functions returns the fid
   1168  * for the back file system.
   1169  * Returns ENOENT if file does not exist.
   1170  * Returns ENOMSG if fid is not valid, ie: local file.
   1171  */
   1172 int
   1173 cachefs_io_cidtofid(vnode_t *vp, void *dinp, void *doutp)
   1174 {
   1175 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
   1176 	cnode_t *cp = NULL;
   1177 	int error;
   1178 	cfs_cid_t *cidp = (cfs_cid_t *)dinp;
   1179 	cfs_fid_t *fidp = (cfs_fid_t *)doutp;
   1180 
   1181 	/*
   1182 	 * Only called in support of disconnectable operation, so assert
   1183 	 * that this is not called when NFSv4 is the backfilesytem.
   1184 	 */
   1185 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1186 
   1187 	/* get the cnode for the file */
   1188 	error = cachefs_cnode_make(cidp, fscp, NULL, NULL, NULL, kcred, 0, &cp);
   1189 	if (error)
   1190 		goto out;
   1191 
   1192 	/* if local file, fid is a local fid and is not valid */
   1193 	if (cp->c_id.cid_flags & CFS_CID_LOCAL) {
   1194 		error = ENOMSG;
   1195 		goto out;
   1196 	}
   1197 
   1198 	/* copy out the fid */
   1199 	CACHEFS_FID_COPY(&cp->c_cookie, fidp);
   1200 
   1201 out:
   1202 	if (cp)
   1203 		VN_RELE(CTOV(cp));
   1204 	return	(error);
   1205 }
   1206 
   1207 /*
   1208  * This performs a getattr on the back file system given
   1209  * a fid that is passed in.
   1210  *
   1211  * The backfid is in gafid->cg_backfid, the creds to use for
   1212  * this operation are in gafid->cg_cred.  The attributes are
   1213  * returned in gafid->cg_attr
   1214  *
   1215  * the error returned is 0 if successful, nozero if not
   1216  */
   1217 int
   1218 cachefs_io_getattrfid(vnode_t *vp, void *dinp, void *doutp)
   1219 {
   1220 	vnode_t	*backvp = NULL;
   1221 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
   1222 	int error = 0;
   1223 	cred_t	*cr;
   1224 	cachefsio_getattrfid_t *gafid;
   1225 	fid_t	*tmpfidp;
   1226 	vattr_t *tmpvap;
   1227 	cfs_vattr_t *attrp;
   1228 	CACHEFS_DECL(fid_t, tmpfid);
   1229 	CACHEFS_DECL(vattr_t, va);
   1230 
   1231 	/*
   1232 	 * Only called in support of disconnectable operation, so assert
   1233 	 * that this is not called when NFSv4 is the backfilesytem.
   1234 	 */
   1235 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1236 
   1237 	gafid = (cachefsio_getattrfid_t *)dinp;
   1238 	attrp = (cfs_vattr_t *)doutp;
   1239 
   1240 	/* Get a vnode for the back file */
   1241 	CACHEFS_TMPPTR_SET(&gafid->cg_backfid, &tmpfid, tmpfidp, fid_t);
   1242 	CACHEFS_FID_COPYIN(&gafid->cg_backfid, tmpfidp);
   1243 	error = VFS_VGET(fscp->fs_backvfsp, &backvp, tmpfidp);
   1244 	if (error)
   1245 		return (error);
   1246 
   1247 	cr = conj_cred(&gafid->cg_cred);
   1248 	CACHEFS_TMPPTR_SET(attrp, &va, tmpvap, vattr_t);
   1249 	tmpvap->va_mask = AT_ALL;
   1250 	error = VOP_GETATTR(backvp, tmpvap, 0, cr, NULL);
   1251 	CACHEFS_VATTR_COPYOUT(tmpvap, attrp, error);
   1252 	crfree(cr);
   1253 
   1254 	/* VFS_VGET performs a VN_HOLD on the vp */
   1255 	VN_RELE(backvp);
   1256 
   1257 	return (error);
   1258 }
   1259 
   1260 
   1261 /*
   1262  * This performs a getattr on the back file system.  Instead of
   1263  * passing the fid to perform the gettr on we are given the
   1264  * parent directory fid and a name.
   1265  */
   1266 int
   1267 cachefs_io_getattrname(vnode_t *vp, void *dinp, void *doutp)
   1268 {
   1269 	vnode_t	*pbackvp = NULL;
   1270 	vnode_t	*cbackvp = NULL;
   1271 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
   1272 	int error = 0;
   1273 	cred_t	*cr;
   1274 	fid_t	*tmpfidp;
   1275 	vattr_t	*tmpvap;
   1276 	cachefsio_getattrname_arg_t *gap;
   1277 	cachefsio_getattrname_return_t *retp;
   1278 	CACHEFS_DECL(fid_t, tmpfid);
   1279 	CACHEFS_DECL(vattr_t, va);
   1280 
   1281 	/*
   1282 	 * Only called in support of disconnectable operation, so assert
   1283 	 * that this is not called when NFSv4 is the backfilesytem.
   1284 	 */
   1285 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1286 
   1287 	gap = (cachefsio_getattrname_arg_t *)dinp;
   1288 	retp = (cachefsio_getattrname_return_t *)doutp;
   1289 
   1290 	/* Get a vnode for the parent directory */
   1291 	CACHEFS_TMPPTR_SET(&gap->cg_dir, &tmpfid, tmpfidp, fid_t);
   1292 	CACHEFS_FID_COPYIN(&gap->cg_dir, tmpfidp);
   1293 	error = VFS_VGET(fscp->fs_backvfsp, &pbackvp, tmpfidp);
   1294 	if (error)
   1295 		return (error);
   1296 
   1297 	/* lookup the file name */
   1298 	cr = conj_cred(&gap->cg_cred);
   1299 	error = VOP_LOOKUP(pbackvp, gap->cg_name, &cbackvp,
   1300 	    (struct pathname *)NULL, 0, (vnode_t *)NULL, cr, NULL, NULL, NULL);
   1301 	if (error) {
   1302 		crfree(cr);
   1303 		VN_RELE(pbackvp);
   1304 		return (error);
   1305 	}
   1306 
   1307 	CACHEFS_TMPPTR_SET(&retp->cg_attr, &va, tmpvap, vattr_t);
   1308 	tmpvap->va_mask = AT_ALL;
   1309 	error = VOP_GETATTR(cbackvp, tmpvap, 0, cr, NULL);
   1310 	CACHEFS_VATTR_COPYOUT(tmpvap, &retp->cg_attr, error);
   1311 	if (!error) {
   1312 		CACHEFS_TMPPTR_SET(&retp->cg_fid, &tmpfid, tmpfidp, fid_t);
   1313 		tmpfidp->fid_len = MAXFIDSZ;
   1314 		error = VOP_FID(cbackvp, tmpfidp, NULL);
   1315 		CACHEFS_FID_COPYOUT(tmpfidp, &retp->cg_fid);
   1316 	}
   1317 
   1318 	crfree(cr);
   1319 	VN_RELE(cbackvp);
   1320 	VN_RELE(pbackvp);
   1321 	return (error);
   1322 }
   1323 
   1324 /*
   1325  * This will return the fid of the root of this mount point.
   1326  */
   1327 int
   1328 /*ARGSUSED*/
   1329 cachefs_io_rootfid(vnode_t *vp, void *dinp, void *doutp)
   1330 {
   1331 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
   1332 	cfs_fid_t *rootfid = (cfs_fid_t *)doutp;
   1333 
   1334 	/*
   1335 	 * Only called in support of disconnectable operation, so assert
   1336 	 * that this is not called when NFSv4 is the backfilesytem.
   1337 	 */
   1338 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1339 
   1340 	CACHEFS_FID_COPY(&VTOC(fscp->fs_rootvp)->c_metadata.md_cookie, rootfid);
   1341 	return (0);
   1342 }
   1343 
   1344 /*
   1345  * Pushes the data associated with a file back to the file server.
   1346  */
   1347 int
   1348 cachefs_io_pushback(vnode_t *vp, void *dinp, void *doutp)
   1349 {
   1350 	vnode_t *backvp = NULL;
   1351 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
   1352 	caddr_t	buffer = NULL;
   1353 	int error = 0;
   1354 	cnode_t	*cp;
   1355 	size_t amt;
   1356 	u_offset_t size;
   1357 	vattr_t	va;
   1358 	offset_t off;
   1359 	cred_t *cr = NULL;
   1360 	fid_t	*tmpfidp;
   1361 	cachefsio_pushback_arg_t *pbp;
   1362 	cachefsio_pushback_return_t *retp;
   1363 	CACHEFS_DECL(fid_t, tmpfid);
   1364 
   1365 	/*
   1366 	 * Only called in support of disconnectable operation, so assert
   1367 	 * that this is not called when NFSv4 is the backfilesytem.
   1368 	 */
   1369 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1370 
   1371 	pbp = (cachefsio_pushback_arg_t *)dinp;
   1372 	retp = (cachefsio_pushback_return_t *)doutp;
   1373 
   1374 	cr = conj_cred(&pbp->pb_cred);
   1375 
   1376 	/* get the backvp to push to */
   1377 	CACHEFS_TMPPTR_SET(&pbp->pb_fid, &tmpfid, tmpfidp, fid_t);
   1378 	CACHEFS_FID_COPYIN(&pbp->pb_fid, tmpfidp);
   1379 	error = VFS_VGET(fscp->fs_backvfsp, &backvp, tmpfidp);
   1380 	if (error) {
   1381 		backvp = NULL;
   1382 		goto out;
   1383 	}
   1384 
   1385 	/* Get the cnode for the file we are to push back */
   1386 	error = cachefs_cnode_make(&pbp->pb_cid, fscp,
   1387 	    NULL, NULL, NULL, cr, 0, &cp);
   1388 	if (error) {
   1389 		goto out;
   1390 	}
   1391 
   1392 	/* must be a regular file */
   1393 	if (cp->c_attr.va_type != VREG) {
   1394 		error = EINVAL;
   1395 		goto out;
   1396 	}
   1397 
   1398 	mutex_enter(&cp->c_statelock);
   1399 
   1400 	/* get the front file */
   1401 	if (cp->c_frontvp == NULL) {
   1402 		error = cachefs_getfrontfile(cp);
   1403 		if (error) {
   1404 			mutex_exit(&cp->c_statelock);
   1405 			goto out;
   1406 		}
   1407 	}
   1408 
   1409 	/* better be populated */
   1410 	if ((cp->c_metadata.md_flags & MD_POPULATED) == 0) {
   1411 		mutex_exit(&cp->c_statelock);
   1412 		error = EINVAL;
   1413 		goto out;
   1414 	}
   1415 
   1416 	/* do open so NFS gets correct creds on writes */
   1417 	error = VOP_OPEN(&backvp, FWRITE, cr, NULL);
   1418 	if (error) {
   1419 		mutex_exit(&cp->c_statelock);
   1420 		goto out;
   1421 	}
   1422 
   1423 	buffer = cachefs_kmem_alloc(MAXBSIZE, KM_SLEEP);
   1424 
   1425 	/* Read the data from the cache and write it to the server */
   1426 	/* XXX why not use segmapio? */
   1427 	off = 0;
   1428 	for (size = cp->c_size; size != 0; size -= amt) {
   1429 		if (size > MAXBSIZE)
   1430 			amt = MAXBSIZE;
   1431 		else
   1432 			amt = size;
   1433 
   1434 		/* read a block of data from the front file */
   1435 		error = vn_rdwr(UIO_READ, cp->c_frontvp, buffer,
   1436 			amt, off, UIO_SYSSPACE, 0, RLIM_INFINITY, cr, 0);
   1437 		if (error) {
   1438 			mutex_exit(&cp->c_statelock);
   1439 			goto out;
   1440 		}
   1441 
   1442 		/* write the block of data to the back file */
   1443 		error = vn_rdwr(UIO_WRITE, backvp, buffer, amt, off,
   1444 			UIO_SYSSPACE, 0, RLIM_INFINITY, cr, 0);
   1445 		if (error) {
   1446 			mutex_exit(&cp->c_statelock);
   1447 			goto out;
   1448 		}
   1449 		off += amt;
   1450 	}
   1451 
   1452 	error = VOP_FSYNC(backvp, FSYNC, cr, NULL);
   1453 	if (error == 0)
   1454 		error = VOP_CLOSE(backvp, FWRITE, 1, (offset_t)0, cr, NULL);
   1455 	if (error) {
   1456 		mutex_exit(&cp->c_statelock);
   1457 		goto out;
   1458 	}
   1459 
   1460 	cp->c_metadata.md_flags |= MD_PUSHDONE;
   1461 	cp->c_metadata.md_flags &= ~MD_PUTPAGE;
   1462 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
   1463 	cp->c_flags |= CN_UPDATED;
   1464 	mutex_exit(&cp->c_statelock);
   1465 
   1466 	/*
   1467 	 * if we have successfully stored the data, we need the
   1468 	 * new ctime and mtimes.
   1469 	 */
   1470 	va.va_mask = AT_ALL;
   1471 	error = VOP_GETATTR(backvp, &va, 0, cr, NULL);
   1472 	if (error)
   1473 		goto out;
   1474 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->pb_ctime, error);
   1475 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->pb_mtime, error);
   1476 
   1477 out:
   1478 	if (buffer)
   1479 		cachefs_kmem_free(buffer, MAXBSIZE);
   1480 	if (cp)
   1481 		VN_RELE(CTOV(cp));
   1482 	if (backvp)
   1483 		VN_RELE(backvp);
   1484 	if (cr)
   1485 		crfree(cr);
   1486 	return (error);
   1487 }
   1488 
   1489 /*
   1490  * Create a file on the back file system.
   1491  */
   1492 int
   1493 cachefs_io_create(vnode_t *vp, void *dinp, void *doutp)
   1494 {
   1495 	vnode_t	*dvp = NULL;
   1496 	vnode_t	*cvp = NULL;
   1497 	cnode_t *cp = NULL;
   1498 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
   1499 	vattr_t	va, *tmpvap;
   1500 	int error = 0;
   1501 	cred_t *cr = NULL;
   1502 	fid_t	*tmpfidp;
   1503 	cachefsio_create_arg_t *crp;
   1504 	cachefsio_create_return_t *retp;
   1505 	CACHEFS_DECL(fid_t, tmpfid);
   1506 
   1507 	/*
   1508 	 * Only called in support of disconnectable operation, so assert
   1509 	 * that this is not called when NFSv4 is the backfilesytem.
   1510 	 */
   1511 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1512 
   1513 	crp = (cachefsio_create_arg_t *)dinp;
   1514 	retp = (cachefsio_create_return_t *)doutp;
   1515 
   1516 	/* get a vnode for the parent directory  */
   1517 	CACHEFS_TMPPTR_SET(&crp->cr_backfid, &tmpfid, tmpfidp, fid_t);
   1518 	CACHEFS_FID_COPYIN(&crp->cr_backfid, tmpfidp);
   1519 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
   1520 	if (error)
   1521 		goto out;
   1522 
   1523 	cr = conj_cred(&crp->cr_cred);
   1524 
   1525 	/* do the create */
   1526 	CACHEFS_TMPPTR_SET(&crp->cr_va, &va, tmpvap, vattr_t);
   1527 	CACHEFS_VATTR_COPYIN(&crp->cr_va, tmpvap);
   1528 	error = VOP_CREATE(dvp, crp->cr_name, tmpvap,
   1529 	    crp->cr_exclusive, crp->cr_mode, &cvp, cr, 0, NULL, NULL);
   1530 	if (error)
   1531 		goto out;
   1532 
   1533 	/* get the fid of the file */
   1534 	CACHEFS_TMPPTR_SET(&retp->cr_newfid, &tmpfid, tmpfidp, fid_t);
   1535 	tmpfidp->fid_len = MAXFIDSZ;
   1536 	error = VOP_FID(cvp, tmpfidp, NULL);
   1537 	if (error)
   1538 		goto out;
   1539 	CACHEFS_FID_COPYOUT(tmpfidp, &retp->cr_newfid);
   1540 
   1541 	/* get attributes for the file */
   1542 	va.va_mask = AT_ALL;
   1543 	error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
   1544 	if (error)
   1545 		goto out;
   1546 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->cr_ctime, error);
   1547 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->cr_mtime, error);
   1548 	if (error)
   1549 		goto out;
   1550 
   1551 	/* update the cnode for this file with the new info */
   1552 	error = cachefs_cnode_make(&crp->cr_cid, fscp,
   1553 	    NULL, NULL, NULL, cr, 0, &cp);
   1554 	if (error) {
   1555 		error = 0;
   1556 		goto out;
   1557 	}
   1558 
   1559 	mutex_enter(&cp->c_statelock);
   1560 	ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL);
   1561 	cp->c_attr.va_nodeid = va.va_nodeid;
   1562 	cp->c_metadata.md_flags |= MD_CREATEDONE;
   1563 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
   1564 	cp->c_metadata.md_cookie = *tmpfidp;
   1565 	cp->c_flags |= CN_UPDATED;
   1566 	mutex_exit(&cp->c_statelock);
   1567 
   1568 out:
   1569 	if (cr)
   1570 		crfree(cr);
   1571 	if (dvp)
   1572 		VN_RELE(dvp);
   1573 	if (cvp)
   1574 		VN_RELE(cvp);
   1575 	if (cp)
   1576 		VN_RELE(CTOV(cp));
   1577 	return (error);
   1578 }
   1579 
   1580 /*
   1581  * Remove a file on the back file system.
   1582  * Returns 0 or an error if could not perform operation.
   1583  */
   1584 int
   1585 cachefs_io_remove(vnode_t *vp, void *dinp, void *doutp)
   1586 {
   1587 	vnode_t	*dvp = NULL;
   1588 	vnode_t	*cvp;
   1589 	cred_t *cr = NULL;
   1590 	vattr_t	va;
   1591 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
   1592 	int error;
   1593 	fid_t child_fid, *child_fidp;
   1594 	cachefsio_remove_t *rmp = (cachefsio_remove_t *)dinp;
   1595 	cfs_timestruc_t *ctimep = (cfs_timestruc_t *)doutp;
   1596 
   1597 	/*
   1598 	 * Only called in support of disconnectable operation, so assert
   1599 	 * that this is not called when NFSv4 is the backfilesytem.
   1600 	 */
   1601 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1602 
   1603 	/* Get a vnode for the directory */
   1604 	CACHEFS_TMPPTR_SET(&rmp->rm_fid, &child_fid, child_fidp, fid_t);
   1605 	CACHEFS_FID_COPYIN(&rmp->rm_fid, child_fidp);
   1606 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, child_fidp);
   1607 	if (error) {
   1608 		dvp = NULL;
   1609 		goto out;
   1610 	}
   1611 
   1612 	cr = conj_cred(&rmp->rm_cred);
   1613 
   1614 	/* if the caller wants the ctime after the remove */
   1615 	if (ctimep) {
   1616 		error = VOP_LOOKUP(dvp, rmp->rm_name, &cvp, NULL, 0, NULL, cr,
   1617 			NULL, NULL, NULL);
   1618 		if (error == 0) {
   1619 			child_fid.fid_len = MAXFIDSZ;
   1620 			error = VOP_FID(cvp, &child_fid, NULL);
   1621 			VN_RELE(cvp);
   1622 		}
   1623 		if (error)
   1624 			goto out;
   1625 	}
   1626 
   1627 	/* do the remove */
   1628 	error = VOP_REMOVE(dvp, rmp->rm_name, cr, NULL, 0);
   1629 	if (error)
   1630 		goto out;
   1631 
   1632 	/* get the new ctime if requested */
   1633 	if (ctimep) {
   1634 		error = VFS_VGET(fscp->fs_backvfsp, &cvp, &child_fid);
   1635 		if (error == 0) {
   1636 			va.va_mask = AT_ALL;
   1637 			error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
   1638 			if (error == 0) {
   1639 				CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime,
   1640 					ctimep, error);
   1641 			}
   1642 			VN_RELE(cvp);
   1643 		}
   1644 		cachefs_iosetneedattrs(fscp, &rmp->rm_cid);
   1645 	}
   1646 
   1647 out:
   1648 	if (cr)
   1649 		crfree(cr);
   1650 	if (dvp)
   1651 		VN_RELE(dvp);
   1652 	return (error);
   1653 }
   1654 
   1655 /*
   1656  * Perform a link on the back file system.
   1657  * Returns 0 or an error if could not perform operation.
   1658  */
   1659 int
   1660 cachefs_io_link(vnode_t *vp, void *dinp, void *doutp)
   1661 {
   1662 	vnode_t	*dvp = NULL;
   1663 	vnode_t	*lvp = NULL;
   1664 	vattr_t	va;
   1665 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
   1666 	int error = 0;
   1667 	cred_t *cr = NULL;
   1668 	fid_t *tmpfidp;
   1669 	cachefsio_link_t *linkp = (cachefsio_link_t *)dinp;
   1670 	cfs_timestruc_t *ctimep = (cfs_timestruc_t *)doutp;
   1671 	CACHEFS_DECL(fid_t, tmpfid);
   1672 
   1673 	/*
   1674 	 * Only called in support of disconnectable operation, so assert
   1675 	 * that this is not called when NFSv4 is the backfilesytem.
   1676 	 */
   1677 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1678 
   1679 	/* Get a vnode parent directory */
   1680 	CACHEFS_TMPPTR_SET(&linkp->ln_dirfid, &tmpfid, tmpfidp, fid_t);
   1681 	CACHEFS_FID_COPYIN(&linkp->ln_dirfid, tmpfidp);
   1682 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
   1683 	if (error) {
   1684 		dvp = NULL;
   1685 		goto out;
   1686 	}
   1687 
   1688 	/* Get a vnode file to link to */
   1689 	CACHEFS_TMPPTR_SET(&linkp->ln_filefid, &tmpfid, tmpfidp, fid_t);
   1690 	CACHEFS_FID_COPYIN(&linkp->ln_filefid, tmpfidp);
   1691 	error = VFS_VGET(fscp->fs_backvfsp, &lvp, tmpfidp);
   1692 	if (error) {
   1693 		lvp = NULL;
   1694 		goto out;
   1695 	}
   1696 
   1697 	cr = conj_cred(&linkp->ln_cred);
   1698 
   1699 	/* do the link */
   1700 	error = VOP_LINK(dvp, lvp, linkp->ln_name, cr, NULL, 0);
   1701 	if (error)
   1702 		goto out;
   1703 
   1704 	/* get the ctime */
   1705 	va.va_mask = AT_ALL;
   1706 	error = VOP_GETATTR(lvp, &va, 0, cr, NULL);
   1707 	if (error)
   1708 		goto out;
   1709 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, ctimep, error);
   1710 	if (error)
   1711 		goto out;
   1712 
   1713 	cachefs_iosetneedattrs(fscp, &linkp->ln_cid);
   1714 out:
   1715 	if (cr)
   1716 		crfree(cr);
   1717 	if (dvp)
   1718 		VN_RELE(dvp);
   1719 	if (lvp)
   1720 		VN_RELE(lvp);
   1721 	return (error);
   1722 }
   1723 
   1724 /*
   1725  * Rename the file on the back file system.
   1726  * Returns 0 or an error if could not perform operation.
   1727  */
   1728 int
   1729 cachefs_io_rename(vnode_t *vp, void *dinp, void *doutp)
   1730 {
   1731 	vnode_t	*odvp = NULL;
   1732 	vnode_t	*ndvp = NULL;
   1733 	cred_t *cr = NULL;
   1734 	vnode_t	*cvp = NULL;
   1735 	vattr_t va;
   1736 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
   1737 	int error = 0;
   1738 	fid_t child_fid, *child_fidp;
   1739 	cachefsio_rename_arg_t *rnp;
   1740 	cachefsio_rename_return_t *retp;
   1741 
   1742 	/*
   1743 	 * Only called in support of disconnectable operation, so assert
   1744 	 * that this is not called when NFSv4 is the backfilesytem.
   1745 	 */
   1746 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1747 
   1748 	rnp = (cachefsio_rename_arg_t *)dinp;
   1749 	retp = (cachefsio_rename_return_t *)doutp;
   1750 
   1751 	/* Get vnode of old parent directory */
   1752 	CACHEFS_TMPPTR_SET(&rnp->rn_olddir, &child_fid, child_fidp, fid_t);
   1753 	CACHEFS_FID_COPYIN(&rnp->rn_olddir, child_fidp);
   1754 	error = VFS_VGET(fscp->fs_backvfsp, &odvp, child_fidp);
   1755 	if (error) {
   1756 		odvp = NULL;
   1757 		goto out;
   1758 	}
   1759 
   1760 	/* Get vnode of new parent directory */
   1761 	CACHEFS_TMPPTR_SET(&rnp->rn_newdir, &child_fid, child_fidp, fid_t);
   1762 	CACHEFS_FID_COPYIN(&rnp->rn_newdir, child_fidp);
   1763 	error = VFS_VGET(fscp->fs_backvfsp, &ndvp, child_fidp);
   1764 	if (error) {
   1765 		ndvp = NULL;
   1766 		goto out;
   1767 	}
   1768 
   1769 	cr = conj_cred(&rnp->rn_cred);
   1770 
   1771 	/* if the caller wants the ctime of the target after deletion */
   1772 	if (rnp->rn_del_getctime) {
   1773 		error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0,
   1774 		    NULL, cr, NULL, NULL, NULL);
   1775 		if (error) {
   1776 			cvp = NULL; /* paranoia */
   1777 			goto out;
   1778 		}
   1779 
   1780 		child_fid.fid_len = MAXFIDSZ;
   1781 		error = VOP_FID(cvp, &child_fid, NULL);
   1782 		if (error)
   1783 			goto out;
   1784 		VN_RELE(cvp);
   1785 		cvp = NULL;
   1786 	}
   1787 
   1788 	/* do the rename */
   1789 	error = VOP_RENAME(odvp, rnp->rn_oldname, ndvp, rnp->rn_newname, cr,
   1790 		NULL, 0);
   1791 	if (error)
   1792 		goto out;
   1793 
   1794 	/* get the new ctime on the renamed file */
   1795 	error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0, NULL, cr,
   1796 		NULL, NULL, NULL);
   1797 	if (error)
   1798 		goto out;
   1799 
   1800 	va.va_mask = AT_ALL;
   1801 	error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
   1802 	if (error)
   1803 		goto out;
   1804 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->rn_ctime, error);
   1805 	VN_RELE(cvp);
   1806 	cvp = NULL;
   1807 	if (error)
   1808 		goto out;
   1809 
   1810 	cachefs_iosetneedattrs(fscp, &rnp->rn_cid);
   1811 
   1812 	/* get the new ctime if requested of the deleted target */
   1813 	if (rnp->rn_del_getctime) {
   1814 		error = VFS_VGET(fscp->fs_backvfsp, &cvp, &child_fid);
   1815 		if (error) {
   1816 			cvp = NULL;
   1817 			goto out;
   1818 		}
   1819 		va.va_mask = AT_ALL;
   1820 		error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
   1821 		if (error)
   1822 			goto out;
   1823 		CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->rn_del_ctime,
   1824 			error);
   1825 		VN_RELE(cvp);
   1826 		cvp = NULL;
   1827 		if (error)
   1828 			goto out;
   1829 		cachefs_iosetneedattrs(fscp, &rnp->rn_del_cid);
   1830 	}
   1831 
   1832 out:
   1833 	if (cr)
   1834 		crfree(cr);
   1835 	if (cvp)
   1836 		VN_RELE(cvp);
   1837 	if (odvp)
   1838 		VN_RELE(odvp);
   1839 	if (ndvp)
   1840 		VN_RELE(ndvp);
   1841 	return (error);
   1842 }
   1843 
   1844 /*
   1845  * Make a directory on the backfs.
   1846  * Returns 0 or an error if could not perform operation.
   1847  */
   1848 int
   1849 cachefs_io_mkdir(vnode_t *vp, void *dinp, void *doutp)
   1850 {
   1851 	vnode_t	*dvp = NULL;
   1852 	vnode_t	*cvp = NULL;
   1853 	cnode_t *cp = NULL;
   1854 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
   1855 	int error = 0;
   1856 	cred_t *cr = NULL;
   1857 	fid_t	*tmpfidp;
   1858 	vattr_t va, *tmpvap;
   1859 	cachefsio_mkdir_t *mdirp = (cachefsio_mkdir_t *)dinp;
   1860 	cfs_fid_t *fidp = (cfs_fid_t *)doutp;
   1861 	CACHEFS_DECL(fid_t, tmpfid);
   1862 
   1863 	/*
   1864 	 * Only called in support of disconnectable operation, so assert
   1865 	 * that this is not called when NFSv4 is the backfilesytem.
   1866 	 */
   1867 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1868 
   1869 	/* Get vnode of parent directory */
   1870 	CACHEFS_TMPPTR_SET(&mdirp->md_dirfid, &tmpfid, tmpfidp, fid_t);
   1871 	CACHEFS_FID_COPYIN(&mdirp->md_dirfid, tmpfidp);
   1872 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
   1873 	if (error) {
   1874 		dvp = NULL;
   1875 		goto out;
   1876 	}
   1877 
   1878 	cr = conj_cred(&mdirp->md_cred);
   1879 
   1880 	/* make the directory */
   1881 	CACHEFS_TMPPTR_SET(&mdirp->md_vattr, &va, tmpvap, vattr_t);
   1882 	CACHEFS_VATTR_COPYIN(&mdirp->md_vattr, tmpvap);
   1883 	error = VOP_MKDIR(dvp, mdirp->md_name, tmpvap, &cvp, cr, NULL, 0, NULL);
   1884 	if (error) {
   1885 		if (error != EEXIST)
   1886 			goto out;
   1887 
   1888 		/* if the directory already exists, then use it */
   1889 		error = VOP_LOOKUP(dvp, mdirp->md_name, &cvp,
   1890 		    NULL, 0, NULL, cr, NULL, NULL, NULL);
   1891 		if (error) {
   1892 			cvp = NULL;
   1893 			goto out;
   1894 		}
   1895 		if (cvp->v_type != VDIR) {
   1896 			error = EINVAL;
   1897 			goto out;
   1898 		}
   1899 	}
   1900 
   1901 	/* get the fid of the directory */
   1902 	CACHEFS_TMPPTR_SET(fidp, &tmpfid, tmpfidp, fid_t);
   1903 	tmpfidp->fid_len = MAXFIDSZ;
   1904 	error = VOP_FID(cvp, tmpfidp, NULL);
   1905 	if (error)
   1906 		goto out;
   1907 	CACHEFS_FID_COPYOUT(tmpfidp, fidp);
   1908 
   1909 	/* get attributes of the directory */
   1910 	va.va_mask = AT_ALL;
   1911 	error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
   1912 	if (error)
   1913 		goto out;
   1914 
   1915 	/* update the cnode for this dir with the new fid */
   1916 	error = cachefs_cnode_make(&mdirp->md_cid, fscp,
   1917 	    NULL, NULL, NULL, cr, 0, &cp);
   1918 	if (error) {
   1919 		error = 0;
   1920 		goto out;
   1921 	}
   1922 	mutex_enter(&cp->c_statelock);
   1923 	ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL);
   1924 	cp->c_metadata.md_cookie = *tmpfidp;
   1925 	cp->c_metadata.md_flags |= MD_CREATEDONE;
   1926 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
   1927 	cp->c_attr.va_nodeid = va.va_nodeid;
   1928 	cp->c_flags |= CN_UPDATED;
   1929 	mutex_exit(&cp->c_statelock);
   1930 out:
   1931 	if (cr)
   1932 		crfree(cr);
   1933 	if (dvp)
   1934 		VN_RELE(dvp);
   1935 	if (cvp)
   1936 		VN_RELE(cvp);
   1937 	if (cp)
   1938 		VN_RELE(CTOV(cp));
   1939 	return (error);
   1940 }
   1941 
   1942 /*
   1943  * Perform a rmdir on the back file system.
   1944  * Returns 0 or an error if could not perform operation.
   1945  */
   1946 int
   1947 /*ARGSUSED*/
   1948 cachefs_io_rmdir(vnode_t *vp, void *dinp, void *doutp)
   1949 {
   1950 	vnode_t	*dvp = NULL;
   1951 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
   1952 	int error;
   1953 	cred_t *cr;
   1954 	fid_t	*tmpfidp;
   1955 	cachefsio_rmdir_t *rdp = (cachefsio_rmdir_t *)dinp;
   1956 	CACHEFS_DECL(fid_t, tmpfid);
   1957 
   1958 	/*
   1959 	 * Only called in support of disconnectable operation, so assert
   1960 	 * that this is not called when NFSv4 is the backfilesytem.
   1961 	 */
   1962 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   1963 
   1964 	/* Get a vnode for the back file */
   1965 	CACHEFS_TMPPTR_SET(&rdp->rd_dirfid, &tmpfid, tmpfidp, fid_t);
   1966 	CACHEFS_FID_COPYIN(&rdp->rd_dirfid, tmpfidp);
   1967 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
   1968 	if (error) {
   1969 		dvp = NULL;
   1970 		return (error);
   1971 	}
   1972 
   1973 	cr = conj_cred(&rdp->rd_cred);
   1974 	error = VOP_RMDIR(dvp, rdp->rd_name, dvp, cr, NULL, 0);
   1975 	crfree(cr);
   1976 
   1977 	VN_RELE(dvp);
   1978 	return (error);
   1979 }
   1980 
   1981 /*
   1982  * create a symlink on the back file system
   1983  * Returns 0 or an error if could not perform operation.
   1984  */
   1985 int
   1986 cachefs_io_symlink(vnode_t *vp, void *dinp, void *doutp)
   1987 {
   1988 	vnode_t	*dvp = NULL;
   1989 	vnode_t	*svp = NULL;
   1990 	cnode_t *cp = NULL;
   1991 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
   1992 	fid_t	*tmpfidp;
   1993 	vattr_t	va, *tmpvap;
   1994 	int error = 0;
   1995 	cred_t *cr = NULL;
   1996 	cachefsio_symlink_arg_t *symp;
   1997 	cachefsio_symlink_return_t *retp;
   1998 	CACHEFS_DECL(fid_t, tmpfid);
   1999 
   2000 	/*
   2001 	 * Only called in support of disconnectable operation, so assert
   2002 	 * that this is not called when NFSv4 is the backfilesytem.
   2003 	 */
   2004 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   2005 
   2006 	symp = (cachefsio_symlink_arg_t *)dinp;
   2007 	retp = (cachefsio_symlink_return_t *)doutp;
   2008 
   2009 	/* get a vnode for the back directory */
   2010 	CACHEFS_TMPPTR_SET(&symp->sy_dirfid, &tmpfid, tmpfidp, fid_t);
   2011 	CACHEFS_FID_COPYIN(&symp->sy_dirfid, tmpfidp);
   2012 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
   2013 	if (error) {
   2014 		dvp = NULL;
   2015 		goto out;
   2016 	}
   2017 
   2018 	cr = conj_cred(&symp->sy_cred);
   2019 
   2020 	/* create the symlink */
   2021 	CACHEFS_TMPPTR_SET(&symp->sy_vattr, &va, tmpvap, vattr_t);
   2022 	CACHEFS_VATTR_COPYIN(&symp->sy_vattr, tmpvap);
   2023 	error = VOP_SYMLINK(dvp, symp->sy_name, tmpvap,
   2024 	    symp->sy_link, cr, NULL, 0);
   2025 	if (error)
   2026 		goto out;
   2027 
   2028 	/* get the vnode for the symlink */
   2029 	error = VOP_LOOKUP(dvp, symp->sy_name, &svp, NULL, 0, NULL, cr,
   2030 		NULL, NULL, NULL);
   2031 	if (error)
   2032 		goto out;
   2033 
   2034 	/* get the attributes of the symlink */
   2035 	va.va_mask = AT_ALL;
   2036 	error = VOP_GETATTR(svp, &va, 0, cr, NULL);
   2037 	if (error)
   2038 		goto out;
   2039 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sy_ctime, error);
   2040 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sy_mtime, error);
   2041 	if (error)
   2042 		goto out;
   2043 
   2044 	/* get the fid */
   2045 	CACHEFS_TMPPTR_SET(&retp->sy_newfid, &tmpfid, tmpfidp, fid_t);
   2046 	tmpfidp->fid_len = MAXFIDSZ;
   2047 	error = VOP_FID(svp, tmpfidp, NULL);
   2048 	if (error)
   2049 		goto out;
   2050 	CACHEFS_FID_COPYOUT(tmpfidp, &retp->sy_newfid);
   2051 
   2052 	/* update the cnode for this file with the new info */
   2053 	error = cachefs_cnode_make(&symp->sy_cid, fscp,
   2054 	    NULL, NULL, NULL, cr, 0, &cp);
   2055 	if (error) {
   2056 		error = 0;
   2057 		goto out;
   2058 	}
   2059 	mutex_enter(&cp->c_statelock);
   2060 	ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL);
   2061 	cp->c_metadata.md_cookie = *tmpfidp;
   2062 	cp->c_metadata.md_flags |= MD_CREATEDONE;
   2063 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
   2064 	cp->c_attr.va_nodeid = va.va_nodeid;
   2065 	cp->c_flags |= CN_UPDATED;
   2066 	mutex_exit(&cp->c_statelock);
   2067 
   2068 out:
   2069 	if (cr)
   2070 		crfree(cr);
   2071 	if (dvp)
   2072 		VN_RELE(dvp);
   2073 	if (svp)
   2074 		VN_RELE(svp);
   2075 	if (cp)
   2076 		VN_RELE(CTOV(cp));
   2077 	return (error);
   2078 }
   2079 
   2080 /*
   2081  * Perform setattr on the back file system.
   2082  * Returns 0 or an error if could not perform operation.
   2083  */
   2084 int
   2085 cachefs_io_setattr(vnode_t *vp, void *dinp, void *doutp)
   2086 {
   2087 	vnode_t	*cvp = NULL;
   2088 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
   2089 	fid_t	*tmpfidp;
   2090 	vattr_t	va, *tmpvap;
   2091 	int error = 0;
   2092 	cred_t *cr = NULL;
   2093 	cachefsio_setattr_arg_t *sap;
   2094 	cachefsio_setattr_return_t *retp;
   2095 	CACHEFS_DECL(fid_t, tmpfid);
   2096 
   2097 	/*
   2098 	 * Only called in support of disconnectable operation, so assert
   2099 	 * that this is not called when NFSv4 is the backfilesytem.
   2100 	 */
   2101 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   2102 
   2103 	sap = (cachefsio_setattr_arg_t *)dinp;
   2104 	retp = (cachefsio_setattr_return_t *)doutp;
   2105 
   2106 	/* get a vnode for the back directory */
   2107 	CACHEFS_TMPPTR_SET(&sap->sa_backfid, &tmpfid, tmpfidp, fid_t);
   2108 	CACHEFS_FID_COPYIN(&sap->sa_backfid, tmpfidp);
   2109 	error = VFS_VGET(fscp->fs_backvfsp, &cvp, tmpfidp);
   2110 	if (error) {
   2111 		cvp = NULL;
   2112 		goto out;
   2113 	}
   2114 
   2115 	cr = conj_cred(&sap->sa_cred);
   2116 
   2117 	/* perform the setattr */
   2118 	CACHEFS_TMPPTR_SET(&sap->sa_vattr, &va, tmpvap, vattr_t);
   2119 	CACHEFS_VATTR_COPYIN(&sap->sa_vattr, tmpvap);
   2120 	error = VOP_SETATTR(cvp, tmpvap, 0, cr, NULL);
   2121 	if (error)
   2122 		goto out;
   2123 
   2124 	/* get the new ctime and mtime */
   2125 	va.va_mask = AT_ALL;
   2126 	error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
   2127 	if (error)
   2128 		goto out;
   2129 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sa_ctime, error);
   2130 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sa_mtime, error);
   2131 	if (error)
   2132 		goto out;
   2133 
   2134 	cachefs_iosetneedattrs(fscp, &sap->sa_cid);
   2135 out:
   2136 	if (cr)
   2137 		crfree(cr);
   2138 	if (cvp)
   2139 		VN_RELE(cvp);
   2140 	return (error);
   2141 }
   2142 
   2143 int
   2144 cachefs_io_setsecattr(vnode_t *vp, void *dinp, void *doutp)
   2145 {
   2146 	int error = 0;
   2147 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
   2148 	vnode_t *tvp = NULL;
   2149 	vsecattr_t vsec;
   2150 	vattr_t va;
   2151 	cred_t *cr = NULL;
   2152 	fid_t	*tmpfidp;
   2153 	cachefsio_setsecattr_arg_t *ssap;
   2154 	cachefsio_setsecattr_return_t *retp;
   2155 	CACHEFS_DECL(fid_t, tmpfid);
   2156 
   2157 	/*
   2158 	 * Only called in support of disconnectable operation, so assert
   2159 	 * that this is not called when NFSv4 is the backfilesytem.
   2160 	 */
   2161 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
   2162 
   2163 	ssap = (cachefsio_setsecattr_arg_t *)dinp;
   2164 	retp = (cachefsio_setsecattr_return_t *)doutp;
   2165 
   2166 	/* get vnode of back file to do VOP_SETSECATTR to */
   2167 	CACHEFS_TMPPTR_SET(&ssap->sc_backfid, &tmpfid, tmpfidp, fid_t);
   2168 	CACHEFS_FID_COPYIN(&ssap->sc_backfid, tmpfidp);
   2169 	error = VFS_VGET(fscp->fs_backvfsp, &tvp, tmpfidp);
   2170 	if (error != 0) {
   2171 		tvp = NULL;
   2172 		goto out;
   2173 	}
   2174 
   2175 	/* get the creds */
   2176 	cr = conj_cred(&ssap->sc_cred);
   2177 
   2178 	/* form the vsecattr_t */
   2179 	vsec.vsa_mask = ssap->sc_mask;
   2180 	vsec.vsa_aclcnt = ssap->sc_aclcnt;
   2181 	vsec.vsa_dfaclcnt = ssap->sc_dfaclcnt;
   2182 	vsec.vsa_aclentp = ssap->sc_acl;
   2183 	vsec.vsa_dfaclentp = ssap->sc_acl + ssap->sc_aclcnt;
   2184 
   2185 	/* set the ACL */
   2186 	(void) VOP_RWLOCK(tvp, V_WRITELOCK_TRUE, NULL);
   2187 	error = VOP_SETSECATTR(tvp, &vsec, 0, cr, NULL);
   2188 	VOP_RWUNLOCK(tvp, V_WRITELOCK_TRUE, NULL);
   2189 	if (error != 0)
   2190 		goto out;
   2191 
   2192 	/* get the new ctime and mtime */
   2193 	va.va_mask = AT_ALL;
   2194 	error = VOP_GETATTR(tvp, &va, 0, cr, NULL);
   2195 	if (error)
   2196 		goto out;
   2197 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sc_ctime, error);
   2198 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sc_mtime, error);
   2199 	if (error)
   2200 		goto out;
   2201 
   2202 	cachefs_iosetneedattrs(fscp, &ssap->sc_cid);
   2203 out:
   2204 
   2205 	if (cr != NULL)
   2206 		crfree(cr);
   2207 	if (tvp != NULL)
   2208 		VN_RELE(tvp);
   2209 
   2210 	return (error);
   2211 }
   2212 
   2213 static void
   2214 sync_metadata(cnode_t *cp)
   2215 {
   2216 	if (cp->c_flags & (CN_STALE | CN_DESTROY))
   2217 		return;
   2218 	(void) cachefs_sync_metadata(cp);
   2219 }
   2220 
   2221 static void
   2222 drop_backvp(cnode_t *cp)
   2223 {
   2224 	if (cp->c_backvp) {
   2225 		mutex_enter(&cp->c_statelock);
   2226 		if (cp->c_backvp) {
   2227 			/* dump any pages, may be a dirty one */
   2228 			(void) VOP_PUTPAGE(cp->c_backvp, (offset_t)0, 0,
   2229 			    B_INVAL | B_TRUNC, kcred, NULL);
   2230 		}
   2231 		mutex_exit(&cp->c_statelock);
   2232 	}
   2233 }
   2234 
   2235 static void
   2236 allow_pendrm(cnode_t *cp)
   2237 {
   2238 	if (cp->c_flags & CN_PENDRM) {
   2239 		mutex_enter(&cp->c_statelock);
   2240 		if (cp->c_flags & CN_PENDRM) {
   2241 			cp->c_flags &= ~CN_PENDRM;
   2242 			VN_RELE(CTOV(cp));
   2243 		}
   2244 		mutex_exit(&cp->c_statelock);
   2245 	}
   2246 }
   2247 
   2248 static void
   2249 cachefs_modified_fix(fscache_t *fscp)
   2250 {
   2251 	cnode_t *cp;
   2252 	int error = 0;
   2253 	rl_entry_t rl_ent;
   2254 	cfs_cid_t cid;
   2255 	cachefscache_t *cachep = fscp->fs_cache;
   2256 	enum cachefs_rl_type type;
   2257 	cachefs_metadata_t *mdp;
   2258 	int timedout = 0;
   2259 	struct vattr va;
   2260 
   2261 	/* XXX just return if fs is in error ro mode */
   2262 
   2263 	/* lock out other users of the MF list */
   2264 	mutex_enter(&cachep->c_mflock);
   2265 
   2266 	/* move the modified entries for this file system to the MF list */
   2267 	cachefs_move_modified_to_mf(cachep, fscp);
   2268 
   2269 	rl_ent.rl_current = CACHEFS_RL_MF;
   2270 	for (;;) {
   2271 		/* get the next entry on the MF list */
   2272 		error = cachefs_rlent_data(cachep, &rl_ent, NULL);
   2273 		if (error) {
   2274 			error = 0;
   2275 			break;
   2276 		}
   2277 		ASSERT(fscp->fs_cfsid == rl_ent.rl_fsid);
   2278 
   2279 		/* get the cnode for the file */
   2280 		cid.cid_fileno = rl_ent.rl_fileno;
   2281 		cid.cid_flags = rl_ent.rl_local ? CFS_CID_LOCAL : 0;
   2282 		error = cachefs_cnode_make(&cid, fscp,
   2283 		    NULL, NULL, NULL, kcred, 0, &cp);
   2284 		if (error) {
   2285 #ifdef CFSDEBUG
   2286 			CFS_DEBUG(CFSDEBUG_IOCTL)
   2287 				printf("cachefs: mf: could not find %llu\n",
   2288 				    (u_longlong_t)cid.cid_fileno);
   2289 			delay(5*hz);
   2290 #endif
   2291 			/* XXX this will loop forever, maybe put fs in */
   2292 			/*   ro mode */
   2293 			continue;
   2294 		}
   2295 
   2296 		mutex_enter(&cp->c_statelock);
   2297 
   2298 		mdp = &cp->c_metadata;
   2299 
   2300 		/* if a regular file that has not been pushed */
   2301 		if ((cp->c_attr.va_type == VREG) &&
   2302 		    (((mdp->md_flags & (MD_PUSHDONE | MD_PUTPAGE)) ==
   2303 		    MD_PUTPAGE))) {
   2304 			/* move the file to lost+found */
   2305 			error = cachefs_cnode_lostfound(cp, NULL);
   2306 			if (error) {
   2307 				/* XXX put fs in ro mode */
   2308 				/* XXX need to drain MF list */
   2309 				panic("lostfound failed %d", error);
   2310 			}
   2311 			mutex_exit(&cp->c_statelock);
   2312 			VN_RELE(CTOV(cp));
   2313 			continue;
   2314 		}
   2315 
   2316 		/* if a local file */
   2317 		if (cp->c_id.cid_flags & CFS_CID_LOCAL) {
   2318 			/* if the file was not created */
   2319 			if ((cp->c_metadata.md_flags & MD_CREATEDONE) == 0) {
   2320 				/* do not allow cnode to be used */
   2321 				cachefs_cnode_stale(cp);
   2322 				mutex_exit(&cp->c_statelock);
   2323 				VN_RELE(CTOV(cp));
   2324 				continue;
   2325 			}
   2326 
   2327 			/* save the local fileno for later getattrs */
   2328 			mdp->md_localfileno = cp->c_id.cid_fileno;
   2329 			mutex_exit(&cp->c_statelock);
   2330 
   2331 			/* register the mapping from old to new fileno */
   2332 			mutex_enter(&fscp->fs_fslock);
   2333 			cachefs_inum_register(fscp, cp->c_attr.va_nodeid,
   2334 			    mdp->md_localfileno);
   2335 			cachefs_inum_register(fscp, mdp->md_localfileno, 0);
   2336 			mutex_exit(&fscp->fs_fslock);
   2337 
   2338 			/* move to new location in the cache */
   2339 			cachefs_cnode_move(cp);
   2340 			mutex_enter(&cp->c_statelock);
   2341 		}
   2342 
   2343 		/* else if a modified file that needs to have its mode fixed */
   2344 		else if ((cp->c_metadata.md_flags & MD_FILE) &&
   2345 		    (cp->c_attr.va_type == VREG)) {
   2346 
   2347 			if (cp->c_frontvp == NULL)
   2348 				(void) cachefs_getfrontfile(cp);
   2349 			if (cp->c_frontvp) {
   2350 				/* mark file as no longer modified */
   2351 				va.va_mode = 0666;
   2352 				va.va_mask = AT_MODE;
   2353 				error = VOP_SETATTR(cp->c_frontvp, &va,
   2354 				    0, kcred, NULL);
   2355 				if (error) {
   2356 					cmn_err(CE_WARN,
   2357 					    "Cannot change ff mode.\n");
   2358 				}
   2359 			}
   2360 		}
   2361 
   2362 
   2363 		/* if there is a rl entry, put it on the correct list */
   2364 		if (mdp->md_rlno) {
   2365 			if (mdp->md_flags & MD_PACKED) {
   2366 				if ((mdp->md_flags & MD_POPULATED) ||
   2367 				    ((mdp->md_flags & MD_FILE) == 0))
   2368 					type = CACHEFS_RL_PACKED;
   2369 				else
   2370 					type = CACHEFS_RL_PACKED_PENDING;
   2371 				cachefs_rlent_moveto(fscp->fs_cache, type,
   2372 				    mdp->md_rlno, mdp->md_frontblks);
   2373 				mdp->md_rltype = type;
   2374 			} else if (mdp->md_flags & MD_FILE) {
   2375 				type = CACHEFS_RL_ACTIVE;
   2376 				cachefs_rlent_moveto(fscp->fs_cache, type,
   2377 				    mdp->md_rlno, mdp->md_frontblks);
   2378 				mdp->md_rltype = type;
   2379 			} else {
   2380 				type = CACHEFS_RL_FREE;
   2381 				cachefs_rlent_moveto(fscp->fs_cache, type,
   2382 				    mdp->md_rlno, 0);
   2383 				filegrp_ffrele(cp->c_filegrp);
   2384 				mdp->md_rlno = 0;
   2385 				mdp->md_rltype = CACHEFS_RL_NONE;
   2386 			}
   2387 		}
   2388 		mdp->md_flags &= ~(MD_CREATEDONE | MD_PUTPAGE |
   2389 		    MD_PUSHDONE | MD_MAPPING);
   2390 
   2391 		/* if a directory, populate it */
   2392 		if (CTOV(cp)->v_type == VDIR) {
   2393 			/* XXX hack for now */
   2394 			mdp->md_flags |= MD_INVALREADDIR;
   2395 			dnlc_purge_vp(CTOV(cp));
   2396 
   2397 			mdp->md_flags |= MD_NEEDATTRS;
   2398 		}
   2399 
   2400 		if (!timedout) {
   2401 			error = CFSOP_CHECK_COBJECT(fscp, cp, 0, kcred);
   2402 			if (CFS_TIMEOUT(fscp, error))
   2403 				timedout = 1;
   2404 			else if ((error == 0) &&
   2405 			    ((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0)) {
   2406 				if (cachefs_vtype_aclok(CTOV(cp)) &&
   2407 				    ((cp->c_flags & CN_NOCACHE) == 0))
   2408 					(void) cachefs_cacheacl(cp, NULL);
   2409 			}
   2410 		}
   2411 
   2412 		cp->c_flags |= CN_UPDATED;
   2413 		mutex_exit(&cp->c_statelock);
   2414 		VN_RELE(CTOV(cp));
   2415 	}
   2416 	mutex_exit(&cachep->c_mflock);
   2417 }
   2418 
   2419 void
   2420 cachefs_inum_register(fscache_t *fscp, ino64_t real, ino64_t fake)
   2421 {
   2422 	cachefs_inum_trans_t *tbl;
   2423 	int toff, thop;
   2424 	int i;
   2425 
   2426 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
   2427 
   2428 	/*
   2429 	 * first, see if an empty slot exists.
   2430 	 */
   2431 
   2432 	for (i = 0; i < fscp->fs_inum_size; i++)
   2433 		if (fscp->fs_inum_trans[i].cit_real == 0)
   2434 			break;
   2435 
   2436 	/*
   2437 	 * if there are no empty slots, try to grow the table.
   2438 	 */
   2439 
   2440 	if (i >= fscp->fs_inum_size) {
   2441 		cachefs_inum_trans_t *oldtbl;
   2442 		int oldsize, newsize = 0;
   2443 
   2444 		/*
   2445 		 * try to fetch a new table size that's bigger than
   2446 		 * our current size
   2447 		 */
   2448 
   2449 		for (i = 0; cachefs_hash_sizes[i] != 0; i++)
   2450 			if (cachefs_hash_sizes[i] > fscp->fs_inum_size) {
   2451 				newsize = cachefs_hash_sizes[i];
   2452 				break;
   2453 			}
   2454 
   2455 		/*
   2456 		 * if we're out of larger twin-primes, give up.  thus,
   2457 		 * the inode numbers in some directory entries might
   2458 		 * change at reconnect, and disagree with what stat()
   2459 		 * says.  this isn't worth panicing over, but it does
   2460 		 * merit a warning message.
   2461 		 */
   2462 		if (newsize == 0) {
   2463 			/* only print hash table warning once */
   2464 			if ((fscp->fs_flags & CFS_FS_HASHPRINT) == 0) {
   2465 				cmn_err(CE_WARN,
   2466 				    "cachefs: inode hash table full\n");
   2467 				fscp->fs_flags |= CFS_FS_HASHPRINT;
   2468 			}
   2469 			return;
   2470 		}
   2471 
   2472 		/* set up this fscp with a new hash table */
   2473 
   2474 		oldtbl = fscp->fs_inum_trans;
   2475 		oldsize = fscp->fs_inum_size;
   2476 		fscp->fs_inum_size = newsize;
   2477 		fscp->fs_inum_trans = (cachefs_inum_trans_t *)
   2478 		    cachefs_kmem_zalloc(sizeof (cachefs_inum_trans_t) * newsize,
   2479 			KM_SLEEP);
   2480 
   2481 		/*
   2482 		 * re-insert all of the old values.  this will never
   2483 		 * go more than one level into recursion-land.
   2484 		 */
   2485 
   2486 		for (i = 0; i < oldsize; i++) {
   2487 			tbl = oldtbl + i;
   2488 			if (tbl->cit_real != 0) {
   2489 				cachefs_inum_register(fscp, tbl->cit_real,
   2490 				    tbl->cit_fake);
   2491 			} else {
   2492 				ASSERT(0);
   2493 			}
   2494 		}
   2495 
   2496 		if (oldsize > 0)
   2497 			cachefs_kmem_free(oldtbl, oldsize *
   2498 			    sizeof (cachefs_inum_trans_t));
   2499 	}
   2500 
   2501 	/*
   2502 	 * compute values for the hash table.  see ken rosen's
   2503 	 * `elementary number theory and its applications' for one
   2504 	 * description of double hashing.
   2505 	 */
   2506 
   2507 	toff = (int)(real % fscp->fs_inum_size);
   2508 	thop = (int)(real % (fscp->fs_inum_size - 2)) + 1;
   2509 
   2510 	/*
   2511 	 * since we know the hash table isn't full when we get here,
   2512 	 * this loop shouldn't terminate except via the `break'.
   2513 	 */
   2514 
   2515 	for (i = 0; i < fscp->fs_inum_size; i++) {
   2516 		tbl = fscp->fs_inum_trans + toff;
   2517 		if ((tbl->cit_real == 0) || (tbl->cit_real == real)) {
   2518 			tbl->cit_real = real;
   2519 			tbl->cit_fake = fake;
   2520 			break;
   2521 		}
   2522 
   2523 		toff += thop;
   2524 		toff %= fscp->fs_inum_size;
   2525 	}
   2526 	ASSERT(i < fscp->fs_inum_size);
   2527 }
   2528 
   2529 /*
   2530  * given an inode number, map it to the inode number that should be
   2531  * put in a directory entry before its copied out.
   2532  *
   2533  * don't call this function unless there is a fscp->fs_inum_trans
   2534  * table that has real entries in it!
   2535  */
   2536 
   2537 ino64_t
   2538 cachefs_inum_real2fake(fscache_t *fscp, ino64_t real)
   2539 {
   2540 	cachefs_inum_trans_t *tbl;
   2541 	ino64_t rc = real;
   2542 	int toff, thop;
   2543 	int i;
   2544 
   2545 	ASSERT(fscp->fs_inum_size > 0);
   2546 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
   2547 
   2548 	toff = (int)(real % fscp->fs_inum_size);
   2549 	thop = (int)(real % (fscp->fs_inum_size - 2)) + 1;
   2550 
   2551 	for (i = 0; i < fscp->fs_inum_size; i++) {
   2552 		tbl = fscp->fs_inum_trans + toff;
   2553 
   2554 		if (tbl->cit_real == 0) {
   2555 			break;
   2556 		} else if (tbl->cit_real == real) {
   2557 			rc = tbl->cit_fake;
   2558 			break;
   2559 		}
   2560 
   2561 		toff += thop;
   2562 		toff %= fscp->fs_inum_size;
   2563 	}
   2564 
   2565 	return (rc);
   2566 }
   2567 
   2568 /*
   2569  * Passed a cid, finds the cnode and sets the MD_NEEDATTRS bit
   2570  * in the metadata.
   2571  */
   2572 static void
   2573 cachefs_iosetneedattrs(fscache_t *fscp, cfs_cid_t *cidp)
   2574 {
   2575 	int error;
   2576 	cnode_t *cp;
   2577 
   2578 	error = cachefs_cnode_make(cidp, fscp,
   2579 	    NULL, NULL, NULL, kcred, 0, &cp);
   2580 	if (error)
   2581 		return;
   2582 
   2583 	mutex_enter(&cp->c_statelock);
   2584 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
   2585 	cp->c_flags |= CN_UPDATED;
   2586 	mutex_exit(&cp->c_statelock);
   2587 
   2588 	VN_RELE(CTOV(cp));
   2589 }
   2590