xref: /onnv-gate/usr/src/uts/common/fs/cachefs/cachefs_ioctl.c (revision 5331:3047ad28a67b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*5331Samw  * Common Development and Distribution License (the "License").
6*5331Samw  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*5331Samw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <sys/param.h>
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/systm.h>
300Sstevel@tonic-gate #include <sys/cred.h>
310Sstevel@tonic-gate #include <sys/proc.h>
320Sstevel@tonic-gate #include <sys/user.h>
330Sstevel@tonic-gate #include <sys/time.h>
340Sstevel@tonic-gate #include <sys/vnode.h>
350Sstevel@tonic-gate #include <sys/vfs.h>
360Sstevel@tonic-gate #include <sys/file.h>
370Sstevel@tonic-gate #include <sys/filio.h>
380Sstevel@tonic-gate #include <sys/uio.h>
390Sstevel@tonic-gate #include <sys/buf.h>
400Sstevel@tonic-gate #include <sys/mman.h>
410Sstevel@tonic-gate #include <sys/tiuser.h>
420Sstevel@tonic-gate #include <sys/pathname.h>
430Sstevel@tonic-gate #include <sys/dirent.h>
440Sstevel@tonic-gate #include <sys/conf.h>
450Sstevel@tonic-gate #include <sys/debug.h>
460Sstevel@tonic-gate #include <sys/vmsystm.h>
470Sstevel@tonic-gate #include <sys/fcntl.h>
480Sstevel@tonic-gate #include <sys/flock.h>
490Sstevel@tonic-gate #include <sys/fbuf.h>
500Sstevel@tonic-gate #include <sys/swap.h>
510Sstevel@tonic-gate #include <sys/errno.h>
520Sstevel@tonic-gate #include <sys/sysmacros.h>
530Sstevel@tonic-gate #include <sys/disp.h>
540Sstevel@tonic-gate #include <sys/kmem.h>
550Sstevel@tonic-gate #include <sys/cmn_err.h>
560Sstevel@tonic-gate #include <sys/vtrace.h>
570Sstevel@tonic-gate #include <sys/mount.h>
580Sstevel@tonic-gate #include <sys/dnlc.h>
590Sstevel@tonic-gate #include <sys/stat.h>
600Sstevel@tonic-gate #include <rpc/types.h>
610Sstevel@tonic-gate 
620Sstevel@tonic-gate #include <vm/hat.h>
630Sstevel@tonic-gate #include <vm/as.h>
640Sstevel@tonic-gate #include <vm/page.h>
650Sstevel@tonic-gate #include <vm/pvn.h>
660Sstevel@tonic-gate #include <vm/seg.h>
670Sstevel@tonic-gate #include <vm/seg_map.h>
680Sstevel@tonic-gate #include <vm/seg_vn.h>
690Sstevel@tonic-gate #include <vm/rm.h>
700Sstevel@tonic-gate #include <sys/fs/cachefs_fs.h>
710Sstevel@tonic-gate #include <sys/fs/cachefs_dlog.h>
720Sstevel@tonic-gate #include <sys/fs/cachefs_ioctl.h>
730Sstevel@tonic-gate #include <sys/fs/cachefs_dir.h>
740Sstevel@tonic-gate #include <sys/fs/cachefs_dlog.h>
750Sstevel@tonic-gate #include "fs/fs_subr.h"
760Sstevel@tonic-gate 
770Sstevel@tonic-gate void cachefs_addhash(struct cnode *);
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate  * Local functions
820Sstevel@tonic-gate  */
830Sstevel@tonic-gate static void sync_metadata(cnode_t *);
840Sstevel@tonic-gate static void drop_backvp(cnode_t *);
850Sstevel@tonic-gate static void allow_pendrm(cnode_t *cp);
860Sstevel@tonic-gate static int cachefs_unpack_common(vnode_t *vp);
870Sstevel@tonic-gate static int cachefs_unpackall_list(cachefscache_t *cachep,
880Sstevel@tonic-gate     enum cachefs_rl_type type);
890Sstevel@tonic-gate static void cachefs_modified_fix(fscache_t *fscp);
900Sstevel@tonic-gate static void cachefs_iosetneedattrs(fscache_t *fscp, cfs_cid_t *cidp);
910Sstevel@tonic-gate 
920Sstevel@tonic-gate #if (defined(_SYSCALL32_IMPL) || defined(_LP64))
930Sstevel@tonic-gate 
940Sstevel@tonic-gate #define	CACHEFS_DECL(type, handle)					\
950Sstevel@tonic-gate 	type	handle
960Sstevel@tonic-gate 
970Sstevel@tonic-gate #define	CACHEFS_TMPPTR_SET(in_addr, tmp_addr, tmp_ptr, type)		\
980Sstevel@tonic-gate 	tmp_ptr = (type *)(tmp_addr)
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate #define	CACHEFS_FID_COPYOUT(in_fidp, out_fidp)				\
1010Sstevel@tonic-gate 	CACHEFS_FID_COPY((fid_t *)(in_fidp), (cfs_fid_t *)(out_fidp))
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate #define	CACHEFS_FID_COPYIN(in_fidp, out_fidp)				\
1040Sstevel@tonic-gate 	CACHEFS_FID_COPY((cfs_fid_t *)(in_fidp), (fid_t *)(out_fidp))
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate #define	CACHEFS_VATTR_COPYOUT(in_vattrp, out_vattrp, error)		\
1070Sstevel@tonic-gate 	if (!error) {							\
1080Sstevel@tonic-gate 		CACHEFS_VATTR_TO_CFS_VATTR_COPY((vattr_t *)(in_vattrp),	\
1090Sstevel@tonic-gate 			(cfs_vattr_t *)(out_vattrp), error);		\
1100Sstevel@tonic-gate 	}
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate #define	CACHEFS_VATTR_COPYIN(in_vattrp, out_vattrp)			\
1130Sstevel@tonic-gate 	CACHEFS_CFS_VATTR_TO_VATTR_COPY((cfs_vattr_t *)(in_vattrp),	\
1140Sstevel@tonic-gate 			(vattr_t *)(out_vattrp))
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate #else /* not _SYSCALL32_IMPL || _LP64 */
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate #define	CACHEFS_DECL(type, handle)
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate #define	CACHEFS_TMPPTR_SET(in_addr, tmp_addr, tmp_ptr, type)		\
1210Sstevel@tonic-gate 	tmp_ptr = (type *)(in_addr)
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate #define	CACHEFS_FID_COPYOUT(in_fidp, out_fidp)
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate #define	CACHEFS_FID_COPYIN(in_fidp, out_fidp)
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate #define	CACHEFS_VATTR_COPYOUT(in_vattrp, out_vattrp, error)
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate #define	CACHEFS_VATTR_COPYIN(in_vattrp, out_vattrp)
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL || _LP64 */
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate /*
1340Sstevel@tonic-gate  * Conjure up a credential from the partial credential stored in
1350Sstevel@tonic-gate  * a file.  This is bogus and cachefs should really be fixed, but
1360Sstevel@tonic-gate  * this maintains maximum compatibility.
1370Sstevel@tonic-gate  * dl_cred *cr points to a basic credential followed directly by a buffer that
1380Sstevel@tonic-gate  * takes a number of groups.
1390Sstevel@tonic-gate  */
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate static cred_t *
conj_cred(dl_cred_t * cr)1420Sstevel@tonic-gate conj_cred(dl_cred_t *cr)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate 	cred_t *newcr = crget();
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	(void) crsetresuid(newcr, cr->cr_ruid, cr->cr_uid, cr->cr_suid);
1470Sstevel@tonic-gate 	(void) crsetresgid(newcr, cr->cr_rgid, cr->cr_gid, cr->cr_sgid);
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	(void) crsetgroups(newcr, MIN(NGROUPS_MAX_DEFAULT, cr->cr_ngroups),
1500Sstevel@tonic-gate 		cr->cr_groups);
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	return (newcr);
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate /*
1550Sstevel@tonic-gate  * Pack a file in the cache
1560Sstevel@tonic-gate  *	dvp is the directory the file resides in.
1570Sstevel@tonic-gate  *	name is the name of the file.
1580Sstevel@tonic-gate  *	Returns 0 or an error if could not perform the operation.
1590Sstevel@tonic-gate  */
1600Sstevel@tonic-gate int
cachefs_pack(struct vnode * dvp,char * name,cred_t * cr)1610Sstevel@tonic-gate cachefs_pack(struct vnode *dvp, char *name, cred_t *cr)
1620Sstevel@tonic-gate {
1630Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp));
1640Sstevel@tonic-gate 	int error = 0;
1650Sstevel@tonic-gate 	int connected = 0;
1660Sstevel@tonic-gate 	vnode_t *vp;
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	/*
1690Sstevel@tonic-gate 	 * Return if NFSv4 is the backfs (no caching).
1700Sstevel@tonic-gate 	 */
1710Sstevel@tonic-gate 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
1720Sstevel@tonic-gate 		goto out;
1730Sstevel@tonic-gate 	}
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	for (;;) {
1760Sstevel@tonic-gate 		/* get access to the file system */
1770Sstevel@tonic-gate 		error = cachefs_cd_access(fscp, connected, 0);
1780Sstevel@tonic-gate 		if (error)
1790Sstevel@tonic-gate 			break;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 		/* lookup the file name */
1820Sstevel@tonic-gate 		error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL,
1830Sstevel@tonic-gate 		    cr);
1840Sstevel@tonic-gate 		if (error == 0) {
1850Sstevel@tonic-gate 			error = cachefs_pack_common(vp, cr);
1860Sstevel@tonic-gate 			VN_RELE(vp);
1870Sstevel@tonic-gate 		}
1880Sstevel@tonic-gate 		if (CFS_TIMEOUT(fscp, error)) {
1890Sstevel@tonic-gate 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
1900Sstevel@tonic-gate 				cachefs_cd_release(fscp);
1910Sstevel@tonic-gate 				cachefs_cd_timedout(fscp);
1920Sstevel@tonic-gate 				connected = 0;
1930Sstevel@tonic-gate 				continue;
1940Sstevel@tonic-gate 			} else {
1950Sstevel@tonic-gate 				cachefs_cd_release(fscp);
1960Sstevel@tonic-gate 				connected = 1;
1970Sstevel@tonic-gate 				continue;
1980Sstevel@tonic-gate 			}
1990Sstevel@tonic-gate 		}
2000Sstevel@tonic-gate 		cachefs_cd_release(fscp);
2010Sstevel@tonic-gate 		break;
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate out:
2050Sstevel@tonic-gate 	return (error);
2060Sstevel@tonic-gate }
2070Sstevel@tonic-gate /*
2080Sstevel@tonic-gate  * Packs the file belonging to the passed in vnode.
2090Sstevel@tonic-gate  */
2100Sstevel@tonic-gate int
cachefs_pack_common(vnode_t * vp,cred_t * cr)2110Sstevel@tonic-gate cachefs_pack_common(vnode_t *vp, cred_t *cr)
2120Sstevel@tonic-gate {
2130Sstevel@tonic-gate 	cnode_t *cp = VTOC(vp);
2140Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
2150Sstevel@tonic-gate 	int error = 0;
2160Sstevel@tonic-gate 	offset_t off;
2170Sstevel@tonic-gate 	caddr_t buf;
2180Sstevel@tonic-gate 	int buflen;
2190Sstevel@tonic-gate 	rl_entry_t rl_ent;
2200Sstevel@tonic-gate 	u_offset_t cnode_size;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	rw_enter(&cp->c_rwlock, RW_WRITER);
2230Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	/* done if cannot write to cache */
2260Sstevel@tonic-gate 	if ((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0) {
2270Sstevel@tonic-gate 		error = EROFS;
2280Sstevel@tonic-gate 		goto out;
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	/* done if not usable */
2320Sstevel@tonic-gate 	if (cp->c_flags & (CN_STALE | CN_DESTROY)) {
2330Sstevel@tonic-gate 		error = ESTALE;
2340Sstevel@tonic-gate 		goto out;
2350Sstevel@tonic-gate 	}
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	/* make sure up to date */
2380Sstevel@tonic-gate 	error = CFSOP_CHECK_COBJECT(fscp, cp, C_BACK_CHECK, cr);
2390Sstevel@tonic-gate 	if (error)
2400Sstevel@tonic-gate 		goto out;
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	/* make it cachable */
2430Sstevel@tonic-gate 	cp->c_flags &= ~CN_NOCACHE;
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	/* get a metadata slot if we do not have one yet */
2460Sstevel@tonic-gate 	if (cp->c_flags & CN_ALLOC_PENDING) {
2470Sstevel@tonic-gate 		if (cp->c_filegrp->fg_flags & CFS_FG_ALLOC_ATTR) {
2480Sstevel@tonic-gate 			(void) filegrp_allocattr(cp->c_filegrp);
2490Sstevel@tonic-gate 		}
2500Sstevel@tonic-gate 		error = filegrp_create_metadata(cp->c_filegrp,
2510Sstevel@tonic-gate 		    &cp->c_metadata, &cp->c_id);
2520Sstevel@tonic-gate 		if (error)
2530Sstevel@tonic-gate 			goto out;
2540Sstevel@tonic-gate 		cp->c_flags &= ~CN_ALLOC_PENDING;
2550Sstevel@tonic-gate 		cp->c_flags |= CN_UPDATED;
2560Sstevel@tonic-gate 	}
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	/* cache the ACL if necessary */
2590Sstevel@tonic-gate 	if (((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0) &&
2600Sstevel@tonic-gate 	    (cachefs_vtype_aclok(vp)) &&
2610Sstevel@tonic-gate 	    ((cp->c_metadata.md_flags & MD_ACL) == 0)) {
2620Sstevel@tonic-gate 		error = cachefs_cacheacl(cp, NULL);
2630Sstevel@tonic-gate 		if (error != 0)
2640Sstevel@tonic-gate 			goto out;
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	/* directory */
2680Sstevel@tonic-gate 	if (vp->v_type == VDIR) {
2690Sstevel@tonic-gate 		if (cp->c_metadata.md_flags & MD_POPULATED)
2700Sstevel@tonic-gate 			goto out;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 		if (error = cachefs_dir_fill(cp, cr))
2730Sstevel@tonic-gate 			goto out;
2740Sstevel@tonic-gate 	}
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	/* regular file */
2770Sstevel@tonic-gate 	else if (vp->v_type == VREG) {
2780Sstevel@tonic-gate 		if (cp->c_metadata.md_flags & MD_POPULATED)
2790Sstevel@tonic-gate 			goto out;
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 		if (cp->c_backvp == NULL) {
2820Sstevel@tonic-gate 			error = cachefs_getbackvp(fscp, cp);
2830Sstevel@tonic-gate 			if (error)
2840Sstevel@tonic-gate 				goto out;
2850Sstevel@tonic-gate 		}
2860Sstevel@tonic-gate 		if (cp->c_frontvp == NULL) {
2870Sstevel@tonic-gate 			error = cachefs_getfrontfile(cp);
2880Sstevel@tonic-gate 			if (error)
2890Sstevel@tonic-gate 				goto out;
2900Sstevel@tonic-gate 		}
2910Sstevel@tonic-gate 		/* populate the file */
2920Sstevel@tonic-gate 		off = (offset_t)0;
2930Sstevel@tonic-gate 		cnode_size = cp->c_attr.va_size;
2940Sstevel@tonic-gate 		while (off < cnode_size) {
2950Sstevel@tonic-gate 			if (!cachefs_check_allocmap(cp, off)) {
2960Sstevel@tonic-gate 				u_offset_t popoff;
2970Sstevel@tonic-gate 				size_t popsize;
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 				cachefs_cluster_allocmap(off, &popoff,
3000Sstevel@tonic-gate 				    &popsize, (size_t)DEF_POP_SIZE, cp);
3010Sstevel@tonic-gate 				if (popsize != 0) {
3020Sstevel@tonic-gate 					error = cachefs_populate(cp, popoff,
3030Sstevel@tonic-gate 					    popsize, cp->c_frontvp,
3040Sstevel@tonic-gate 					    cp->c_backvp, cp->c_size, cr);
3050Sstevel@tonic-gate 					if (error)
3060Sstevel@tonic-gate 						goto out;
3070Sstevel@tonic-gate 					else
3080Sstevel@tonic-gate 						cp->c_flags |= (CN_UPDATED |
3090Sstevel@tonic-gate 						    CN_NEED_FRONT_SYNC |
3100Sstevel@tonic-gate 						    CN_POPULATION_PENDING);
3110Sstevel@tonic-gate 					popsize = popsize - (off - popoff);
3120Sstevel@tonic-gate 				}
3130Sstevel@tonic-gate 			}
3140Sstevel@tonic-gate 			off += PAGESIZE;
3150Sstevel@tonic-gate 		}
3160Sstevel@tonic-gate 	}
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	/* symbolic link */
3190Sstevel@tonic-gate 	else if (vp->v_type == VLNK) {
3200Sstevel@tonic-gate 		if (cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK))
3210Sstevel@tonic-gate 			goto out;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 		/* get the sym link contents from the back fs */
3240Sstevel@tonic-gate 		error = cachefs_readlink_back(cp, cr, &buf, &buflen);
3250Sstevel@tonic-gate 		if (error)
3260Sstevel@tonic-gate 			goto out;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 		/* try to cache the sym link */
3290Sstevel@tonic-gate 		error = cachefs_stuffsymlink(cp, buf, buflen);
3300Sstevel@tonic-gate 		cachefs_kmem_free(buf, MAXPATHLEN);
3310Sstevel@tonic-gate 	}
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	/* assume that all other types fit in the attributes */
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate out:
3360Sstevel@tonic-gate 	/* get the rl slot if needed */
3370Sstevel@tonic-gate 	if ((error == 0) && (cp->c_metadata.md_rlno == 0)) {
3380Sstevel@tonic-gate 		rl_ent.rl_fileno = cp->c_id.cid_fileno;
3390Sstevel@tonic-gate 		rl_ent.rl_local = (cp->c_id.cid_flags & CFS_CID_LOCAL) ? 1 : 0;
3400Sstevel@tonic-gate 		rl_ent.rl_fsid = fscp->fs_cfsid;
3410Sstevel@tonic-gate 		rl_ent.rl_attrc = 0;
3420Sstevel@tonic-gate 		cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
3430Sstevel@tonic-gate 		error = cachefs_rl_alloc(fscp->fs_cache, &rl_ent,
3440Sstevel@tonic-gate 		    &cp->c_metadata.md_rlno);
3450Sstevel@tonic-gate 		if (error == 0)
3460Sstevel@tonic-gate 			error = filegrp_ffhold(cp->c_filegrp);
3470Sstevel@tonic-gate 	}
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	/* mark the file as packed */
3500Sstevel@tonic-gate 	if (error == 0) {
3510Sstevel@tonic-gate 		/* modified takes precedence over packed */
3520Sstevel@tonic-gate 		if (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) {
3530Sstevel@tonic-gate 			cachefs_rlent_moveto(fscp->fs_cache,
3540Sstevel@tonic-gate 			    CACHEFS_RL_PACKED, cp->c_metadata.md_rlno,
3550Sstevel@tonic-gate 			    cp->c_metadata.md_frontblks);
3560Sstevel@tonic-gate 			cp->c_metadata.md_rltype = CACHEFS_RL_PACKED;
3570Sstevel@tonic-gate 		}
3580Sstevel@tonic-gate 		cp->c_metadata.md_flags |= MD_PACKED;
3590Sstevel@tonic-gate 		cp->c_flags |= CN_UPDATED;
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
3630Sstevel@tonic-gate 	rw_exit(&cp->c_rwlock);
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	return (error);
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate /*
3690Sstevel@tonic-gate  * Unpack a file from the cache
3700Sstevel@tonic-gate  *	dvp is the directory the file resides in.
3710Sstevel@tonic-gate  *	name is the name of the file.
3720Sstevel@tonic-gate  *	Returns 0 or an error if could not perform the operation.
3730Sstevel@tonic-gate  */
3740Sstevel@tonic-gate int
cachefs_unpack(struct vnode * dvp,char * name,cred_t * cr)3750Sstevel@tonic-gate cachefs_unpack(struct vnode *dvp, char *name, cred_t *cr)
3760Sstevel@tonic-gate {
3770Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp));
3780Sstevel@tonic-gate 	int error = 0;
3790Sstevel@tonic-gate 	int connected = 0;
3800Sstevel@tonic-gate 	vnode_t *vp;
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	/* Return error if NFSv4 is the backfs (no caching) */
3830Sstevel@tonic-gate 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
3840Sstevel@tonic-gate 		goto out;
3850Sstevel@tonic-gate 	}
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	for (;;) {
3880Sstevel@tonic-gate 		/* get access to the file system */
3890Sstevel@tonic-gate 		error = cachefs_cd_access(fscp, connected, 0);
3900Sstevel@tonic-gate 		if (error)
3910Sstevel@tonic-gate 			break;
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 		/* lookup the file name */
3940Sstevel@tonic-gate 		error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL,
3950Sstevel@tonic-gate 		    cr);
3960Sstevel@tonic-gate 		if (error == 0) {
3970Sstevel@tonic-gate 			error = cachefs_unpack_common(vp);
3980Sstevel@tonic-gate 			VN_RELE(vp);
3990Sstevel@tonic-gate 		}
4000Sstevel@tonic-gate 		if (CFS_TIMEOUT(fscp, error)) {
4010Sstevel@tonic-gate 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
4020Sstevel@tonic-gate 				cachefs_cd_release(fscp);
4030Sstevel@tonic-gate 				cachefs_cd_timedout(fscp);
4040Sstevel@tonic-gate 				connected = 0;
4050Sstevel@tonic-gate 				continue;
4060Sstevel@tonic-gate 			} else {
4070Sstevel@tonic-gate 				cachefs_cd_release(fscp);
4080Sstevel@tonic-gate 				connected = 1;
4090Sstevel@tonic-gate 				continue;
4100Sstevel@tonic-gate 			}
4110Sstevel@tonic-gate 		}
4120Sstevel@tonic-gate 		cachefs_cd_release(fscp);
4130Sstevel@tonic-gate 		break;
4140Sstevel@tonic-gate 	}
4150Sstevel@tonic-gate out:
4160Sstevel@tonic-gate 	return (error);
4170Sstevel@tonic-gate }
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate /*
4200Sstevel@tonic-gate  * Unpacks the file belonging to the passed in vnode.
4210Sstevel@tonic-gate  */
4220Sstevel@tonic-gate static int
cachefs_unpack_common(vnode_t * vp)4230Sstevel@tonic-gate cachefs_unpack_common(vnode_t *vp)
4240Sstevel@tonic-gate {
4250Sstevel@tonic-gate 	cnode_t *cp = VTOC(vp);
4260Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(cp);
4270Sstevel@tonic-gate 	int error = 0;
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	/* nothing to do if not packed */
4320Sstevel@tonic-gate 	if ((cp->c_metadata.md_flags & MD_PACKED) == 0)
4330Sstevel@tonic-gate 		goto out;
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	/* nothing to do if cannot modify cache */
4360Sstevel@tonic-gate 	if ((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0) {
4370Sstevel@tonic-gate 		error = EROFS;
4380Sstevel@tonic-gate 		goto out;
4390Sstevel@tonic-gate 	}
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	/* mark file as no longer packed */
4420Sstevel@tonic-gate 	ASSERT(cp->c_metadata.md_rlno);
4430Sstevel@tonic-gate 	cp->c_metadata.md_flags &= ~MD_PACKED;
4440Sstevel@tonic-gate 	cp->c_flags |= CN_UPDATED;
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	/* done if file has been modified */
4470Sstevel@tonic-gate 	if (cp->c_metadata.md_rltype == CACHEFS_RL_MODIFIED)
4480Sstevel@tonic-gate 		goto out;
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	/* if there is no front file */
4510Sstevel@tonic-gate 	if ((cp->c_metadata.md_flags & MD_FILE) == 0) {
4520Sstevel@tonic-gate 		/* nuke front file resources */
4530Sstevel@tonic-gate 		filegrp_ffrele(cp->c_filegrp);
4540Sstevel@tonic-gate 		cachefs_rlent_moveto(fscp->fs_cache,
4550Sstevel@tonic-gate 		    CACHEFS_RL_FREE, cp->c_metadata.md_rlno, 0);
4560Sstevel@tonic-gate 		cp->c_metadata.md_rlno = 0;
4570Sstevel@tonic-gate 		cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
4580Sstevel@tonic-gate 	}
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	/* else move the front file to the active list */
4610Sstevel@tonic-gate 	else {
4620Sstevel@tonic-gate 		cachefs_rlent_moveto(fscp->fs_cache,
4630Sstevel@tonic-gate 		    CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno,
4640Sstevel@tonic-gate 		    cp->c_metadata.md_frontblks);
4650Sstevel@tonic-gate 		cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE;
4660Sstevel@tonic-gate 	}
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate out:
4690Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
4700Sstevel@tonic-gate 	return (error);
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate /*
4740Sstevel@tonic-gate  * Returns packing information on a file.
4750Sstevel@tonic-gate  *	dvp is the directory the file resides in.
4760Sstevel@tonic-gate  *	name is the name of the file.
4770Sstevel@tonic-gate  *	*statusp is set to the status of the file
4780Sstevel@tonic-gate  *	Returns 0 or an error if could not perform the operation.
4790Sstevel@tonic-gate  */
4800Sstevel@tonic-gate int
cachefs_packinfo(struct vnode * dvp,char * name,int * statusp,cred_t * cr)4810Sstevel@tonic-gate cachefs_packinfo(struct vnode *dvp, char *name, int *statusp, cred_t *cr)
4820Sstevel@tonic-gate {
4830Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp));
4840Sstevel@tonic-gate 	struct vnode *vp;
4850Sstevel@tonic-gate 	struct cnode *cp;
4860Sstevel@tonic-gate 	int error;
4870Sstevel@tonic-gate 	int connected = 0;
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	*statusp = 0;
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	/*
4920Sstevel@tonic-gate 	 * Return if NFSv4 is the backfs (no caching).
4930Sstevel@tonic-gate 	 */
4940Sstevel@tonic-gate 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
4950Sstevel@tonic-gate 		goto out;
4960Sstevel@tonic-gate 	}
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	for (;;) {
4990Sstevel@tonic-gate 		/* get access to the file system */
5000Sstevel@tonic-gate 		error = cachefs_cd_access(fscp, connected, 0);
5010Sstevel@tonic-gate 		if (error)
5020Sstevel@tonic-gate 			break;
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 		/* lookup the file name */
5050Sstevel@tonic-gate 		error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL,
5060Sstevel@tonic-gate 		    cr);
5070Sstevel@tonic-gate 		if (CFS_TIMEOUT(fscp, error)) {
5080Sstevel@tonic-gate 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
5090Sstevel@tonic-gate 				cachefs_cd_release(fscp);
5100Sstevel@tonic-gate 				cachefs_cd_timedout(fscp);
5110Sstevel@tonic-gate 				connected = 0;
5120Sstevel@tonic-gate 				continue;
5130Sstevel@tonic-gate 			} else {
5140Sstevel@tonic-gate 				cachefs_cd_release(fscp);
5150Sstevel@tonic-gate 				connected = 1;
5160Sstevel@tonic-gate 				continue;
5170Sstevel@tonic-gate 			}
5180Sstevel@tonic-gate 		}
5190Sstevel@tonic-gate 		if (error)
5200Sstevel@tonic-gate 			break;
5210Sstevel@tonic-gate 		cp = VTOC(vp);
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 		mutex_enter(&cp->c_statelock);
5240Sstevel@tonic-gate 		if (cp->c_metadata.md_flags & MD_PACKED)
5250Sstevel@tonic-gate 			*statusp |= CACHEFS_PACKED_FILE;
5260Sstevel@tonic-gate 		if (cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK))
5270Sstevel@tonic-gate 			*statusp |= CACHEFS_PACKED_DATA;
5280Sstevel@tonic-gate 		else if ((vp->v_type != VREG) &&
5290Sstevel@tonic-gate 		    (vp->v_type != VDIR) &&
5300Sstevel@tonic-gate 		    (vp->v_type != VLNK))
5310Sstevel@tonic-gate 			*statusp |= CACHEFS_PACKED_DATA;
5320Sstevel@tonic-gate 		else if (cp->c_size == 0)
5330Sstevel@tonic-gate 			*statusp |= CACHEFS_PACKED_DATA;
5340Sstevel@tonic-gate 		if (cp->c_flags & CN_NOCACHE)
5350Sstevel@tonic-gate 			*statusp |= CACHEFS_PACKED_NOCACHE;
5360Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 		VN_RELE(vp);
5390Sstevel@tonic-gate 		cachefs_cd_release(fscp);
5400Sstevel@tonic-gate 		break;
5410Sstevel@tonic-gate 	}
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate out:
5440Sstevel@tonic-gate 	return (error);
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate /*
5480Sstevel@tonic-gate  * Finds all packed files in the cache and unpacks them.
5490Sstevel@tonic-gate  */
5500Sstevel@tonic-gate int
cachefs_unpackall(vnode_t * vp)5510Sstevel@tonic-gate cachefs_unpackall(vnode_t *vp)
5520Sstevel@tonic-gate {
5530Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
5540Sstevel@tonic-gate 	cachefscache_t *cachep = fscp->fs_cache;
5550Sstevel@tonic-gate 	int error;
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	/*
5580Sstevel@tonic-gate 	 * Return if NFSv4 is the backfs (no caching).
5590Sstevel@tonic-gate 	 */
5600Sstevel@tonic-gate 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
5610Sstevel@tonic-gate 		goto out;
5620Sstevel@tonic-gate 	}
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	error = cachefs_unpackall_list(cachep, CACHEFS_RL_PACKED);
5650Sstevel@tonic-gate 	if (error)
5660Sstevel@tonic-gate 		goto out;
5670Sstevel@tonic-gate 	error = cachefs_unpackall_list(cachep, CACHEFS_RL_PACKED_PENDING);
5680Sstevel@tonic-gate out:
5690Sstevel@tonic-gate 	return (error);
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate /*
5730Sstevel@tonic-gate  * Finds all packed files on the specified list and unpacks them.
5740Sstevel@tonic-gate  */
5750Sstevel@tonic-gate static int
cachefs_unpackall_list(cachefscache_t * cachep,enum cachefs_rl_type type)5760Sstevel@tonic-gate cachefs_unpackall_list(cachefscache_t *cachep, enum cachefs_rl_type type)
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate 	fscache_t *fscp = NULL;
5790Sstevel@tonic-gate 	cnode_t *cp;
5800Sstevel@tonic-gate 	int error = 0;
5810Sstevel@tonic-gate 	rl_entry_t rl_ent;
5820Sstevel@tonic-gate 	cfs_cid_t cid;
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	rl_ent.rl_current = type;
5850Sstevel@tonic-gate 	for (;;) {
5860Sstevel@tonic-gate 		/* get the next entry on the specified resource list */
5870Sstevel@tonic-gate 		error = cachefs_rlent_data(cachep, &rl_ent, NULL);
5880Sstevel@tonic-gate 		if (error) {
5890Sstevel@tonic-gate 			error = 0;
5900Sstevel@tonic-gate 			break;
5910Sstevel@tonic-gate 		}
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 		/* if the fscp we have does not match */
5940Sstevel@tonic-gate 		if ((fscp == NULL) || (fscp->fs_cfsid != rl_ent.rl_fsid)) {
5950Sstevel@tonic-gate 			if (fscp) {
5960Sstevel@tonic-gate 				cachefs_cd_release(fscp);
5970Sstevel@tonic-gate 				fscache_rele(fscp);
5980Sstevel@tonic-gate 				fscp = NULL;
5990Sstevel@tonic-gate 			}
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 			/* get the file system cache object for this fsid */
6020Sstevel@tonic-gate 			mutex_enter(&cachep->c_fslistlock);
6030Sstevel@tonic-gate 			fscp = fscache_list_find(cachep, rl_ent.rl_fsid);
6040Sstevel@tonic-gate 			if (fscp == NULL) {
6050Sstevel@tonic-gate 				fscp = fscache_create(cachep);
6060Sstevel@tonic-gate 				error = fscache_activate(fscp, rl_ent.rl_fsid,
6070Sstevel@tonic-gate 				    NULL, NULL, 0);
6080Sstevel@tonic-gate 				if (error) {
6090Sstevel@tonic-gate 					cmn_err(CE_WARN,
6100Sstevel@tonic-gate 					    "cachefs: cache error, run fsck\n");
6110Sstevel@tonic-gate 					fscache_destroy(fscp);
6120Sstevel@tonic-gate 					fscp = NULL;
6130Sstevel@tonic-gate 					mutex_exit(&cachep->c_fslistlock);
6140Sstevel@tonic-gate 					break;
6150Sstevel@tonic-gate 				}
6160Sstevel@tonic-gate 				fscache_list_add(cachep, fscp);
6170Sstevel@tonic-gate 			}
6180Sstevel@tonic-gate 			fscache_hold(fscp);
6190Sstevel@tonic-gate 			mutex_exit(&cachep->c_fslistlock);
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 			/* get access to the file system */
6220Sstevel@tonic-gate 			error = cachefs_cd_access(fscp, 0, 0);
6230Sstevel@tonic-gate 			if (error) {
6240Sstevel@tonic-gate 				fscache_rele(fscp);
6250Sstevel@tonic-gate 				fscp = NULL;
6260Sstevel@tonic-gate 				break;
6270Sstevel@tonic-gate 			}
6280Sstevel@tonic-gate 		}
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 		/* get the cnode for the file */
6310Sstevel@tonic-gate 		cid.cid_fileno = rl_ent.rl_fileno;
6320Sstevel@tonic-gate 		cid.cid_flags = rl_ent.rl_local ? CFS_CID_LOCAL : 0;
6330Sstevel@tonic-gate 		error = cachefs_cnode_make(&cid, fscp,
6340Sstevel@tonic-gate 		    NULL, NULL, NULL, kcred, 0, &cp);
6350Sstevel@tonic-gate 		if (error) {
6360Sstevel@tonic-gate #ifdef CFSDEBUG
6370Sstevel@tonic-gate 			CFS_DEBUG(CFSDEBUG_IOCTL)
6380Sstevel@tonic-gate 				printf("cachefs: cul: could not find %llu\n",
6390Sstevel@tonic-gate 				    (u_longlong_t)cid.cid_fileno);
6400Sstevel@tonic-gate 			delay(5*hz);
6410Sstevel@tonic-gate #endif
6420Sstevel@tonic-gate 			continue;
6430Sstevel@tonic-gate 		}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 		/* unpack the file */
6460Sstevel@tonic-gate 		(void) cachefs_unpack_common(CTOV(cp));
6470Sstevel@tonic-gate 		VN_RELE(CTOV(cp));
6480Sstevel@tonic-gate 	}
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	/* free up allocated resources */
6510Sstevel@tonic-gate 	if (fscp) {
6520Sstevel@tonic-gate 		cachefs_cd_release(fscp);
6530Sstevel@tonic-gate 		fscache_rele(fscp);
6540Sstevel@tonic-gate 	}
6550Sstevel@tonic-gate 	return (error);
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate /*
6590Sstevel@tonic-gate  * Identifies this process as the cachefsd.
6600Sstevel@tonic-gate  * Stays this way until close is done.
6610Sstevel@tonic-gate  */
6620Sstevel@tonic-gate int
6630Sstevel@tonic-gate /*ARGSUSED*/
cachefs_io_daemonid(vnode_t * vp,void * dinp,void * doutp)6640Sstevel@tonic-gate cachefs_io_daemonid(vnode_t *vp, void *dinp, void *doutp)
6650Sstevel@tonic-gate {
6660Sstevel@tonic-gate 	int error = 0;
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
6690Sstevel@tonic-gate 	cachefscache_t *cachep = fscp->fs_cache;
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	mutex_enter(&fscp->fs_cdlock);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	/* can only do this on the root of the file system */
6740Sstevel@tonic-gate 	if (vp != fscp->fs_rootvp)
6750Sstevel@tonic-gate 		error = ENOENT;
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	/* else if there already is a daemon running */
6780Sstevel@tonic-gate 	else if (fscp->fs_cddaemonid)
6790Sstevel@tonic-gate 		error = EBUSY;
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	/* else use the pid to identify the daemon */
6820Sstevel@tonic-gate 	else {
6830Sstevel@tonic-gate 		fscp->fs_cddaemonid = ttoproc(curthread)->p_pid;
6840Sstevel@tonic-gate 		cv_broadcast(&fscp->fs_cdwaitcv);
6850Sstevel@tonic-gate 	}
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	mutex_exit(&fscp->fs_cdlock);
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	if (error == 0) {
6900Sstevel@tonic-gate 		/* the daemon that takes care of root is special */
6910Sstevel@tonic-gate 		if (fscp->fs_flags & CFS_FS_ROOTFS) {
6920Sstevel@tonic-gate 			mutex_enter(&cachep->c_contentslock);
6930Sstevel@tonic-gate 			ASSERT(cachep->c_rootdaemonid == 0);
6940Sstevel@tonic-gate 			cachep->c_rootdaemonid = fscp->fs_cddaemonid;
6950Sstevel@tonic-gate 			mutex_exit(&cachep->c_contentslock);
6960Sstevel@tonic-gate 		}
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 	return (error);
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate /*
7020Sstevel@tonic-gate  * Returns the current state in doutp
7030Sstevel@tonic-gate  */
7040Sstevel@tonic-gate int
7050Sstevel@tonic-gate /*ARGSUSED*/
cachefs_io_stateget(vnode_t * vp,void * dinp,void * doutp)7060Sstevel@tonic-gate cachefs_io_stateget(vnode_t *vp, void *dinp, void *doutp)
7070Sstevel@tonic-gate {
7080Sstevel@tonic-gate 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
7090Sstevel@tonic-gate 	int *statep = (int *)doutp;
7100Sstevel@tonic-gate 	int state;
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	/*
7130Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
7140Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
7150Sstevel@tonic-gate 	 */
7160Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	mutex_enter(&fscp->fs_cdlock);
7190Sstevel@tonic-gate 	switch (fscp->fs_cdconnected) {
7200Sstevel@tonic-gate 	case CFS_CD_CONNECTED:
7210Sstevel@tonic-gate 		state = CFS_FS_CONNECTED;
7220Sstevel@tonic-gate 		break;
7230Sstevel@tonic-gate 	case CFS_CD_DISCONNECTED:
7240Sstevel@tonic-gate 		state = CFS_FS_DISCONNECTED;
7250Sstevel@tonic-gate 		break;
7260Sstevel@tonic-gate 	case CFS_CD_RECONNECTING:
7270Sstevel@tonic-gate 		state = CFS_FS_RECONNECTING;
7280Sstevel@tonic-gate 		break;
7290Sstevel@tonic-gate 	default:
7300Sstevel@tonic-gate 		ASSERT(0);
7310Sstevel@tonic-gate 		break;
7320Sstevel@tonic-gate 	}
7330Sstevel@tonic-gate 	mutex_exit(&fscp->fs_cdlock);
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	*statep = state;
7360Sstevel@tonic-gate 	return (0);
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate /*
7400Sstevel@tonic-gate  * Sets the state of the file system.
7410Sstevel@tonic-gate  */
7420Sstevel@tonic-gate int
7430Sstevel@tonic-gate /*ARGSUSED*/
cachefs_io_stateset(vnode_t * vp,void * dinp,void * doutp)7440Sstevel@tonic-gate cachefs_io_stateset(vnode_t *vp, void *dinp, void *doutp)
7450Sstevel@tonic-gate {
7460Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
7470Sstevel@tonic-gate 	int error = 0;
7480Sstevel@tonic-gate 	int nosig = 1;
7490Sstevel@tonic-gate 	int state = *(int *)dinp;
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	/*
7520Sstevel@tonic-gate 	 * State should not be changeable and always be connected if
7530Sstevel@tonic-gate 	 * NFSv4 is in use.
7540Sstevel@tonic-gate 	 */
7550Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	/* wait until the file system is quiet */
7580Sstevel@tonic-gate 	mutex_enter(&fscp->fs_cdlock);
7590Sstevel@tonic-gate 	if (fscp->fs_cdtransition == 1) {
7600Sstevel@tonic-gate 		/* if someone is already changing the state */
7610Sstevel@tonic-gate 		mutex_exit(&fscp->fs_cdlock);
7620Sstevel@tonic-gate 		return (0);
7630Sstevel@tonic-gate 	}
7640Sstevel@tonic-gate 	fscp->fs_cdtransition = 1;
7650Sstevel@tonic-gate 	while (nosig && (fscp->fs_cdrefcnt != 0)) {
7660Sstevel@tonic-gate 		nosig = cv_wait_sig(&fscp->fs_cdwaitcv, &fscp->fs_cdlock);
7670Sstevel@tonic-gate 	}
7680Sstevel@tonic-gate 	if (!nosig) {
7690Sstevel@tonic-gate 		fscp->fs_cdtransition = 0;
7700Sstevel@tonic-gate 		cv_broadcast(&fscp->fs_cdwaitcv);
7710Sstevel@tonic-gate 		mutex_exit(&fscp->fs_cdlock);
7720Sstevel@tonic-gate 		return (EINTR);
7730Sstevel@tonic-gate 	}
7740Sstevel@tonic-gate 	mutex_exit(&fscp->fs_cdlock);
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	switch (state) {
7770Sstevel@tonic-gate 	case CFS_FS_CONNECTED:
7780Sstevel@tonic-gate 		/* done if already in this state */
7790Sstevel@tonic-gate 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED)
7800Sstevel@tonic-gate 			break;
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 		mutex_enter(&fscp->fs_cdlock);
7830Sstevel@tonic-gate 		fscp->fs_cdconnected = CFS_CD_CONNECTED;
7840Sstevel@tonic-gate 		mutex_exit(&fscp->fs_cdlock);
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 		/* fix up modified files */
7870Sstevel@tonic-gate 		cachefs_modified_fix(fscp);
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate #if 0
7900Sstevel@tonic-gate 		if (fscp->fs_hostname != NULL)
7910Sstevel@tonic-gate 			printf("\ncachefs:server          - %s",
7920Sstevel@tonic-gate 			    fscp->fs_hostname);
7930Sstevel@tonic-gate 		if (fscp->fs_mntpt != NULL)
7940Sstevel@tonic-gate 			printf("\ncachefs:mount point     - %s",
7950Sstevel@tonic-gate 			    fscp->fs_mntpt);
7960Sstevel@tonic-gate 		if (fscp->fs_backfsname != NULL)
7970Sstevel@tonic-gate 			printf("\ncachefs:back filesystem - %s",
7980Sstevel@tonic-gate 			    fscp->fs_backfsname);
7990Sstevel@tonic-gate 		printf("\nok\n");
8000Sstevel@tonic-gate #else
8010Sstevel@tonic-gate 		if (fscp->fs_hostname && fscp->fs_backfsname)
8020Sstevel@tonic-gate 			printf("cachefs: %s:%s ok\n",
8030Sstevel@tonic-gate 			    fscp->fs_hostname, fscp->fs_backfsname);
8040Sstevel@tonic-gate 		else
8050Sstevel@tonic-gate 			printf("cachefs: server ok\n");
8060Sstevel@tonic-gate #endif
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 		/* allow deletion of renamed open files to proceed */
8090Sstevel@tonic-gate 		cachefs_cnode_traverse(fscp, allow_pendrm);
8100Sstevel@tonic-gate 		break;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	case CFS_FS_DISCONNECTED:
8130Sstevel@tonic-gate 		/* done if already in this state */
8140Sstevel@tonic-gate 		if (fscp->fs_cdconnected == CFS_CD_DISCONNECTED)
8150Sstevel@tonic-gate 			break;
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 		/* drop all back vps */
8180Sstevel@tonic-gate 		cachefs_cnode_traverse(fscp, drop_backvp);
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 		mutex_enter(&fscp->fs_cdlock);
8220Sstevel@tonic-gate 		fscp->fs_cdconnected = CFS_CD_DISCONNECTED;
8230Sstevel@tonic-gate 		mutex_exit(&fscp->fs_cdlock);
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate #if 0
8260Sstevel@tonic-gate 		if (fscp->fs_hostname != NULL)
8270Sstevel@tonic-gate 			printf("\ncachefs:server          - %s",
8280Sstevel@tonic-gate 			    fscp->fs_hostname);
8290Sstevel@tonic-gate 		if (fscp->fs_mntpt != NULL)
8300Sstevel@tonic-gate 			printf("\ncachefs:mount point     - %s",
8310Sstevel@tonic-gate 			    fscp->fs_mntpt);
8320Sstevel@tonic-gate 		if (fscp->fs_backfsname != NULL)
8330Sstevel@tonic-gate 			printf("\ncachefs:back filesystem - %s",
8340Sstevel@tonic-gate 			    fscp->fs_backfsname);
8350Sstevel@tonic-gate 		printf("\nnot responding still trying\n");
8360Sstevel@tonic-gate #else
8370Sstevel@tonic-gate 		if (fscp->fs_hostname && fscp->fs_backfsname)
8380Sstevel@tonic-gate 			printf("cachefs: %s:%s not responding still trying\n",
8390Sstevel@tonic-gate 			    fscp->fs_hostname, fscp->fs_backfsname);
8400Sstevel@tonic-gate 		else
8410Sstevel@tonic-gate 			printf("cachefs: server not responding still trying\n");
8420Sstevel@tonic-gate #endif
8430Sstevel@tonic-gate 		break;
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	case CFS_FS_RECONNECTING:
8460Sstevel@tonic-gate 		/* done if already in this state */
8470Sstevel@tonic-gate 		if (fscp->fs_cdconnected == CFS_CD_RECONNECTING)
8480Sstevel@tonic-gate 			break;
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 		/*
8510Sstevel@tonic-gate 		 * Before we enter disconnected state we sync all metadata,
8520Sstevel@tonic-gate 		 * this allows us to read metadata directly in subsequent
8530Sstevel@tonic-gate 		 * calls so we don't need to allocate cnodes when
8540Sstevel@tonic-gate 		 * we just need metadata information.
8550Sstevel@tonic-gate 		 */
8560Sstevel@tonic-gate 		/* XXX bob: need to eliminate this */
8570Sstevel@tonic-gate 		cachefs_cnode_traverse(fscp, sync_metadata);
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 		mutex_enter(&fscp->fs_cdlock);
8600Sstevel@tonic-gate 		fscp->fs_cdconnected = CFS_CD_RECONNECTING;
8610Sstevel@tonic-gate 		mutex_exit(&fscp->fs_cdlock);
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 		/* no longer need dlog active */
8640Sstevel@tonic-gate 		cachefs_dlog_teardown(fscp);
8650Sstevel@tonic-gate 		break;
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	default:
8680Sstevel@tonic-gate 		error = ENOTTY;
8690Sstevel@tonic-gate 		break;
8700Sstevel@tonic-gate 	}
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	mutex_enter(&fscp->fs_cdlock);
8730Sstevel@tonic-gate 	fscp->fs_cdtransition = 0;
8740Sstevel@tonic-gate 	cv_broadcast(&fscp->fs_cdwaitcv);
8750Sstevel@tonic-gate 	mutex_exit(&fscp->fs_cdlock);
8760Sstevel@tonic-gate 	return (error);
8770Sstevel@tonic-gate }
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate /*
8800Sstevel@tonic-gate  * Blocks until the file system switches
8810Sstevel@tonic-gate  * out of the connected state.
8820Sstevel@tonic-gate  */
8830Sstevel@tonic-gate int
8840Sstevel@tonic-gate /*ARGSUSED*/
cachefs_io_xwait(vnode_t * vp,void * dinp,void * doutp)8850Sstevel@tonic-gate cachefs_io_xwait(vnode_t *vp, void *dinp, void *doutp)
8860Sstevel@tonic-gate {
8870Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
8880Sstevel@tonic-gate 	int nosig = 1;
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	/*
8910Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
8920Sstevel@tonic-gate 	 * that this is not used when NFSv4 is the backfilesytem.
8930Sstevel@tonic-gate 	 */
8940Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	mutex_enter(&fscp->fs_cdlock);
8970Sstevel@tonic-gate 	while (nosig &&
8980Sstevel@tonic-gate 	    (fscp->fs_cdconnected == CFS_CD_CONNECTED)) {
8990Sstevel@tonic-gate 		nosig = cv_wait_sig(&fscp->fs_cdwaitcv, &fscp->fs_cdlock);
9000Sstevel@tonic-gate 	}
9010Sstevel@tonic-gate 	mutex_exit(&fscp->fs_cdlock);
9020Sstevel@tonic-gate 	if (!nosig)
9030Sstevel@tonic-gate 		return (EINTR);
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	return (0);
9060Sstevel@tonic-gate }
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate #define	RL_HEAD(cachep, type) \
9090Sstevel@tonic-gate 	(&(cachep->c_rlinfo.rl_items[CACHEFS_RL_INDEX(type)]))
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate /*
9120Sstevel@tonic-gate  * Returns some statistics about the cache.
9130Sstevel@tonic-gate  */
9140Sstevel@tonic-gate #define	CFS_STAT_FACTOR		(MAXBSIZE / 1024)
9150Sstevel@tonic-gate int
9160Sstevel@tonic-gate /*ARGSUSED*/
cachefs_io_getstats(vnode_t * vp,void * dinp,void * doutp)9170Sstevel@tonic-gate cachefs_io_getstats(vnode_t *vp, void *dinp, void *doutp)
9180Sstevel@tonic-gate {
9190Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
9200Sstevel@tonic-gate 	cachefscache_t *cachep = fscp->fs_cache;
9210Sstevel@tonic-gate 	struct statvfs64 sb;
9220Sstevel@tonic-gate 	fsblkcnt64_t avail = 0;
9230Sstevel@tonic-gate 	fsblkcnt64_t blocks;
9240Sstevel@tonic-gate 	int error;
9250Sstevel@tonic-gate 	cachefsio_getstats_t *gsp = (cachefsio_getstats_t *)doutp;
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	/* determine number of blocks available to the cache */
9280Sstevel@tonic-gate 	error = VFS_STATVFS(cachep->c_dirvp->v_vfsp, &sb);
9290Sstevel@tonic-gate 	if (error == 0) {
9300Sstevel@tonic-gate 		blocks = (fsblkcnt64_t)(cachep->c_label.cl_maxblks -
9310Sstevel@tonic-gate 		    cachep->c_usage.cu_blksused);
9320Sstevel@tonic-gate 		if ((longlong_t)blocks < (longlong_t)0)
9330Sstevel@tonic-gate 			blocks = (fsblkcnt64_t)0;
9340Sstevel@tonic-gate 		avail = (sb.f_bfree * sb.f_frsize) / MAXBSIZE;
9350Sstevel@tonic-gate 		if (blocks < avail)
9360Sstevel@tonic-gate 			avail = blocks;
9370Sstevel@tonic-gate 	}
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 	gsp->gs_total = cachep->c_usage.cu_blksused * CFS_STAT_FACTOR;
9400Sstevel@tonic-gate 	gsp->gs_gc = RL_HEAD(cachep, CACHEFS_RL_GC)->rli_blkcnt *
9410Sstevel@tonic-gate 		CFS_STAT_FACTOR;
9420Sstevel@tonic-gate 	gsp->gs_active = RL_HEAD(cachep, CACHEFS_RL_ACTIVE)->rli_blkcnt *
9430Sstevel@tonic-gate 		CFS_STAT_FACTOR;
9440Sstevel@tonic-gate 	gsp->gs_packed = RL_HEAD(cachep, CACHEFS_RL_PACKED)->rli_blkcnt *
9450Sstevel@tonic-gate 		CFS_STAT_FACTOR;
9460Sstevel@tonic-gate 	gsp->gs_free = (long)(avail * CFS_STAT_FACTOR);
9470Sstevel@tonic-gate 	gsp->gs_gctime = cachep->c_rlinfo.rl_gctime;
9480Sstevel@tonic-gate 	return (0);
9490Sstevel@tonic-gate }
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate /*
9520Sstevel@tonic-gate  * This looks to see if the specified file exists in the cache.
9530Sstevel@tonic-gate  * 	0 is returned if it exists
9540Sstevel@tonic-gate  *	ENOENT is returned if it doesn't exist.
9550Sstevel@tonic-gate  */
9560Sstevel@tonic-gate int
9570Sstevel@tonic-gate /*ARGSUSED*/
cachefs_io_exists(vnode_t * vp,void * dinp,void * doutp)9580Sstevel@tonic-gate cachefs_io_exists(vnode_t *vp, void *dinp, void *doutp)
9590Sstevel@tonic-gate {
9600Sstevel@tonic-gate 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
9610Sstevel@tonic-gate 	cnode_t *cp = NULL;
9620Sstevel@tonic-gate 	int error;
9630Sstevel@tonic-gate 	cfs_cid_t *cidp = (cfs_cid_t *)dinp;
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	/*
9660Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
9670Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
9680Sstevel@tonic-gate 	 */
9690Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	/* find the cnode of the file */
9720Sstevel@tonic-gate 	error = cachefs_cnode_make(cidp, fscp,
9730Sstevel@tonic-gate 	    NULL, NULL, NULL, kcred, 0, &cp);
9740Sstevel@tonic-gate 	if (error)
9750Sstevel@tonic-gate 		return (ENOENT);
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	if ((cp->c_flags & (CN_DESTROY | CN_NOCACHE)) ||
9780Sstevel@tonic-gate 	    !(cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK)))
9790Sstevel@tonic-gate 		error = ENOENT;
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	VN_RELE(CTOV(cp));
9820Sstevel@tonic-gate 	return	(error);
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate /*
9870Sstevel@tonic-gate  * Moves the specified file to the lost+found directory for the
9880Sstevel@tonic-gate  * cached file system.
9890Sstevel@tonic-gate  * Invalidates cached data and attributes.
9900Sstevel@tonic-gate  * Returns 0 or an error if could not perform operation.
9910Sstevel@tonic-gate  */
9920Sstevel@tonic-gate int
cachefs_io_lostfound(vnode_t * vp,void * dinp,void * doutp)9930Sstevel@tonic-gate cachefs_io_lostfound(vnode_t *vp, void *dinp, void *doutp)
9940Sstevel@tonic-gate {
9950Sstevel@tonic-gate 	int error;
9960Sstevel@tonic-gate 	cnode_t *cp = NULL;
9970Sstevel@tonic-gate 	fscache_t *fscp;
9980Sstevel@tonic-gate 	cachefscache_t *cachep;
9990Sstevel@tonic-gate 	cachefsio_lostfound_arg_t *lfp;
10000Sstevel@tonic-gate 	cachefsio_lostfound_return_t *rp;
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	lfp = (cachefsio_lostfound_arg_t *)dinp;
10030Sstevel@tonic-gate 	rp = (cachefsio_lostfound_return_t *)doutp;
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 	fscp = C_TO_FSCACHE(VTOC(vp));
10060Sstevel@tonic-gate 	cachep = fscp->fs_cache;
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0);
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 	/*
10110Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
10120Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
10130Sstevel@tonic-gate 	 */
10140Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 	/* find the cnode of the file */
10170Sstevel@tonic-gate 	error = cachefs_cnode_make(&lfp->lf_cid, fscp,
10180Sstevel@tonic-gate 	    NULL, NULL, NULL, kcred, 0, &cp);
10190Sstevel@tonic-gate 	if (error) {
10200Sstevel@tonic-gate 		error = ENOENT;
10210Sstevel@tonic-gate 		goto out;
10220Sstevel@tonic-gate 	}
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	/* must be regular file and modified */
10270Sstevel@tonic-gate 	if ((cp->c_attr.va_type != VREG) ||
10280Sstevel@tonic-gate 	    (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED)) {
10290Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
10300Sstevel@tonic-gate 		error = EINVAL;
10310Sstevel@tonic-gate 		goto out;
10320Sstevel@tonic-gate 	}
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	/* move to lost+found */
10350Sstevel@tonic-gate 	error = cachefs_cnode_lostfound(cp, lfp->lf_name);
10360Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	if (error == 0)
10390Sstevel@tonic-gate 		(void) strcpy(rp->lf_name, lfp->lf_name);
10400Sstevel@tonic-gate out:
10410Sstevel@tonic-gate 	if (cp)
10420Sstevel@tonic-gate 		VN_RELE(CTOV(cp));
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	return (error);
10450Sstevel@tonic-gate }
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate /*
10480Sstevel@tonic-gate  * Given a cid, returns info about the file in the cache.
10490Sstevel@tonic-gate  */
10500Sstevel@tonic-gate int
cachefs_io_getinfo(vnode_t * vp,void * dinp,void * doutp)10510Sstevel@tonic-gate cachefs_io_getinfo(vnode_t *vp, void *dinp, void *doutp)
10520Sstevel@tonic-gate {
10530Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
10540Sstevel@tonic-gate 	struct cnode *dcp = NULL;
10550Sstevel@tonic-gate 	struct cnode *cp = NULL;
10560Sstevel@tonic-gate 	struct vattr va;
10570Sstevel@tonic-gate 	u_offset_t blockoff = 0;
10580Sstevel@tonic-gate 	struct fbuf *fbp;
10590Sstevel@tonic-gate 	int offset = 0;
10600Sstevel@tonic-gate 	int error = 0;
10610Sstevel@tonic-gate 	cfs_cid_t *fcidp;
10620Sstevel@tonic-gate 	cachefsio_getinfo_t *infop;
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	/*
10650Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
10660Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
10670Sstevel@tonic-gate 	 */
10680Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	fcidp = (cfs_cid_t *)dinp;
10710Sstevel@tonic-gate 	infop = (cachefsio_getinfo_t *)doutp;
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	/* find the cnode of the file */
10740Sstevel@tonic-gate 	error = cachefs_cnode_make(fcidp, fscp, NULL, NULL, NULL,
10750Sstevel@tonic-gate 	    kcred, 0, &cp);
10760Sstevel@tonic-gate 	if (error) {
10770Sstevel@tonic-gate 		error = ENOENT;
10780Sstevel@tonic-gate 		goto out;
10790Sstevel@tonic-gate 	}
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 	infop->gi_cid = *fcidp;
10820Sstevel@tonic-gate 	infop->gi_modified = (cp->c_metadata.md_rltype == CACHEFS_RL_MODIFIED);
10830Sstevel@tonic-gate 	CACHEFS_VATTR_TO_CFS_VATTR_COPY(&cp->c_attr, &infop->gi_attr, error);
10840Sstevel@tonic-gate 	infop->gi_pcid = cp->c_metadata.md_parent;
10850Sstevel@tonic-gate 	infop->gi_name[0] = '\0';
10860Sstevel@tonic-gate 	infop->gi_seq = cp->c_metadata.md_seq;
10870Sstevel@tonic-gate 	if (error || (cp->c_metadata.md_parent.cid_fileno == 0))
10880Sstevel@tonic-gate 		goto out;
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	/* try to get the cnode of the parent dir */
10910Sstevel@tonic-gate 	error = cachefs_cnode_make(&cp->c_metadata.md_parent, fscp,
10920Sstevel@tonic-gate 	    NULL, NULL, NULL, kcred, 0, &dcp);
10930Sstevel@tonic-gate 	if (error) {
10940Sstevel@tonic-gate 		error = 0;
10950Sstevel@tonic-gate 		goto out;
10960Sstevel@tonic-gate 	}
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	/* make sure a directory and populated */
10990Sstevel@tonic-gate 	if ((((dcp->c_flags & CN_ASYNC_POPULATE) == 0) ||
11000Sstevel@tonic-gate 	    ((dcp->c_metadata.md_flags & MD_POPULATED) == 0)) &&
11010Sstevel@tonic-gate 	    (CTOV(dcp)->v_type == VDIR)) {
11020Sstevel@tonic-gate 		error = 0;
11030Sstevel@tonic-gate 		goto out;
11040Sstevel@tonic-gate 	}
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 	/* get the front file */
11070Sstevel@tonic-gate 	if (dcp->c_frontvp == NULL) {
11080Sstevel@tonic-gate 		mutex_enter(&dcp->c_statelock);
11090Sstevel@tonic-gate 		error = cachefs_getfrontfile(dcp);
11100Sstevel@tonic-gate 		mutex_exit(&dcp->c_statelock);
11110Sstevel@tonic-gate 		if (error) {
11120Sstevel@tonic-gate 			error = 0;
11130Sstevel@tonic-gate 			goto out;
11140Sstevel@tonic-gate 		}
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 		/* make sure frontvp is still populated */
11170Sstevel@tonic-gate 		if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
11180Sstevel@tonic-gate 			error = 0;
11190Sstevel@tonic-gate 			goto out;
11200Sstevel@tonic-gate 		}
11210Sstevel@tonic-gate 	}
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 	/* Get the length of the directory */
11240Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
1125*5331Samw 	error = VOP_GETATTR(dcp->c_frontvp, &va, 0, kcred, NULL);
11260Sstevel@tonic-gate 	if (error) {
11270Sstevel@tonic-gate 		error = 0;
11280Sstevel@tonic-gate 		goto out;
11290Sstevel@tonic-gate 	}
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 	/* XXX bob: change this to use cachfs_dir_read */
11320Sstevel@tonic-gate 	/* We have found the parent, now we open the dir and look for file */
11330Sstevel@tonic-gate 	while (blockoff < va.va_size) {
11340Sstevel@tonic-gate 		offset = 0;
11350Sstevel@tonic-gate 		error = fbread(dcp->c_frontvp, (offset_t)blockoff, MAXBSIZE,
11360Sstevel@tonic-gate 						S_OTHER, &fbp);
11370Sstevel@tonic-gate 		if (error)
11380Sstevel@tonic-gate 			goto out;
11390Sstevel@tonic-gate 		while (offset < MAXBSIZE && (blockoff + offset) < va.va_size) {
11400Sstevel@tonic-gate 			struct c_dirent	*dep;
11410Sstevel@tonic-gate 			dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr +
11420Sstevel@tonic-gate 									offset);
11430Sstevel@tonic-gate 			if ((dep->d_flag & CDE_VALID) &&
11440Sstevel@tonic-gate 			    (bcmp(&dep->d_id, &infop->gi_cid,
11450Sstevel@tonic-gate 			    sizeof (cfs_cid_t)) == 0)) {
11460Sstevel@tonic-gate 				/* found the name */
11470Sstevel@tonic-gate 				(void) strcpy(infop->gi_name, dep->d_name);
11480Sstevel@tonic-gate 				fbrelse(fbp, S_OTHER);
11490Sstevel@tonic-gate 				goto out;
11500Sstevel@tonic-gate 			}
11510Sstevel@tonic-gate 			offset += dep->d_length;
11520Sstevel@tonic-gate 		}
11530Sstevel@tonic-gate 		fbrelse(fbp, S_OTHER);
11540Sstevel@tonic-gate 		fbp = NULL;
11550Sstevel@tonic-gate 		blockoff += MAXBSIZE;
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	}
11580Sstevel@tonic-gate out:
11590Sstevel@tonic-gate 	if (cp)
11600Sstevel@tonic-gate 		VN_RELE(CTOV(cp));
11610Sstevel@tonic-gate 	if (dcp)
11620Sstevel@tonic-gate 		VN_RELE(CTOV(dcp));
11630Sstevel@tonic-gate 	return (error);
11640Sstevel@tonic-gate }
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate /*
11670Sstevel@tonic-gate  * Given a file number, this functions returns the fid
11680Sstevel@tonic-gate  * for the back file system.
11690Sstevel@tonic-gate  * Returns ENOENT if file does not exist.
11700Sstevel@tonic-gate  * Returns ENOMSG if fid is not valid, ie: local file.
11710Sstevel@tonic-gate  */
11720Sstevel@tonic-gate int
cachefs_io_cidtofid(vnode_t * vp,void * dinp,void * doutp)11730Sstevel@tonic-gate cachefs_io_cidtofid(vnode_t *vp, void *dinp, void *doutp)
11740Sstevel@tonic-gate {
11750Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
11760Sstevel@tonic-gate 	cnode_t *cp = NULL;
11770Sstevel@tonic-gate 	int error;
11780Sstevel@tonic-gate 	cfs_cid_t *cidp = (cfs_cid_t *)dinp;
11790Sstevel@tonic-gate 	cfs_fid_t *fidp = (cfs_fid_t *)doutp;
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 	/*
11820Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
11830Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
11840Sstevel@tonic-gate 	 */
11850Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 	/* get the cnode for the file */
11880Sstevel@tonic-gate 	error = cachefs_cnode_make(cidp, fscp, NULL, NULL, NULL, kcred, 0, &cp);
11890Sstevel@tonic-gate 	if (error)
11900Sstevel@tonic-gate 		goto out;
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	/* if local file, fid is a local fid and is not valid */
11930Sstevel@tonic-gate 	if (cp->c_id.cid_flags & CFS_CID_LOCAL) {
11940Sstevel@tonic-gate 		error = ENOMSG;
11950Sstevel@tonic-gate 		goto out;
11960Sstevel@tonic-gate 	}
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	/* copy out the fid */
11990Sstevel@tonic-gate 	CACHEFS_FID_COPY(&cp->c_cookie, fidp);
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate out:
12020Sstevel@tonic-gate 	if (cp)
12030Sstevel@tonic-gate 		VN_RELE(CTOV(cp));
12040Sstevel@tonic-gate 	return	(error);
12050Sstevel@tonic-gate }
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate /*
12080Sstevel@tonic-gate  * This performs a getattr on the back file system given
12090Sstevel@tonic-gate  * a fid that is passed in.
12100Sstevel@tonic-gate  *
12110Sstevel@tonic-gate  * The backfid is in gafid->cg_backfid, the creds to use for
12120Sstevel@tonic-gate  * this operation are in gafid->cg_cred.  The attributes are
12130Sstevel@tonic-gate  * returned in gafid->cg_attr
12140Sstevel@tonic-gate  *
12150Sstevel@tonic-gate  * the error returned is 0 if successful, nozero if not
12160Sstevel@tonic-gate  */
12170Sstevel@tonic-gate int
cachefs_io_getattrfid(vnode_t * vp,void * dinp,void * doutp)12180Sstevel@tonic-gate cachefs_io_getattrfid(vnode_t *vp, void *dinp, void *doutp)
12190Sstevel@tonic-gate {
12200Sstevel@tonic-gate 	vnode_t	*backvp = NULL;
12210Sstevel@tonic-gate 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
12220Sstevel@tonic-gate 	int error = 0;
12230Sstevel@tonic-gate 	cred_t	*cr;
12240Sstevel@tonic-gate 	cachefsio_getattrfid_t *gafid;
12250Sstevel@tonic-gate 	fid_t	*tmpfidp;
12260Sstevel@tonic-gate 	vattr_t *tmpvap;
12270Sstevel@tonic-gate 	cfs_vattr_t *attrp;
12280Sstevel@tonic-gate 	CACHEFS_DECL(fid_t, tmpfid);
12290Sstevel@tonic-gate 	CACHEFS_DECL(vattr_t, va);
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 	/*
12320Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
12330Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
12340Sstevel@tonic-gate 	 */
12350Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate 	gafid = (cachefsio_getattrfid_t *)dinp;
12380Sstevel@tonic-gate 	attrp = (cfs_vattr_t *)doutp;
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 	/* Get a vnode for the back file */
12410Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&gafid->cg_backfid, &tmpfid, tmpfidp, fid_t);
12420Sstevel@tonic-gate 	CACHEFS_FID_COPYIN(&gafid->cg_backfid, tmpfidp);
12430Sstevel@tonic-gate 	error = VFS_VGET(fscp->fs_backvfsp, &backvp, tmpfidp);
12440Sstevel@tonic-gate 	if (error)
12450Sstevel@tonic-gate 		return (error);
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	cr = conj_cred(&gafid->cg_cred);
12480Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(attrp, &va, tmpvap, vattr_t);
12490Sstevel@tonic-gate 	tmpvap->va_mask = AT_ALL;
1250*5331Samw 	error = VOP_GETATTR(backvp, tmpvap, 0, cr, NULL);
12510Sstevel@tonic-gate 	CACHEFS_VATTR_COPYOUT(tmpvap, attrp, error);
12520Sstevel@tonic-gate 	crfree(cr);
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 	/* VFS_VGET performs a VN_HOLD on the vp */
12550Sstevel@tonic-gate 	VN_RELE(backvp);
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 	return (error);
12580Sstevel@tonic-gate }
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate /*
12620Sstevel@tonic-gate  * This performs a getattr on the back file system.  Instead of
12630Sstevel@tonic-gate  * passing the fid to perform the gettr on we are given the
12640Sstevel@tonic-gate  * parent directory fid and a name.
12650Sstevel@tonic-gate  */
12660Sstevel@tonic-gate int
cachefs_io_getattrname(vnode_t * vp,void * dinp,void * doutp)12670Sstevel@tonic-gate cachefs_io_getattrname(vnode_t *vp, void *dinp, void *doutp)
12680Sstevel@tonic-gate {
12690Sstevel@tonic-gate 	vnode_t	*pbackvp = NULL;
12700Sstevel@tonic-gate 	vnode_t	*cbackvp = NULL;
12710Sstevel@tonic-gate 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
12720Sstevel@tonic-gate 	int error = 0;
12730Sstevel@tonic-gate 	cred_t	*cr;
12740Sstevel@tonic-gate 	fid_t	*tmpfidp;
12750Sstevel@tonic-gate 	vattr_t	*tmpvap;
12760Sstevel@tonic-gate 	cachefsio_getattrname_arg_t *gap;
12770Sstevel@tonic-gate 	cachefsio_getattrname_return_t *retp;
12780Sstevel@tonic-gate 	CACHEFS_DECL(fid_t, tmpfid);
12790Sstevel@tonic-gate 	CACHEFS_DECL(vattr_t, va);
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 	/*
12820Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
12830Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
12840Sstevel@tonic-gate 	 */
12850Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	gap = (cachefsio_getattrname_arg_t *)dinp;
12880Sstevel@tonic-gate 	retp = (cachefsio_getattrname_return_t *)doutp;
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 	/* Get a vnode for the parent directory */
12910Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&gap->cg_dir, &tmpfid, tmpfidp, fid_t);
12920Sstevel@tonic-gate 	CACHEFS_FID_COPYIN(&gap->cg_dir, tmpfidp);
12930Sstevel@tonic-gate 	error = VFS_VGET(fscp->fs_backvfsp, &pbackvp, tmpfidp);
12940Sstevel@tonic-gate 	if (error)
12950Sstevel@tonic-gate 		return (error);
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 	/* lookup the file name */
12980Sstevel@tonic-gate 	cr = conj_cred(&gap->cg_cred);
12990Sstevel@tonic-gate 	error = VOP_LOOKUP(pbackvp, gap->cg_name, &cbackvp,
1300*5331Samw 	    (struct pathname *)NULL, 0, (vnode_t *)NULL, cr, NULL, NULL, NULL);
13010Sstevel@tonic-gate 	if (error) {
13020Sstevel@tonic-gate 		crfree(cr);
13030Sstevel@tonic-gate 		VN_RELE(pbackvp);
13040Sstevel@tonic-gate 		return (error);
13050Sstevel@tonic-gate 	}
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&retp->cg_attr, &va, tmpvap, vattr_t);
13080Sstevel@tonic-gate 	tmpvap->va_mask = AT_ALL;
1309*5331Samw 	error = VOP_GETATTR(cbackvp, tmpvap, 0, cr, NULL);
13100Sstevel@tonic-gate 	CACHEFS_VATTR_COPYOUT(tmpvap, &retp->cg_attr, error);
13110Sstevel@tonic-gate 	if (!error) {
13120Sstevel@tonic-gate 		CACHEFS_TMPPTR_SET(&retp->cg_fid, &tmpfid, tmpfidp, fid_t);
13130Sstevel@tonic-gate 		tmpfidp->fid_len = MAXFIDSZ;
1314*5331Samw 		error = VOP_FID(cbackvp, tmpfidp, NULL);
13150Sstevel@tonic-gate 		CACHEFS_FID_COPYOUT(tmpfidp, &retp->cg_fid);
13160Sstevel@tonic-gate 	}
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 	crfree(cr);
13190Sstevel@tonic-gate 	VN_RELE(cbackvp);
13200Sstevel@tonic-gate 	VN_RELE(pbackvp);
13210Sstevel@tonic-gate 	return (error);
13220Sstevel@tonic-gate }
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate /*
13250Sstevel@tonic-gate  * This will return the fid of the root of this mount point.
13260Sstevel@tonic-gate  */
13270Sstevel@tonic-gate int
13280Sstevel@tonic-gate /*ARGSUSED*/
cachefs_io_rootfid(vnode_t * vp,void * dinp,void * doutp)13290Sstevel@tonic-gate cachefs_io_rootfid(vnode_t *vp, void *dinp, void *doutp)
13300Sstevel@tonic-gate {
13310Sstevel@tonic-gate 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
13320Sstevel@tonic-gate 	cfs_fid_t *rootfid = (cfs_fid_t *)doutp;
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate 	/*
13350Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
13360Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
13370Sstevel@tonic-gate 	 */
13380Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	CACHEFS_FID_COPY(&VTOC(fscp->fs_rootvp)->c_metadata.md_cookie, rootfid);
13410Sstevel@tonic-gate 	return (0);
13420Sstevel@tonic-gate }
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate /*
13450Sstevel@tonic-gate  * Pushes the data associated with a file back to the file server.
13460Sstevel@tonic-gate  */
13470Sstevel@tonic-gate int
cachefs_io_pushback(vnode_t * vp,void * dinp,void * doutp)13480Sstevel@tonic-gate cachefs_io_pushback(vnode_t *vp, void *dinp, void *doutp)
13490Sstevel@tonic-gate {
13500Sstevel@tonic-gate 	vnode_t *backvp = NULL;
13510Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
13520Sstevel@tonic-gate 	caddr_t	buffer = NULL;
13530Sstevel@tonic-gate 	int error = 0;
13540Sstevel@tonic-gate 	cnode_t	*cp;
13550Sstevel@tonic-gate 	size_t amt;
13560Sstevel@tonic-gate 	u_offset_t size;
13570Sstevel@tonic-gate 	vattr_t	va;
13580Sstevel@tonic-gate 	offset_t off;
13590Sstevel@tonic-gate 	cred_t *cr = NULL;
13600Sstevel@tonic-gate 	fid_t	*tmpfidp;
13610Sstevel@tonic-gate 	cachefsio_pushback_arg_t *pbp;
13620Sstevel@tonic-gate 	cachefsio_pushback_return_t *retp;
13630Sstevel@tonic-gate 	CACHEFS_DECL(fid_t, tmpfid);
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	/*
13660Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
13670Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
13680Sstevel@tonic-gate 	 */
13690Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 	pbp = (cachefsio_pushback_arg_t *)dinp;
13720Sstevel@tonic-gate 	retp = (cachefsio_pushback_return_t *)doutp;
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate 	cr = conj_cred(&pbp->pb_cred);
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	/* get the backvp to push to */
13770Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&pbp->pb_fid, &tmpfid, tmpfidp, fid_t);
13780Sstevel@tonic-gate 	CACHEFS_FID_COPYIN(&pbp->pb_fid, tmpfidp);
13790Sstevel@tonic-gate 	error = VFS_VGET(fscp->fs_backvfsp, &backvp, tmpfidp);
13800Sstevel@tonic-gate 	if (error) {
13810Sstevel@tonic-gate 		backvp = NULL;
13820Sstevel@tonic-gate 		goto out;
13830Sstevel@tonic-gate 	}
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 	/* Get the cnode for the file we are to push back */
13860Sstevel@tonic-gate 	error = cachefs_cnode_make(&pbp->pb_cid, fscp,
13870Sstevel@tonic-gate 	    NULL, NULL, NULL, cr, 0, &cp);
13880Sstevel@tonic-gate 	if (error) {
13890Sstevel@tonic-gate 		goto out;
13900Sstevel@tonic-gate 	}
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 	/* must be a regular file */
13930Sstevel@tonic-gate 	if (cp->c_attr.va_type != VREG) {
13940Sstevel@tonic-gate 		error = EINVAL;
13950Sstevel@tonic-gate 		goto out;
13960Sstevel@tonic-gate 	}
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 	/* get the front file */
14010Sstevel@tonic-gate 	if (cp->c_frontvp == NULL) {
14020Sstevel@tonic-gate 		error = cachefs_getfrontfile(cp);
14030Sstevel@tonic-gate 		if (error) {
14040Sstevel@tonic-gate 			mutex_exit(&cp->c_statelock);
14050Sstevel@tonic-gate 			goto out;
14060Sstevel@tonic-gate 		}
14070Sstevel@tonic-gate 	}
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 	/* better be populated */
14100Sstevel@tonic-gate 	if ((cp->c_metadata.md_flags & MD_POPULATED) == 0) {
14110Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
14120Sstevel@tonic-gate 		error = EINVAL;
14130Sstevel@tonic-gate 		goto out;
14140Sstevel@tonic-gate 	}
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 	/* do open so NFS gets correct creds on writes */
1417*5331Samw 	error = VOP_OPEN(&backvp, FWRITE, cr, NULL);
14180Sstevel@tonic-gate 	if (error) {
14190Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
14200Sstevel@tonic-gate 		goto out;
14210Sstevel@tonic-gate 	}
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	buffer = cachefs_kmem_alloc(MAXBSIZE, KM_SLEEP);
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate 	/* Read the data from the cache and write it to the server */
14260Sstevel@tonic-gate 	/* XXX why not use segmapio? */
14270Sstevel@tonic-gate 	off = 0;
14280Sstevel@tonic-gate 	for (size = cp->c_size; size != 0; size -= amt) {
14290Sstevel@tonic-gate 		if (size > MAXBSIZE)
14300Sstevel@tonic-gate 			amt = MAXBSIZE;
14310Sstevel@tonic-gate 		else
14320Sstevel@tonic-gate 			amt = size;
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 		/* read a block of data from the front file */
14350Sstevel@tonic-gate 		error = vn_rdwr(UIO_READ, cp->c_frontvp, buffer,
14360Sstevel@tonic-gate 			amt, off, UIO_SYSSPACE, 0, RLIM_INFINITY, cr, 0);
14370Sstevel@tonic-gate 		if (error) {
14380Sstevel@tonic-gate 			mutex_exit(&cp->c_statelock);
14390Sstevel@tonic-gate 			goto out;
14400Sstevel@tonic-gate 		}
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 		/* write the block of data to the back file */
14430Sstevel@tonic-gate 		error = vn_rdwr(UIO_WRITE, backvp, buffer, amt, off,
14440Sstevel@tonic-gate 			UIO_SYSSPACE, 0, RLIM_INFINITY, cr, 0);
14450Sstevel@tonic-gate 		if (error) {
14460Sstevel@tonic-gate 			mutex_exit(&cp->c_statelock);
14470Sstevel@tonic-gate 			goto out;
14480Sstevel@tonic-gate 		}
14490Sstevel@tonic-gate 		off += amt;
14500Sstevel@tonic-gate 	}
14510Sstevel@tonic-gate 
1452*5331Samw 	error = VOP_FSYNC(backvp, FSYNC, cr, NULL);
14530Sstevel@tonic-gate 	if (error == 0)
1454*5331Samw 		error = VOP_CLOSE(backvp, FWRITE, 1, (offset_t)0, cr, NULL);
14550Sstevel@tonic-gate 	if (error) {
14560Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
14570Sstevel@tonic-gate 		goto out;
14580Sstevel@tonic-gate 	}
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 	cp->c_metadata.md_flags |= MD_PUSHDONE;
14610Sstevel@tonic-gate 	cp->c_metadata.md_flags &= ~MD_PUTPAGE;
14620Sstevel@tonic-gate 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
14630Sstevel@tonic-gate 	cp->c_flags |= CN_UPDATED;
14640Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
14650Sstevel@tonic-gate 
14660Sstevel@tonic-gate 	/*
14670Sstevel@tonic-gate 	 * if we have successfully stored the data, we need the
14680Sstevel@tonic-gate 	 * new ctime and mtimes.
14690Sstevel@tonic-gate 	 */
14700Sstevel@tonic-gate 	va.va_mask = AT_ALL;
1471*5331Samw 	error = VOP_GETATTR(backvp, &va, 0, cr, NULL);
14720Sstevel@tonic-gate 	if (error)
14730Sstevel@tonic-gate 		goto out;
14740Sstevel@tonic-gate 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->pb_ctime, error);
14750Sstevel@tonic-gate 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->pb_mtime, error);
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate out:
14780Sstevel@tonic-gate 	if (buffer)
14790Sstevel@tonic-gate 		cachefs_kmem_free(buffer, MAXBSIZE);
14800Sstevel@tonic-gate 	if (cp)
14810Sstevel@tonic-gate 		VN_RELE(CTOV(cp));
14820Sstevel@tonic-gate 	if (backvp)
14830Sstevel@tonic-gate 		VN_RELE(backvp);
14840Sstevel@tonic-gate 	if (cr)
14850Sstevel@tonic-gate 		crfree(cr);
14860Sstevel@tonic-gate 	return (error);
14870Sstevel@tonic-gate }
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate /*
14900Sstevel@tonic-gate  * Create a file on the back file system.
14910Sstevel@tonic-gate  */
14920Sstevel@tonic-gate int
cachefs_io_create(vnode_t * vp,void * dinp,void * doutp)14930Sstevel@tonic-gate cachefs_io_create(vnode_t *vp, void *dinp, void *doutp)
14940Sstevel@tonic-gate {
14950Sstevel@tonic-gate 	vnode_t	*dvp = NULL;
14960Sstevel@tonic-gate 	vnode_t	*cvp = NULL;
14970Sstevel@tonic-gate 	cnode_t *cp = NULL;
14980Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
14990Sstevel@tonic-gate 	vattr_t	va, *tmpvap;
15000Sstevel@tonic-gate 	int error = 0;
15010Sstevel@tonic-gate 	cred_t *cr = NULL;
15020Sstevel@tonic-gate 	fid_t	*tmpfidp;
15030Sstevel@tonic-gate 	cachefsio_create_arg_t *crp;
15040Sstevel@tonic-gate 	cachefsio_create_return_t *retp;
15050Sstevel@tonic-gate 	CACHEFS_DECL(fid_t, tmpfid);
15060Sstevel@tonic-gate 
15070Sstevel@tonic-gate 	/*
15080Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
15090Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
15100Sstevel@tonic-gate 	 */
15110Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	crp = (cachefsio_create_arg_t *)dinp;
15140Sstevel@tonic-gate 	retp = (cachefsio_create_return_t *)doutp;
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 	/* get a vnode for the parent directory  */
15170Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&crp->cr_backfid, &tmpfid, tmpfidp, fid_t);
15180Sstevel@tonic-gate 	CACHEFS_FID_COPYIN(&crp->cr_backfid, tmpfidp);
15190Sstevel@tonic-gate 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
15200Sstevel@tonic-gate 	if (error)
15210Sstevel@tonic-gate 		goto out;
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 	cr = conj_cred(&crp->cr_cred);
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate 	/* do the create */
15260Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&crp->cr_va, &va, tmpvap, vattr_t);
15270Sstevel@tonic-gate 	CACHEFS_VATTR_COPYIN(&crp->cr_va, tmpvap);
15280Sstevel@tonic-gate 	error = VOP_CREATE(dvp, crp->cr_name, tmpvap,
1529*5331Samw 	    crp->cr_exclusive, crp->cr_mode, &cvp, cr, 0, NULL, NULL);
15300Sstevel@tonic-gate 	if (error)
15310Sstevel@tonic-gate 		goto out;
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 	/* get the fid of the file */
15340Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&retp->cr_newfid, &tmpfid, tmpfidp, fid_t);
15350Sstevel@tonic-gate 	tmpfidp->fid_len = MAXFIDSZ;
1536*5331Samw 	error = VOP_FID(cvp, tmpfidp, NULL);
15370Sstevel@tonic-gate 	if (error)
15380Sstevel@tonic-gate 		goto out;
15390Sstevel@tonic-gate 	CACHEFS_FID_COPYOUT(tmpfidp, &retp->cr_newfid);
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 	/* get attributes for the file */
15420Sstevel@tonic-gate 	va.va_mask = AT_ALL;
1543*5331Samw 	error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
15440Sstevel@tonic-gate 	if (error)
15450Sstevel@tonic-gate 		goto out;
15460Sstevel@tonic-gate 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->cr_ctime, error);
15470Sstevel@tonic-gate 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->cr_mtime, error);
15480Sstevel@tonic-gate 	if (error)
15490Sstevel@tonic-gate 		goto out;
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 	/* update the cnode for this file with the new info */
15520Sstevel@tonic-gate 	error = cachefs_cnode_make(&crp->cr_cid, fscp,
15530Sstevel@tonic-gate 	    NULL, NULL, NULL, cr, 0, &cp);
15540Sstevel@tonic-gate 	if (error) {
15550Sstevel@tonic-gate 		error = 0;
15560Sstevel@tonic-gate 		goto out;
15570Sstevel@tonic-gate 	}
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
15600Sstevel@tonic-gate 	ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL);
15610Sstevel@tonic-gate 	cp->c_attr.va_nodeid = va.va_nodeid;
15620Sstevel@tonic-gate 	cp->c_metadata.md_flags |= MD_CREATEDONE;
15630Sstevel@tonic-gate 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
15640Sstevel@tonic-gate 	cp->c_metadata.md_cookie = *tmpfidp;
15650Sstevel@tonic-gate 	cp->c_flags |= CN_UPDATED;
15660Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate out:
15690Sstevel@tonic-gate 	if (cr)
15700Sstevel@tonic-gate 		crfree(cr);
15710Sstevel@tonic-gate 	if (dvp)
15720Sstevel@tonic-gate 		VN_RELE(dvp);
15730Sstevel@tonic-gate 	if (cvp)
15740Sstevel@tonic-gate 		VN_RELE(cvp);
15750Sstevel@tonic-gate 	if (cp)
15760Sstevel@tonic-gate 		VN_RELE(CTOV(cp));
15770Sstevel@tonic-gate 	return (error);
15780Sstevel@tonic-gate }
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate /*
15810Sstevel@tonic-gate  * Remove a file on the back file system.
15820Sstevel@tonic-gate  * Returns 0 or an error if could not perform operation.
15830Sstevel@tonic-gate  */
15840Sstevel@tonic-gate int
cachefs_io_remove(vnode_t * vp,void * dinp,void * doutp)15850Sstevel@tonic-gate cachefs_io_remove(vnode_t *vp, void *dinp, void *doutp)
15860Sstevel@tonic-gate {
15870Sstevel@tonic-gate 	vnode_t	*dvp = NULL;
15880Sstevel@tonic-gate 	vnode_t	*cvp;
15890Sstevel@tonic-gate 	cred_t *cr = NULL;
15900Sstevel@tonic-gate 	vattr_t	va;
15910Sstevel@tonic-gate 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
15920Sstevel@tonic-gate 	int error;
15930Sstevel@tonic-gate 	fid_t child_fid, *child_fidp;
15940Sstevel@tonic-gate 	cachefsio_remove_t *rmp = (cachefsio_remove_t *)dinp;
15950Sstevel@tonic-gate 	cfs_timestruc_t *ctimep = (cfs_timestruc_t *)doutp;
15960Sstevel@tonic-gate 
15970Sstevel@tonic-gate 	/*
15980Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
15990Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
16000Sstevel@tonic-gate 	 */
16010Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
16020Sstevel@tonic-gate 
16030Sstevel@tonic-gate 	/* Get a vnode for the directory */
16040Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&rmp->rm_fid, &child_fid, child_fidp, fid_t);
16050Sstevel@tonic-gate 	CACHEFS_FID_COPYIN(&rmp->rm_fid, child_fidp);
16060Sstevel@tonic-gate 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, child_fidp);
16070Sstevel@tonic-gate 	if (error) {
16080Sstevel@tonic-gate 		dvp = NULL;
16090Sstevel@tonic-gate 		goto out;
16100Sstevel@tonic-gate 	}
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate 	cr = conj_cred(&rmp->rm_cred);
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate 	/* if the caller wants the ctime after the remove */
16150Sstevel@tonic-gate 	if (ctimep) {
1616*5331Samw 		error = VOP_LOOKUP(dvp, rmp->rm_name, &cvp, NULL, 0, NULL, cr,
1617*5331Samw 			NULL, NULL, NULL);
16180Sstevel@tonic-gate 		if (error == 0) {
16190Sstevel@tonic-gate 			child_fid.fid_len = MAXFIDSZ;
1620*5331Samw 			error = VOP_FID(cvp, &child_fid, NULL);
16210Sstevel@tonic-gate 			VN_RELE(cvp);
16220Sstevel@tonic-gate 		}
16230Sstevel@tonic-gate 		if (error)
16240Sstevel@tonic-gate 			goto out;
16250Sstevel@tonic-gate 	}
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 	/* do the remove */
1628*5331Samw 	error = VOP_REMOVE(dvp, rmp->rm_name, cr, NULL, 0);
16290Sstevel@tonic-gate 	if (error)
16300Sstevel@tonic-gate 		goto out;
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate 	/* get the new ctime if requested */
16330Sstevel@tonic-gate 	if (ctimep) {
16340Sstevel@tonic-gate 		error = VFS_VGET(fscp->fs_backvfsp, &cvp, &child_fid);
16350Sstevel@tonic-gate 		if (error == 0) {
16360Sstevel@tonic-gate 			va.va_mask = AT_ALL;
1637*5331Samw 			error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
16380Sstevel@tonic-gate 			if (error == 0) {
16390Sstevel@tonic-gate 				CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime,
16400Sstevel@tonic-gate 					ctimep, error);
16410Sstevel@tonic-gate 			}
16420Sstevel@tonic-gate 			VN_RELE(cvp);
16430Sstevel@tonic-gate 		}
16440Sstevel@tonic-gate 		cachefs_iosetneedattrs(fscp, &rmp->rm_cid);
16450Sstevel@tonic-gate 	}
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate out:
16480Sstevel@tonic-gate 	if (cr)
16490Sstevel@tonic-gate 		crfree(cr);
16500Sstevel@tonic-gate 	if (dvp)
16510Sstevel@tonic-gate 		VN_RELE(dvp);
16520Sstevel@tonic-gate 	return (error);
16530Sstevel@tonic-gate }
16540Sstevel@tonic-gate 
16550Sstevel@tonic-gate /*
16560Sstevel@tonic-gate  * Perform a link on the back file system.
16570Sstevel@tonic-gate  * Returns 0 or an error if could not perform operation.
16580Sstevel@tonic-gate  */
16590Sstevel@tonic-gate int
cachefs_io_link(vnode_t * vp,void * dinp,void * doutp)16600Sstevel@tonic-gate cachefs_io_link(vnode_t *vp, void *dinp, void *doutp)
16610Sstevel@tonic-gate {
16620Sstevel@tonic-gate 	vnode_t	*dvp = NULL;
16630Sstevel@tonic-gate 	vnode_t	*lvp = NULL;
16640Sstevel@tonic-gate 	vattr_t	va;
16650Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
16660Sstevel@tonic-gate 	int error = 0;
16670Sstevel@tonic-gate 	cred_t *cr = NULL;
16680Sstevel@tonic-gate 	fid_t *tmpfidp;
16690Sstevel@tonic-gate 	cachefsio_link_t *linkp = (cachefsio_link_t *)dinp;
16700Sstevel@tonic-gate 	cfs_timestruc_t *ctimep = (cfs_timestruc_t *)doutp;
16710Sstevel@tonic-gate 	CACHEFS_DECL(fid_t, tmpfid);
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 	/*
16740Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
16750Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
16760Sstevel@tonic-gate 	 */
16770Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
16780Sstevel@tonic-gate 
16790Sstevel@tonic-gate 	/* Get a vnode parent directory */
16800Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&linkp->ln_dirfid, &tmpfid, tmpfidp, fid_t);
16810Sstevel@tonic-gate 	CACHEFS_FID_COPYIN(&linkp->ln_dirfid, tmpfidp);
16820Sstevel@tonic-gate 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
16830Sstevel@tonic-gate 	if (error) {
16840Sstevel@tonic-gate 		dvp = NULL;
16850Sstevel@tonic-gate 		goto out;
16860Sstevel@tonic-gate 	}
16870Sstevel@tonic-gate 
16880Sstevel@tonic-gate 	/* Get a vnode file to link to */
16890Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&linkp->ln_filefid, &tmpfid, tmpfidp, fid_t);
16900Sstevel@tonic-gate 	CACHEFS_FID_COPYIN(&linkp->ln_filefid, tmpfidp);
16910Sstevel@tonic-gate 	error = VFS_VGET(fscp->fs_backvfsp, &lvp, tmpfidp);
16920Sstevel@tonic-gate 	if (error) {
16930Sstevel@tonic-gate 		lvp = NULL;
16940Sstevel@tonic-gate 		goto out;
16950Sstevel@tonic-gate 	}
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 	cr = conj_cred(&linkp->ln_cred);
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate 	/* do the link */
1700*5331Samw 	error = VOP_LINK(dvp, lvp, linkp->ln_name, cr, NULL, 0);
17010Sstevel@tonic-gate 	if (error)
17020Sstevel@tonic-gate 		goto out;
17030Sstevel@tonic-gate 
17040Sstevel@tonic-gate 	/* get the ctime */
17050Sstevel@tonic-gate 	va.va_mask = AT_ALL;
1706*5331Samw 	error = VOP_GETATTR(lvp, &va, 0, cr, NULL);
17070Sstevel@tonic-gate 	if (error)
17080Sstevel@tonic-gate 		goto out;
17090Sstevel@tonic-gate 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, ctimep, error);
17100Sstevel@tonic-gate 	if (error)
17110Sstevel@tonic-gate 		goto out;
17120Sstevel@tonic-gate 
17130Sstevel@tonic-gate 	cachefs_iosetneedattrs(fscp, &linkp->ln_cid);
17140Sstevel@tonic-gate out:
17150Sstevel@tonic-gate 	if (cr)
17160Sstevel@tonic-gate 		crfree(cr);
17170Sstevel@tonic-gate 	if (dvp)
17180Sstevel@tonic-gate 		VN_RELE(dvp);
17190Sstevel@tonic-gate 	if (lvp)
17200Sstevel@tonic-gate 		VN_RELE(lvp);
17210Sstevel@tonic-gate 	return (error);
17220Sstevel@tonic-gate }
17230Sstevel@tonic-gate 
17240Sstevel@tonic-gate /*
17250Sstevel@tonic-gate  * Rename the file on the back file system.
17260Sstevel@tonic-gate  * Returns 0 or an error if could not perform operation.
17270Sstevel@tonic-gate  */
17280Sstevel@tonic-gate int
cachefs_io_rename(vnode_t * vp,void * dinp,void * doutp)17290Sstevel@tonic-gate cachefs_io_rename(vnode_t *vp, void *dinp, void *doutp)
17300Sstevel@tonic-gate {
17310Sstevel@tonic-gate 	vnode_t	*odvp = NULL;
17320Sstevel@tonic-gate 	vnode_t	*ndvp = NULL;
17330Sstevel@tonic-gate 	cred_t *cr = NULL;
17340Sstevel@tonic-gate 	vnode_t	*cvp = NULL;
17350Sstevel@tonic-gate 	vattr_t va;
17360Sstevel@tonic-gate 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
17370Sstevel@tonic-gate 	int error = 0;
17380Sstevel@tonic-gate 	fid_t child_fid, *child_fidp;
17390Sstevel@tonic-gate 	cachefsio_rename_arg_t *rnp;
17400Sstevel@tonic-gate 	cachefsio_rename_return_t *retp;
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 	/*
17430Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
17440Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
17450Sstevel@tonic-gate 	 */
17460Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 	rnp = (cachefsio_rename_arg_t *)dinp;
17490Sstevel@tonic-gate 	retp = (cachefsio_rename_return_t *)doutp;
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate 	/* Get vnode of old parent directory */
17520Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&rnp->rn_olddir, &child_fid, child_fidp, fid_t);
17530Sstevel@tonic-gate 	CACHEFS_FID_COPYIN(&rnp->rn_olddir, child_fidp);
17540Sstevel@tonic-gate 	error = VFS_VGET(fscp->fs_backvfsp, &odvp, child_fidp);
17550Sstevel@tonic-gate 	if (error) {
17560Sstevel@tonic-gate 		odvp = NULL;
17570Sstevel@tonic-gate 		goto out;
17580Sstevel@tonic-gate 	}
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 	/* Get vnode of new parent directory */
17610Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&rnp->rn_newdir, &child_fid, child_fidp, fid_t);
17620Sstevel@tonic-gate 	CACHEFS_FID_COPYIN(&rnp->rn_newdir, child_fidp);
17630Sstevel@tonic-gate 	error = VFS_VGET(fscp->fs_backvfsp, &ndvp, child_fidp);
17640Sstevel@tonic-gate 	if (error) {
17650Sstevel@tonic-gate 		ndvp = NULL;
17660Sstevel@tonic-gate 		goto out;
17670Sstevel@tonic-gate 	}
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 	cr = conj_cred(&rnp->rn_cred);
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate 	/* if the caller wants the ctime of the target after deletion */
17720Sstevel@tonic-gate 	if (rnp->rn_del_getctime) {
17730Sstevel@tonic-gate 		error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0,
1774*5331Samw 		    NULL, cr, NULL, NULL, NULL);
17750Sstevel@tonic-gate 		if (error) {
17760Sstevel@tonic-gate 			cvp = NULL; /* paranoia */
17770Sstevel@tonic-gate 			goto out;
17780Sstevel@tonic-gate 		}
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 		child_fid.fid_len = MAXFIDSZ;
1781*5331Samw 		error = VOP_FID(cvp, &child_fid, NULL);
17820Sstevel@tonic-gate 		if (error)
17830Sstevel@tonic-gate 			goto out;
17840Sstevel@tonic-gate 		VN_RELE(cvp);
17850Sstevel@tonic-gate 		cvp = NULL;
17860Sstevel@tonic-gate 	}
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 	/* do the rename */
1789*5331Samw 	error = VOP_RENAME(odvp, rnp->rn_oldname, ndvp, rnp->rn_newname, cr,
1790*5331Samw 		NULL, 0);
17910Sstevel@tonic-gate 	if (error)
17920Sstevel@tonic-gate 		goto out;
17930Sstevel@tonic-gate 
17940Sstevel@tonic-gate 	/* get the new ctime on the renamed file */
1795*5331Samw 	error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0, NULL, cr,
1796*5331Samw 		NULL, NULL, NULL);
17970Sstevel@tonic-gate 	if (error)
17980Sstevel@tonic-gate 		goto out;
17990Sstevel@tonic-gate 
18000Sstevel@tonic-gate 	va.va_mask = AT_ALL;
1801*5331Samw 	error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
18020Sstevel@tonic-gate 	if (error)
18030Sstevel@tonic-gate 		goto out;
18040Sstevel@tonic-gate 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->rn_ctime, error);
18050Sstevel@tonic-gate 	VN_RELE(cvp);
18060Sstevel@tonic-gate 	cvp = NULL;
18070Sstevel@tonic-gate 	if (error)
18080Sstevel@tonic-gate 		goto out;
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate 	cachefs_iosetneedattrs(fscp, &rnp->rn_cid);
18110Sstevel@tonic-gate 
18120Sstevel@tonic-gate 	/* get the new ctime if requested of the deleted target */
18130Sstevel@tonic-gate 	if (rnp->rn_del_getctime) {
18140Sstevel@tonic-gate 		error = VFS_VGET(fscp->fs_backvfsp, &cvp, &child_fid);
18150Sstevel@tonic-gate 		if (error) {
18160Sstevel@tonic-gate 			cvp = NULL;
18170Sstevel@tonic-gate 			goto out;
18180Sstevel@tonic-gate 		}
18190Sstevel@tonic-gate 		va.va_mask = AT_ALL;
1820*5331Samw 		error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
18210Sstevel@tonic-gate 		if (error)
18220Sstevel@tonic-gate 			goto out;
18230Sstevel@tonic-gate 		CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->rn_del_ctime,
18240Sstevel@tonic-gate 			error);
18250Sstevel@tonic-gate 		VN_RELE(cvp);
18260Sstevel@tonic-gate 		cvp = NULL;
18270Sstevel@tonic-gate 		if (error)
18280Sstevel@tonic-gate 			goto out;
18290Sstevel@tonic-gate 		cachefs_iosetneedattrs(fscp, &rnp->rn_del_cid);
18300Sstevel@tonic-gate 	}
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate out:
18330Sstevel@tonic-gate 	if (cr)
18340Sstevel@tonic-gate 		crfree(cr);
18350Sstevel@tonic-gate 	if (cvp)
18360Sstevel@tonic-gate 		VN_RELE(cvp);
18370Sstevel@tonic-gate 	if (odvp)
18380Sstevel@tonic-gate 		VN_RELE(odvp);
18390Sstevel@tonic-gate 	if (ndvp)
18400Sstevel@tonic-gate 		VN_RELE(ndvp);
18410Sstevel@tonic-gate 	return (error);
18420Sstevel@tonic-gate }
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate /*
18450Sstevel@tonic-gate  * Make a directory on the backfs.
18460Sstevel@tonic-gate  * Returns 0 or an error if could not perform operation.
18470Sstevel@tonic-gate  */
18480Sstevel@tonic-gate int
cachefs_io_mkdir(vnode_t * vp,void * dinp,void * doutp)18490Sstevel@tonic-gate cachefs_io_mkdir(vnode_t *vp, void *dinp, void *doutp)
18500Sstevel@tonic-gate {
18510Sstevel@tonic-gate 	vnode_t	*dvp = NULL;
18520Sstevel@tonic-gate 	vnode_t	*cvp = NULL;
18530Sstevel@tonic-gate 	cnode_t *cp = NULL;
18540Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
18550Sstevel@tonic-gate 	int error = 0;
18560Sstevel@tonic-gate 	cred_t *cr = NULL;
18570Sstevel@tonic-gate 	fid_t	*tmpfidp;
18580Sstevel@tonic-gate 	vattr_t va, *tmpvap;
18590Sstevel@tonic-gate 	cachefsio_mkdir_t *mdirp = (cachefsio_mkdir_t *)dinp;
18600Sstevel@tonic-gate 	cfs_fid_t *fidp = (cfs_fid_t *)doutp;
18610Sstevel@tonic-gate 	CACHEFS_DECL(fid_t, tmpfid);
18620Sstevel@tonic-gate 
18630Sstevel@tonic-gate 	/*
18640Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
18650Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
18660Sstevel@tonic-gate 	 */
18670Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 	/* Get vnode of parent directory */
18700Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&mdirp->md_dirfid, &tmpfid, tmpfidp, fid_t);
18710Sstevel@tonic-gate 	CACHEFS_FID_COPYIN(&mdirp->md_dirfid, tmpfidp);
18720Sstevel@tonic-gate 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
18730Sstevel@tonic-gate 	if (error) {
18740Sstevel@tonic-gate 		dvp = NULL;
18750Sstevel@tonic-gate 		goto out;
18760Sstevel@tonic-gate 	}
18770Sstevel@tonic-gate 
18780Sstevel@tonic-gate 	cr = conj_cred(&mdirp->md_cred);
18790Sstevel@tonic-gate 
18800Sstevel@tonic-gate 	/* make the directory */
18810Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&mdirp->md_vattr, &va, tmpvap, vattr_t);
18820Sstevel@tonic-gate 	CACHEFS_VATTR_COPYIN(&mdirp->md_vattr, tmpvap);
1883*5331Samw 	error = VOP_MKDIR(dvp, mdirp->md_name, tmpvap, &cvp, cr, NULL, 0, NULL);
18840Sstevel@tonic-gate 	if (error) {
18850Sstevel@tonic-gate 		if (error != EEXIST)
18860Sstevel@tonic-gate 			goto out;
18870Sstevel@tonic-gate 
18880Sstevel@tonic-gate 		/* if the directory already exists, then use it */
18890Sstevel@tonic-gate 		error = VOP_LOOKUP(dvp, mdirp->md_name, &cvp,
1890*5331Samw 		    NULL, 0, NULL, cr, NULL, NULL, NULL);
18910Sstevel@tonic-gate 		if (error) {
18920Sstevel@tonic-gate 			cvp = NULL;
18930Sstevel@tonic-gate 			goto out;
18940Sstevel@tonic-gate 		}
18950Sstevel@tonic-gate 		if (cvp->v_type != VDIR) {
18960Sstevel@tonic-gate 			error = EINVAL;
18970Sstevel@tonic-gate 			goto out;
18980Sstevel@tonic-gate 		}
18990Sstevel@tonic-gate 	}
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate 	/* get the fid of the directory */
19020Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(fidp, &tmpfid, tmpfidp, fid_t);
19030Sstevel@tonic-gate 	tmpfidp->fid_len = MAXFIDSZ;
1904*5331Samw 	error = VOP_FID(cvp, tmpfidp, NULL);
19050Sstevel@tonic-gate 	if (error)
19060Sstevel@tonic-gate 		goto out;
19070Sstevel@tonic-gate 	CACHEFS_FID_COPYOUT(tmpfidp, fidp);
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	/* get attributes of the directory */
19100Sstevel@tonic-gate 	va.va_mask = AT_ALL;
1911*5331Samw 	error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
19120Sstevel@tonic-gate 	if (error)
19130Sstevel@tonic-gate 		goto out;
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate 	/* update the cnode for this dir with the new fid */
19160Sstevel@tonic-gate 	error = cachefs_cnode_make(&mdirp->md_cid, fscp,
19170Sstevel@tonic-gate 	    NULL, NULL, NULL, cr, 0, &cp);
19180Sstevel@tonic-gate 	if (error) {
19190Sstevel@tonic-gate 		error = 0;
19200Sstevel@tonic-gate 		goto out;
19210Sstevel@tonic-gate 	}
19220Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
19230Sstevel@tonic-gate 	ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL);
19240Sstevel@tonic-gate 	cp->c_metadata.md_cookie = *tmpfidp;
19250Sstevel@tonic-gate 	cp->c_metadata.md_flags |= MD_CREATEDONE;
19260Sstevel@tonic-gate 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
19270Sstevel@tonic-gate 	cp->c_attr.va_nodeid = va.va_nodeid;
19280Sstevel@tonic-gate 	cp->c_flags |= CN_UPDATED;
19290Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
19300Sstevel@tonic-gate out:
19310Sstevel@tonic-gate 	if (cr)
19320Sstevel@tonic-gate 		crfree(cr);
19330Sstevel@tonic-gate 	if (dvp)
19340Sstevel@tonic-gate 		VN_RELE(dvp);
19350Sstevel@tonic-gate 	if (cvp)
19360Sstevel@tonic-gate 		VN_RELE(cvp);
19370Sstevel@tonic-gate 	if (cp)
19380Sstevel@tonic-gate 		VN_RELE(CTOV(cp));
19390Sstevel@tonic-gate 	return (error);
19400Sstevel@tonic-gate }
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate /*
19430Sstevel@tonic-gate  * Perform a rmdir on the back file system.
19440Sstevel@tonic-gate  * Returns 0 or an error if could not perform operation.
19450Sstevel@tonic-gate  */
19460Sstevel@tonic-gate int
19470Sstevel@tonic-gate /*ARGSUSED*/
cachefs_io_rmdir(vnode_t * vp,void * dinp,void * doutp)19480Sstevel@tonic-gate cachefs_io_rmdir(vnode_t *vp, void *dinp, void *doutp)
19490Sstevel@tonic-gate {
19500Sstevel@tonic-gate 	vnode_t	*dvp = NULL;
19510Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
19520Sstevel@tonic-gate 	int error;
19530Sstevel@tonic-gate 	cred_t *cr;
19540Sstevel@tonic-gate 	fid_t	*tmpfidp;
19550Sstevel@tonic-gate 	cachefsio_rmdir_t *rdp = (cachefsio_rmdir_t *)dinp;
19560Sstevel@tonic-gate 	CACHEFS_DECL(fid_t, tmpfid);
19570Sstevel@tonic-gate 
19580Sstevel@tonic-gate 	/*
19590Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
19600Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
19610Sstevel@tonic-gate 	 */
19620Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
19630Sstevel@tonic-gate 
19640Sstevel@tonic-gate 	/* Get a vnode for the back file */
19650Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&rdp->rd_dirfid, &tmpfid, tmpfidp, fid_t);
19660Sstevel@tonic-gate 	CACHEFS_FID_COPYIN(&rdp->rd_dirfid, tmpfidp);
19670Sstevel@tonic-gate 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
19680Sstevel@tonic-gate 	if (error) {
19690Sstevel@tonic-gate 		dvp = NULL;
19700Sstevel@tonic-gate 		return (error);
19710Sstevel@tonic-gate 	}
19720Sstevel@tonic-gate 
19730Sstevel@tonic-gate 	cr = conj_cred(&rdp->rd_cred);
1974*5331Samw 	error = VOP_RMDIR(dvp, rdp->rd_name, dvp, cr, NULL, 0);
19750Sstevel@tonic-gate 	crfree(cr);
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate 	VN_RELE(dvp);
19780Sstevel@tonic-gate 	return (error);
19790Sstevel@tonic-gate }
19800Sstevel@tonic-gate 
19810Sstevel@tonic-gate /*
19820Sstevel@tonic-gate  * create a symlink on the back file system
19830Sstevel@tonic-gate  * Returns 0 or an error if could not perform operation.
19840Sstevel@tonic-gate  */
19850Sstevel@tonic-gate int
cachefs_io_symlink(vnode_t * vp,void * dinp,void * doutp)19860Sstevel@tonic-gate cachefs_io_symlink(vnode_t *vp, void *dinp, void *doutp)
19870Sstevel@tonic-gate {
19880Sstevel@tonic-gate 	vnode_t	*dvp = NULL;
19890Sstevel@tonic-gate 	vnode_t	*svp = NULL;
19900Sstevel@tonic-gate 	cnode_t *cp = NULL;
19910Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
19920Sstevel@tonic-gate 	fid_t	*tmpfidp;
19930Sstevel@tonic-gate 	vattr_t	va, *tmpvap;
19940Sstevel@tonic-gate 	int error = 0;
19950Sstevel@tonic-gate 	cred_t *cr = NULL;
19960Sstevel@tonic-gate 	cachefsio_symlink_arg_t *symp;
19970Sstevel@tonic-gate 	cachefsio_symlink_return_t *retp;
19980Sstevel@tonic-gate 	CACHEFS_DECL(fid_t, tmpfid);
19990Sstevel@tonic-gate 
20000Sstevel@tonic-gate 	/*
20010Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
20020Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
20030Sstevel@tonic-gate 	 */
20040Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
20050Sstevel@tonic-gate 
20060Sstevel@tonic-gate 	symp = (cachefsio_symlink_arg_t *)dinp;
20070Sstevel@tonic-gate 	retp = (cachefsio_symlink_return_t *)doutp;
20080Sstevel@tonic-gate 
20090Sstevel@tonic-gate 	/* get a vnode for the back directory */
20100Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&symp->sy_dirfid, &tmpfid, tmpfidp, fid_t);
20110Sstevel@tonic-gate 	CACHEFS_FID_COPYIN(&symp->sy_dirfid, tmpfidp);
20120Sstevel@tonic-gate 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
20130Sstevel@tonic-gate 	if (error) {
20140Sstevel@tonic-gate 		dvp = NULL;
20150Sstevel@tonic-gate 		goto out;
20160Sstevel@tonic-gate 	}
20170Sstevel@tonic-gate 
20180Sstevel@tonic-gate 	cr = conj_cred(&symp->sy_cred);
20190Sstevel@tonic-gate 
20200Sstevel@tonic-gate 	/* create the symlink */
20210Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&symp->sy_vattr, &va, tmpvap, vattr_t);
20220Sstevel@tonic-gate 	CACHEFS_VATTR_COPYIN(&symp->sy_vattr, tmpvap);
20230Sstevel@tonic-gate 	error = VOP_SYMLINK(dvp, symp->sy_name, tmpvap,
2024*5331Samw 	    symp->sy_link, cr, NULL, 0);
20250Sstevel@tonic-gate 	if (error)
20260Sstevel@tonic-gate 		goto out;
20270Sstevel@tonic-gate 
20280Sstevel@tonic-gate 	/* get the vnode for the symlink */
2029*5331Samw 	error = VOP_LOOKUP(dvp, symp->sy_name, &svp, NULL, 0, NULL, cr,
2030*5331Samw 		NULL, NULL, NULL);
20310Sstevel@tonic-gate 	if (error)
20320Sstevel@tonic-gate 		goto out;
20330Sstevel@tonic-gate 
20340Sstevel@tonic-gate 	/* get the attributes of the symlink */
20350Sstevel@tonic-gate 	va.va_mask = AT_ALL;
2036*5331Samw 	error = VOP_GETATTR(svp, &va, 0, cr, NULL);
20370Sstevel@tonic-gate 	if (error)
20380Sstevel@tonic-gate 		goto out;
20390Sstevel@tonic-gate 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sy_ctime, error);
20400Sstevel@tonic-gate 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sy_mtime, error);
20410Sstevel@tonic-gate 	if (error)
20420Sstevel@tonic-gate 		goto out;
20430Sstevel@tonic-gate 
20440Sstevel@tonic-gate 	/* get the fid */
20450Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&retp->sy_newfid, &tmpfid, tmpfidp, fid_t);
20460Sstevel@tonic-gate 	tmpfidp->fid_len = MAXFIDSZ;
2047*5331Samw 	error = VOP_FID(svp, tmpfidp, NULL);
20480Sstevel@tonic-gate 	if (error)
20490Sstevel@tonic-gate 		goto out;
20500Sstevel@tonic-gate 	CACHEFS_FID_COPYOUT(tmpfidp, &retp->sy_newfid);
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate 	/* update the cnode for this file with the new info */
20530Sstevel@tonic-gate 	error = cachefs_cnode_make(&symp->sy_cid, fscp,
20540Sstevel@tonic-gate 	    NULL, NULL, NULL, cr, 0, &cp);
20550Sstevel@tonic-gate 	if (error) {
20560Sstevel@tonic-gate 		error = 0;
20570Sstevel@tonic-gate 		goto out;
20580Sstevel@tonic-gate 	}
20590Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
20600Sstevel@tonic-gate 	ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL);
20610Sstevel@tonic-gate 	cp->c_metadata.md_cookie = *tmpfidp;
20620Sstevel@tonic-gate 	cp->c_metadata.md_flags |= MD_CREATEDONE;
20630Sstevel@tonic-gate 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
20640Sstevel@tonic-gate 	cp->c_attr.va_nodeid = va.va_nodeid;
20650Sstevel@tonic-gate 	cp->c_flags |= CN_UPDATED;
20660Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
20670Sstevel@tonic-gate 
20680Sstevel@tonic-gate out:
20690Sstevel@tonic-gate 	if (cr)
20700Sstevel@tonic-gate 		crfree(cr);
20710Sstevel@tonic-gate 	if (dvp)
20720Sstevel@tonic-gate 		VN_RELE(dvp);
20730Sstevel@tonic-gate 	if (svp)
20740Sstevel@tonic-gate 		VN_RELE(svp);
20750Sstevel@tonic-gate 	if (cp)
20760Sstevel@tonic-gate 		VN_RELE(CTOV(cp));
20770Sstevel@tonic-gate 	return (error);
20780Sstevel@tonic-gate }
20790Sstevel@tonic-gate 
20800Sstevel@tonic-gate /*
20810Sstevel@tonic-gate  * Perform setattr on the back file system.
20820Sstevel@tonic-gate  * Returns 0 or an error if could not perform operation.
20830Sstevel@tonic-gate  */
20840Sstevel@tonic-gate int
cachefs_io_setattr(vnode_t * vp,void * dinp,void * doutp)20850Sstevel@tonic-gate cachefs_io_setattr(vnode_t *vp, void *dinp, void *doutp)
20860Sstevel@tonic-gate {
20870Sstevel@tonic-gate 	vnode_t	*cvp = NULL;
20880Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
20890Sstevel@tonic-gate 	fid_t	*tmpfidp;
20900Sstevel@tonic-gate 	vattr_t	va, *tmpvap;
20910Sstevel@tonic-gate 	int error = 0;
20920Sstevel@tonic-gate 	cred_t *cr = NULL;
20930Sstevel@tonic-gate 	cachefsio_setattr_arg_t *sap;
20940Sstevel@tonic-gate 	cachefsio_setattr_return_t *retp;
20950Sstevel@tonic-gate 	CACHEFS_DECL(fid_t, tmpfid);
20960Sstevel@tonic-gate 
20970Sstevel@tonic-gate 	/*
20980Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
20990Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
21000Sstevel@tonic-gate 	 */
21010Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
21020Sstevel@tonic-gate 
21030Sstevel@tonic-gate 	sap = (cachefsio_setattr_arg_t *)dinp;
21040Sstevel@tonic-gate 	retp = (cachefsio_setattr_return_t *)doutp;
21050Sstevel@tonic-gate 
21060Sstevel@tonic-gate 	/* get a vnode for the back directory */
21070Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&sap->sa_backfid, &tmpfid, tmpfidp, fid_t);
21080Sstevel@tonic-gate 	CACHEFS_FID_COPYIN(&sap->sa_backfid, tmpfidp);
21090Sstevel@tonic-gate 	error = VFS_VGET(fscp->fs_backvfsp, &cvp, tmpfidp);
21100Sstevel@tonic-gate 	if (error) {
21110Sstevel@tonic-gate 		cvp = NULL;
21120Sstevel@tonic-gate 		goto out;
21130Sstevel@tonic-gate 	}
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 	cr = conj_cred(&sap->sa_cred);
21160Sstevel@tonic-gate 
21170Sstevel@tonic-gate 	/* perform the setattr */
21180Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&sap->sa_vattr, &va, tmpvap, vattr_t);
21190Sstevel@tonic-gate 	CACHEFS_VATTR_COPYIN(&sap->sa_vattr, tmpvap);
21200Sstevel@tonic-gate 	error = VOP_SETATTR(cvp, tmpvap, 0, cr, NULL);
21210Sstevel@tonic-gate 	if (error)
21220Sstevel@tonic-gate 		goto out;
21230Sstevel@tonic-gate 
21240Sstevel@tonic-gate 	/* get the new ctime and mtime */
21250Sstevel@tonic-gate 	va.va_mask = AT_ALL;
2126*5331Samw 	error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
21270Sstevel@tonic-gate 	if (error)
21280Sstevel@tonic-gate 		goto out;
21290Sstevel@tonic-gate 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sa_ctime, error);
21300Sstevel@tonic-gate 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sa_mtime, error);
21310Sstevel@tonic-gate 	if (error)
21320Sstevel@tonic-gate 		goto out;
21330Sstevel@tonic-gate 
21340Sstevel@tonic-gate 	cachefs_iosetneedattrs(fscp, &sap->sa_cid);
21350Sstevel@tonic-gate out:
21360Sstevel@tonic-gate 	if (cr)
21370Sstevel@tonic-gate 		crfree(cr);
21380Sstevel@tonic-gate 	if (cvp)
21390Sstevel@tonic-gate 		VN_RELE(cvp);
21400Sstevel@tonic-gate 	return (error);
21410Sstevel@tonic-gate }
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate int
cachefs_io_setsecattr(vnode_t * vp,void * dinp,void * doutp)21440Sstevel@tonic-gate cachefs_io_setsecattr(vnode_t *vp, void *dinp, void *doutp)
21450Sstevel@tonic-gate {
21460Sstevel@tonic-gate 	int error = 0;
21470Sstevel@tonic-gate 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
21480Sstevel@tonic-gate 	vnode_t *tvp = NULL;
21490Sstevel@tonic-gate 	vsecattr_t vsec;
21500Sstevel@tonic-gate 	vattr_t va;
21510Sstevel@tonic-gate 	cred_t *cr = NULL;
21520Sstevel@tonic-gate 	fid_t	*tmpfidp;
21530Sstevel@tonic-gate 	cachefsio_setsecattr_arg_t *ssap;
21540Sstevel@tonic-gate 	cachefsio_setsecattr_return_t *retp;
21550Sstevel@tonic-gate 	CACHEFS_DECL(fid_t, tmpfid);
21560Sstevel@tonic-gate 
21570Sstevel@tonic-gate 	/*
21580Sstevel@tonic-gate 	 * Only called in support of disconnectable operation, so assert
21590Sstevel@tonic-gate 	 * that this is not called when NFSv4 is the backfilesytem.
21600Sstevel@tonic-gate 	 */
21610Sstevel@tonic-gate 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
21620Sstevel@tonic-gate 
21630Sstevel@tonic-gate 	ssap = (cachefsio_setsecattr_arg_t *)dinp;
21640Sstevel@tonic-gate 	retp = (cachefsio_setsecattr_return_t *)doutp;
21650Sstevel@tonic-gate 
21660Sstevel@tonic-gate 	/* get vnode of back file to do VOP_SETSECATTR to */
21670Sstevel@tonic-gate 	CACHEFS_TMPPTR_SET(&ssap->sc_backfid, &tmpfid, tmpfidp, fid_t);
21680Sstevel@tonic-gate 	CACHEFS_FID_COPYIN(&ssap->sc_backfid, tmpfidp);
21690Sstevel@tonic-gate 	error = VFS_VGET(fscp->fs_backvfsp, &tvp, tmpfidp);
21700Sstevel@tonic-gate 	if (error != 0) {
21710Sstevel@tonic-gate 		tvp = NULL;
21720Sstevel@tonic-gate 		goto out;
21730Sstevel@tonic-gate 	}
21740Sstevel@tonic-gate 
21750Sstevel@tonic-gate 	/* get the creds */
21760Sstevel@tonic-gate 	cr = conj_cred(&ssap->sc_cred);
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate 	/* form the vsecattr_t */
21790Sstevel@tonic-gate 	vsec.vsa_mask = ssap->sc_mask;
21800Sstevel@tonic-gate 	vsec.vsa_aclcnt = ssap->sc_aclcnt;
21810Sstevel@tonic-gate 	vsec.vsa_dfaclcnt = ssap->sc_dfaclcnt;
21820Sstevel@tonic-gate 	vsec.vsa_aclentp = ssap->sc_acl;
21830Sstevel@tonic-gate 	vsec.vsa_dfaclentp = ssap->sc_acl + ssap->sc_aclcnt;
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate 	/* set the ACL */
21860Sstevel@tonic-gate 	(void) VOP_RWLOCK(tvp, V_WRITELOCK_TRUE, NULL);
2187*5331Samw 	error = VOP_SETSECATTR(tvp, &vsec, 0, cr, NULL);
21880Sstevel@tonic-gate 	VOP_RWUNLOCK(tvp, V_WRITELOCK_TRUE, NULL);
21890Sstevel@tonic-gate 	if (error != 0)
21900Sstevel@tonic-gate 		goto out;
21910Sstevel@tonic-gate 
21920Sstevel@tonic-gate 	/* get the new ctime and mtime */
21930Sstevel@tonic-gate 	va.va_mask = AT_ALL;
2194*5331Samw 	error = VOP_GETATTR(tvp, &va, 0, cr, NULL);
21950Sstevel@tonic-gate 	if (error)
21960Sstevel@tonic-gate 		goto out;
21970Sstevel@tonic-gate 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sc_ctime, error);
21980Sstevel@tonic-gate 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sc_mtime, error);
21990Sstevel@tonic-gate 	if (error)
22000Sstevel@tonic-gate 		goto out;
22010Sstevel@tonic-gate 
22020Sstevel@tonic-gate 	cachefs_iosetneedattrs(fscp, &ssap->sc_cid);
22030Sstevel@tonic-gate out:
22040Sstevel@tonic-gate 
22050Sstevel@tonic-gate 	if (cr != NULL)
22060Sstevel@tonic-gate 		crfree(cr);
22070Sstevel@tonic-gate 	if (tvp != NULL)
22080Sstevel@tonic-gate 		VN_RELE(tvp);
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate 	return (error);
22110Sstevel@tonic-gate }
22120Sstevel@tonic-gate 
22130Sstevel@tonic-gate static void
sync_metadata(cnode_t * cp)22140Sstevel@tonic-gate sync_metadata(cnode_t *cp)
22150Sstevel@tonic-gate {
22160Sstevel@tonic-gate 	if (cp->c_flags & (CN_STALE | CN_DESTROY))
22170Sstevel@tonic-gate 		return;
22180Sstevel@tonic-gate 	(void) cachefs_sync_metadata(cp);
22190Sstevel@tonic-gate }
22200Sstevel@tonic-gate 
22210Sstevel@tonic-gate static void
drop_backvp(cnode_t * cp)22220Sstevel@tonic-gate drop_backvp(cnode_t *cp)
22230Sstevel@tonic-gate {
22240Sstevel@tonic-gate 	if (cp->c_backvp) {
22250Sstevel@tonic-gate 		mutex_enter(&cp->c_statelock);
22260Sstevel@tonic-gate 		if (cp->c_backvp) {
22270Sstevel@tonic-gate 			/* dump any pages, may be a dirty one */
22280Sstevel@tonic-gate 			(void) VOP_PUTPAGE(cp->c_backvp, (offset_t)0, 0,
2229*5331Samw 			    B_INVAL | B_TRUNC, kcred, NULL);
22300Sstevel@tonic-gate 		}
22310Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
22320Sstevel@tonic-gate 	}
22330Sstevel@tonic-gate }
22340Sstevel@tonic-gate 
22350Sstevel@tonic-gate static void
allow_pendrm(cnode_t * cp)22360Sstevel@tonic-gate allow_pendrm(cnode_t *cp)
22370Sstevel@tonic-gate {
22380Sstevel@tonic-gate 	if (cp->c_flags & CN_PENDRM) {
22390Sstevel@tonic-gate 		mutex_enter(&cp->c_statelock);
22400Sstevel@tonic-gate 		if (cp->c_flags & CN_PENDRM) {
22410Sstevel@tonic-gate 			cp->c_flags &= ~CN_PENDRM;
22420Sstevel@tonic-gate 			VN_RELE(CTOV(cp));
22430Sstevel@tonic-gate 		}
22440Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
22450Sstevel@tonic-gate 	}
22460Sstevel@tonic-gate }
22470Sstevel@tonic-gate 
22480Sstevel@tonic-gate static void
cachefs_modified_fix(fscache_t * fscp)22490Sstevel@tonic-gate cachefs_modified_fix(fscache_t *fscp)
22500Sstevel@tonic-gate {
22510Sstevel@tonic-gate 	cnode_t *cp;
22520Sstevel@tonic-gate 	int error = 0;
22530Sstevel@tonic-gate 	rl_entry_t rl_ent;
22540Sstevel@tonic-gate 	cfs_cid_t cid;
22550Sstevel@tonic-gate 	cachefscache_t *cachep = fscp->fs_cache;
22560Sstevel@tonic-gate 	enum cachefs_rl_type type;
22570Sstevel@tonic-gate 	cachefs_metadata_t *mdp;
22580Sstevel@tonic-gate 	int timedout = 0;
22590Sstevel@tonic-gate 	struct vattr va;
22600Sstevel@tonic-gate 
22610Sstevel@tonic-gate 	/* XXX just return if fs is in error ro mode */
22620Sstevel@tonic-gate 
22630Sstevel@tonic-gate 	/* lock out other users of the MF list */
22640Sstevel@tonic-gate 	mutex_enter(&cachep->c_mflock);
22650Sstevel@tonic-gate 
22660Sstevel@tonic-gate 	/* move the modified entries for this file system to the MF list */
22670Sstevel@tonic-gate 	cachefs_move_modified_to_mf(cachep, fscp);
22680Sstevel@tonic-gate 
22690Sstevel@tonic-gate 	rl_ent.rl_current = CACHEFS_RL_MF;
22700Sstevel@tonic-gate 	for (;;) {
22710Sstevel@tonic-gate 		/* get the next entry on the MF list */
22720Sstevel@tonic-gate 		error = cachefs_rlent_data(cachep, &rl_ent, NULL);
22730Sstevel@tonic-gate 		if (error) {
22740Sstevel@tonic-gate 			error = 0;
22750Sstevel@tonic-gate 			break;
22760Sstevel@tonic-gate 		}
22770Sstevel@tonic-gate 		ASSERT(fscp->fs_cfsid == rl_ent.rl_fsid);
22780Sstevel@tonic-gate 
22790Sstevel@tonic-gate 		/* get the cnode for the file */
22800Sstevel@tonic-gate 		cid.cid_fileno = rl_ent.rl_fileno;
22810Sstevel@tonic-gate 		cid.cid_flags = rl_ent.rl_local ? CFS_CID_LOCAL : 0;
22820Sstevel@tonic-gate 		error = cachefs_cnode_make(&cid, fscp,
22830Sstevel@tonic-gate 		    NULL, NULL, NULL, kcred, 0, &cp);
22840Sstevel@tonic-gate 		if (error) {
22850Sstevel@tonic-gate #ifdef CFSDEBUG
22860Sstevel@tonic-gate 			CFS_DEBUG(CFSDEBUG_IOCTL)
22870Sstevel@tonic-gate 				printf("cachefs: mf: could not find %llu\n",
22880Sstevel@tonic-gate 				    (u_longlong_t)cid.cid_fileno);
22890Sstevel@tonic-gate 			delay(5*hz);
22900Sstevel@tonic-gate #endif
22910Sstevel@tonic-gate 			/* XXX this will loop forever, maybe put fs in */
22920Sstevel@tonic-gate 			/*   ro mode */
22930Sstevel@tonic-gate 			continue;
22940Sstevel@tonic-gate 		}
22950Sstevel@tonic-gate 
22960Sstevel@tonic-gate 		mutex_enter(&cp->c_statelock);
22970Sstevel@tonic-gate 
22980Sstevel@tonic-gate 		mdp = &cp->c_metadata;
22990Sstevel@tonic-gate 
23000Sstevel@tonic-gate 		/* if a regular file that has not been pushed */
23010Sstevel@tonic-gate 		if ((cp->c_attr.va_type == VREG) &&
23020Sstevel@tonic-gate 		    (((mdp->md_flags & (MD_PUSHDONE | MD_PUTPAGE)) ==
23030Sstevel@tonic-gate 		    MD_PUTPAGE))) {
23040Sstevel@tonic-gate 			/* move the file to lost+found */
23050Sstevel@tonic-gate 			error = cachefs_cnode_lostfound(cp, NULL);
23060Sstevel@tonic-gate 			if (error) {
23070Sstevel@tonic-gate 				/* XXX put fs in ro mode */
23080Sstevel@tonic-gate 				/* XXX need to drain MF list */
23090Sstevel@tonic-gate 				panic("lostfound failed %d", error);
23100Sstevel@tonic-gate 			}
23110Sstevel@tonic-gate 			mutex_exit(&cp->c_statelock);
23120Sstevel@tonic-gate 			VN_RELE(CTOV(cp));
23130Sstevel@tonic-gate 			continue;
23140Sstevel@tonic-gate 		}
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate 		/* if a local file */
23170Sstevel@tonic-gate 		if (cp->c_id.cid_flags & CFS_CID_LOCAL) {
23180Sstevel@tonic-gate 			/* if the file was not created */
23190Sstevel@tonic-gate 			if ((cp->c_metadata.md_flags & MD_CREATEDONE) == 0) {
23200Sstevel@tonic-gate 				/* do not allow cnode to be used */
23210Sstevel@tonic-gate 				cachefs_cnode_stale(cp);
23220Sstevel@tonic-gate 				mutex_exit(&cp->c_statelock);
23230Sstevel@tonic-gate 				VN_RELE(CTOV(cp));
23240Sstevel@tonic-gate 				continue;
23250Sstevel@tonic-gate 			}
23260Sstevel@tonic-gate 
23270Sstevel@tonic-gate 			/* save the local fileno for later getattrs */
23280Sstevel@tonic-gate 			mdp->md_localfileno = cp->c_id.cid_fileno;
23290Sstevel@tonic-gate 			mutex_exit(&cp->c_statelock);
23300Sstevel@tonic-gate 
23310Sstevel@tonic-gate 			/* register the mapping from old to new fileno */
23320Sstevel@tonic-gate 			mutex_enter(&fscp->fs_fslock);
23330Sstevel@tonic-gate 			cachefs_inum_register(fscp, cp->c_attr.va_nodeid,
23340Sstevel@tonic-gate 			    mdp->md_localfileno);
23350Sstevel@tonic-gate 			cachefs_inum_register(fscp, mdp->md_localfileno, 0);
23360Sstevel@tonic-gate 			mutex_exit(&fscp->fs_fslock);
23370Sstevel@tonic-gate 
23380Sstevel@tonic-gate 			/* move to new location in the cache */
23390Sstevel@tonic-gate 			cachefs_cnode_move(cp);
23400Sstevel@tonic-gate 			mutex_enter(&cp->c_statelock);
23410Sstevel@tonic-gate 		}
23420Sstevel@tonic-gate 
23430Sstevel@tonic-gate 		/* else if a modified file that needs to have its mode fixed */
23440Sstevel@tonic-gate 		else if ((cp->c_metadata.md_flags & MD_FILE) &&
23450Sstevel@tonic-gate 		    (cp->c_attr.va_type == VREG)) {
23460Sstevel@tonic-gate 
23470Sstevel@tonic-gate 			if (cp->c_frontvp == NULL)
23480Sstevel@tonic-gate 				(void) cachefs_getfrontfile(cp);
23490Sstevel@tonic-gate 			if (cp->c_frontvp) {
23500Sstevel@tonic-gate 				/* mark file as no longer modified */
23510Sstevel@tonic-gate 				va.va_mode = 0666;
23520Sstevel@tonic-gate 				va.va_mask = AT_MODE;
23530Sstevel@tonic-gate 				error = VOP_SETATTR(cp->c_frontvp, &va,
23540Sstevel@tonic-gate 				    0, kcred, NULL);
23550Sstevel@tonic-gate 				if (error) {
23560Sstevel@tonic-gate 					cmn_err(CE_WARN,
23570Sstevel@tonic-gate 					    "Cannot change ff mode.\n");
23580Sstevel@tonic-gate 				}
23590Sstevel@tonic-gate 			}
23600Sstevel@tonic-gate 		}
23610Sstevel@tonic-gate 
23620Sstevel@tonic-gate 
23630Sstevel@tonic-gate 		/* if there is a rl entry, put it on the correct list */
23640Sstevel@tonic-gate 		if (mdp->md_rlno) {
23650Sstevel@tonic-gate 			if (mdp->md_flags & MD_PACKED) {
23660Sstevel@tonic-gate 				if ((mdp->md_flags & MD_POPULATED) ||
23670Sstevel@tonic-gate 				    ((mdp->md_flags & MD_FILE) == 0))
23680Sstevel@tonic-gate 					type = CACHEFS_RL_PACKED;
23690Sstevel@tonic-gate 				else
23700Sstevel@tonic-gate 					type = CACHEFS_RL_PACKED_PENDING;
23710Sstevel@tonic-gate 				cachefs_rlent_moveto(fscp->fs_cache, type,
23720Sstevel@tonic-gate 				    mdp->md_rlno, mdp->md_frontblks);
23730Sstevel@tonic-gate 				mdp->md_rltype = type;
23740Sstevel@tonic-gate 			} else if (mdp->md_flags & MD_FILE) {
23750Sstevel@tonic-gate 				type = CACHEFS_RL_ACTIVE;
23760Sstevel@tonic-gate 				cachefs_rlent_moveto(fscp->fs_cache, type,
23770Sstevel@tonic-gate 				    mdp->md_rlno, mdp->md_frontblks);
23780Sstevel@tonic-gate 				mdp->md_rltype = type;
23790Sstevel@tonic-gate 			} else {
23800Sstevel@tonic-gate 				type = CACHEFS_RL_FREE;
23810Sstevel@tonic-gate 				cachefs_rlent_moveto(fscp->fs_cache, type,
23820Sstevel@tonic-gate 				    mdp->md_rlno, 0);
23830Sstevel@tonic-gate 				filegrp_ffrele(cp->c_filegrp);
23840Sstevel@tonic-gate 				mdp->md_rlno = 0;
23850Sstevel@tonic-gate 				mdp->md_rltype = CACHEFS_RL_NONE;
23860Sstevel@tonic-gate 			}
23870Sstevel@tonic-gate 		}
23880Sstevel@tonic-gate 		mdp->md_flags &= ~(MD_CREATEDONE | MD_PUTPAGE |
23890Sstevel@tonic-gate 		    MD_PUSHDONE | MD_MAPPING);
23900Sstevel@tonic-gate 
23910Sstevel@tonic-gate 		/* if a directory, populate it */
23920Sstevel@tonic-gate 		if (CTOV(cp)->v_type == VDIR) {
23930Sstevel@tonic-gate 			/* XXX hack for now */
23940Sstevel@tonic-gate 			mdp->md_flags |= MD_INVALREADDIR;
23950Sstevel@tonic-gate 			dnlc_purge_vp(CTOV(cp));
23960Sstevel@tonic-gate 
23970Sstevel@tonic-gate 			mdp->md_flags |= MD_NEEDATTRS;
23980Sstevel@tonic-gate 		}
23990Sstevel@tonic-gate 
24000Sstevel@tonic-gate 		if (!timedout) {
24010Sstevel@tonic-gate 			error = CFSOP_CHECK_COBJECT(fscp, cp, 0, kcred);
24020Sstevel@tonic-gate 			if (CFS_TIMEOUT(fscp, error))
24030Sstevel@tonic-gate 				timedout = 1;
24040Sstevel@tonic-gate 			else if ((error == 0) &&
24050Sstevel@tonic-gate 			    ((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0)) {
24060Sstevel@tonic-gate 				if (cachefs_vtype_aclok(CTOV(cp)) &&
24070Sstevel@tonic-gate 				    ((cp->c_flags & CN_NOCACHE) == 0))
24080Sstevel@tonic-gate 					(void) cachefs_cacheacl(cp, NULL);
24090Sstevel@tonic-gate 			}
24100Sstevel@tonic-gate 		}
24110Sstevel@tonic-gate 
24120Sstevel@tonic-gate 		cp->c_flags |= CN_UPDATED;
24130Sstevel@tonic-gate 		mutex_exit(&cp->c_statelock);
24140Sstevel@tonic-gate 		VN_RELE(CTOV(cp));
24150Sstevel@tonic-gate 	}
24160Sstevel@tonic-gate 	mutex_exit(&cachep->c_mflock);
24170Sstevel@tonic-gate }
24180Sstevel@tonic-gate 
24190Sstevel@tonic-gate void
cachefs_inum_register(fscache_t * fscp,ino64_t real,ino64_t fake)24200Sstevel@tonic-gate cachefs_inum_register(fscache_t *fscp, ino64_t real, ino64_t fake)
24210Sstevel@tonic-gate {
24220Sstevel@tonic-gate 	cachefs_inum_trans_t *tbl;
24230Sstevel@tonic-gate 	int toff, thop;
24240Sstevel@tonic-gate 	int i;
24250Sstevel@tonic-gate 
24260Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
24270Sstevel@tonic-gate 
24280Sstevel@tonic-gate 	/*
24290Sstevel@tonic-gate 	 * first, see if an empty slot exists.
24300Sstevel@tonic-gate 	 */
24310Sstevel@tonic-gate 
24320Sstevel@tonic-gate 	for (i = 0; i < fscp->fs_inum_size; i++)
24330Sstevel@tonic-gate 		if (fscp->fs_inum_trans[i].cit_real == 0)
24340Sstevel@tonic-gate 			break;
24350Sstevel@tonic-gate 
24360Sstevel@tonic-gate 	/*
24370Sstevel@tonic-gate 	 * if there are no empty slots, try to grow the table.
24380Sstevel@tonic-gate 	 */
24390Sstevel@tonic-gate 
24400Sstevel@tonic-gate 	if (i >= fscp->fs_inum_size) {
24410Sstevel@tonic-gate 		cachefs_inum_trans_t *oldtbl;
24420Sstevel@tonic-gate 		int oldsize, newsize = 0;
24430Sstevel@tonic-gate 
24440Sstevel@tonic-gate 		/*
24450Sstevel@tonic-gate 		 * try to fetch a new table size that's bigger than
24460Sstevel@tonic-gate 		 * our current size
24470Sstevel@tonic-gate 		 */
24480Sstevel@tonic-gate 
24490Sstevel@tonic-gate 		for (i = 0; cachefs_hash_sizes[i] != 0; i++)
24500Sstevel@tonic-gate 			if (cachefs_hash_sizes[i] > fscp->fs_inum_size) {
24510Sstevel@tonic-gate 				newsize = cachefs_hash_sizes[i];
24520Sstevel@tonic-gate 				break;
24530Sstevel@tonic-gate 			}
24540Sstevel@tonic-gate 
24550Sstevel@tonic-gate 		/*
24560Sstevel@tonic-gate 		 * if we're out of larger twin-primes, give up.  thus,
24570Sstevel@tonic-gate 		 * the inode numbers in some directory entries might
24580Sstevel@tonic-gate 		 * change at reconnect, and disagree with what stat()
24590Sstevel@tonic-gate 		 * says.  this isn't worth panicing over, but it does
24600Sstevel@tonic-gate 		 * merit a warning message.
24610Sstevel@tonic-gate 		 */
24620Sstevel@tonic-gate 		if (newsize == 0) {
24630Sstevel@tonic-gate 			/* only print hash table warning once */
24640Sstevel@tonic-gate 			if ((fscp->fs_flags & CFS_FS_HASHPRINT) == 0) {
24650Sstevel@tonic-gate 				cmn_err(CE_WARN,
24660Sstevel@tonic-gate 				    "cachefs: inode hash table full\n");
24670Sstevel@tonic-gate 				fscp->fs_flags |= CFS_FS_HASHPRINT;
24680Sstevel@tonic-gate 			}
24690Sstevel@tonic-gate 			return;
24700Sstevel@tonic-gate 		}
24710Sstevel@tonic-gate 
24720Sstevel@tonic-gate 		/* set up this fscp with a new hash table */
24730Sstevel@tonic-gate 
24740Sstevel@tonic-gate 		oldtbl = fscp->fs_inum_trans;
24750Sstevel@tonic-gate 		oldsize = fscp->fs_inum_size;
24760Sstevel@tonic-gate 		fscp->fs_inum_size = newsize;
24770Sstevel@tonic-gate 		fscp->fs_inum_trans = (cachefs_inum_trans_t *)
24780Sstevel@tonic-gate 		    cachefs_kmem_zalloc(sizeof (cachefs_inum_trans_t) * newsize,
24790Sstevel@tonic-gate 			KM_SLEEP);
24800Sstevel@tonic-gate 
24810Sstevel@tonic-gate 		/*
24820Sstevel@tonic-gate 		 * re-insert all of the old values.  this will never
24830Sstevel@tonic-gate 		 * go more than one level into recursion-land.
24840Sstevel@tonic-gate 		 */
24850Sstevel@tonic-gate 
24860Sstevel@tonic-gate 		for (i = 0; i < oldsize; i++) {
24870Sstevel@tonic-gate 			tbl = oldtbl + i;
24880Sstevel@tonic-gate 			if (tbl->cit_real != 0) {
24890Sstevel@tonic-gate 				cachefs_inum_register(fscp, tbl->cit_real,
24900Sstevel@tonic-gate 				    tbl->cit_fake);
24910Sstevel@tonic-gate 			} else {
24920Sstevel@tonic-gate 				ASSERT(0);
24930Sstevel@tonic-gate 			}
24940Sstevel@tonic-gate 		}
24950Sstevel@tonic-gate 
24960Sstevel@tonic-gate 		if (oldsize > 0)
24970Sstevel@tonic-gate 			cachefs_kmem_free(oldtbl, oldsize *
24980Sstevel@tonic-gate 			    sizeof (cachefs_inum_trans_t));
24990Sstevel@tonic-gate 	}
25000Sstevel@tonic-gate 
25010Sstevel@tonic-gate 	/*
25020Sstevel@tonic-gate 	 * compute values for the hash table.  see ken rosen's
25030Sstevel@tonic-gate 	 * `elementary number theory and its applications' for one
25040Sstevel@tonic-gate 	 * description of double hashing.
25050Sstevel@tonic-gate 	 */
25060Sstevel@tonic-gate 
25070Sstevel@tonic-gate 	toff = (int)(real % fscp->fs_inum_size);
25080Sstevel@tonic-gate 	thop = (int)(real % (fscp->fs_inum_size - 2)) + 1;
25090Sstevel@tonic-gate 
25100Sstevel@tonic-gate 	/*
25110Sstevel@tonic-gate 	 * since we know the hash table isn't full when we get here,
25120Sstevel@tonic-gate 	 * this loop shouldn't terminate except via the `break'.
25130Sstevel@tonic-gate 	 */
25140Sstevel@tonic-gate 
25150Sstevel@tonic-gate 	for (i = 0; i < fscp->fs_inum_size; i++) {
25160Sstevel@tonic-gate 		tbl = fscp->fs_inum_trans + toff;
25170Sstevel@tonic-gate 		if ((tbl->cit_real == 0) || (tbl->cit_real == real)) {
25180Sstevel@tonic-gate 			tbl->cit_real = real;
25190Sstevel@tonic-gate 			tbl->cit_fake = fake;
25200Sstevel@tonic-gate 			break;
25210Sstevel@tonic-gate 		}
25220Sstevel@tonic-gate 
25230Sstevel@tonic-gate 		toff += thop;
25240Sstevel@tonic-gate 		toff %= fscp->fs_inum_size;
25250Sstevel@tonic-gate 	}
25260Sstevel@tonic-gate 	ASSERT(i < fscp->fs_inum_size);
25270Sstevel@tonic-gate }
25280Sstevel@tonic-gate 
25290Sstevel@tonic-gate /*
25300Sstevel@tonic-gate  * given an inode number, map it to the inode number that should be
25310Sstevel@tonic-gate  * put in a directory entry before its copied out.
25320Sstevel@tonic-gate  *
25330Sstevel@tonic-gate  * don't call this function unless there is a fscp->fs_inum_trans
25340Sstevel@tonic-gate  * table that has real entries in it!
25350Sstevel@tonic-gate  */
25360Sstevel@tonic-gate 
25370Sstevel@tonic-gate ino64_t
cachefs_inum_real2fake(fscache_t * fscp,ino64_t real)25380Sstevel@tonic-gate cachefs_inum_real2fake(fscache_t *fscp, ino64_t real)
25390Sstevel@tonic-gate {
25400Sstevel@tonic-gate 	cachefs_inum_trans_t *tbl;
25410Sstevel@tonic-gate 	ino64_t rc = real;
25420Sstevel@tonic-gate 	int toff, thop;
25430Sstevel@tonic-gate 	int i;
25440Sstevel@tonic-gate 
25450Sstevel@tonic-gate 	ASSERT(fscp->fs_inum_size > 0);
25460Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
25470Sstevel@tonic-gate 
25480Sstevel@tonic-gate 	toff = (int)(real % fscp->fs_inum_size);
25490Sstevel@tonic-gate 	thop = (int)(real % (fscp->fs_inum_size - 2)) + 1;
25500Sstevel@tonic-gate 
25510Sstevel@tonic-gate 	for (i = 0; i < fscp->fs_inum_size; i++) {
25520Sstevel@tonic-gate 		tbl = fscp->fs_inum_trans + toff;
25530Sstevel@tonic-gate 
25540Sstevel@tonic-gate 		if (tbl->cit_real == 0) {
25550Sstevel@tonic-gate 			break;
25560Sstevel@tonic-gate 		} else if (tbl->cit_real == real) {
25570Sstevel@tonic-gate 			rc = tbl->cit_fake;
25580Sstevel@tonic-gate 			break;
25590Sstevel@tonic-gate 		}
25600Sstevel@tonic-gate 
25610Sstevel@tonic-gate 		toff += thop;
25620Sstevel@tonic-gate 		toff %= fscp->fs_inum_size;
25630Sstevel@tonic-gate 	}
25640Sstevel@tonic-gate 
25650Sstevel@tonic-gate 	return (rc);
25660Sstevel@tonic-gate }
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate /*
25690Sstevel@tonic-gate  * Passed a cid, finds the cnode and sets the MD_NEEDATTRS bit
25700Sstevel@tonic-gate  * in the metadata.
25710Sstevel@tonic-gate  */
25720Sstevel@tonic-gate static void
cachefs_iosetneedattrs(fscache_t * fscp,cfs_cid_t * cidp)25730Sstevel@tonic-gate cachefs_iosetneedattrs(fscache_t *fscp, cfs_cid_t *cidp)
25740Sstevel@tonic-gate {
25750Sstevel@tonic-gate 	int error;
25760Sstevel@tonic-gate 	cnode_t *cp;
25770Sstevel@tonic-gate 
25780Sstevel@tonic-gate 	error = cachefs_cnode_make(cidp, fscp,
25790Sstevel@tonic-gate 	    NULL, NULL, NULL, kcred, 0, &cp);
25800Sstevel@tonic-gate 	if (error)
25810Sstevel@tonic-gate 		return;
25820Sstevel@tonic-gate 
25830Sstevel@tonic-gate 	mutex_enter(&cp->c_statelock);
25840Sstevel@tonic-gate 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
25850Sstevel@tonic-gate 	cp->c_flags |= CN_UPDATED;
25860Sstevel@tonic-gate 	mutex_exit(&cp->c_statelock);
25870Sstevel@tonic-gate 
25880Sstevel@tonic-gate 	VN_RELE(CTOV(cp));
25890Sstevel@tonic-gate }
2590