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