xref: /titanic_41/usr/src/uts/common/fs/cachefs/cachefs_subr.c (revision 8d483882aa3390058094b043f3d62187b5d1de03)
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 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/param.h>
30 #include <sys/types.h>
31 #include <sys/systm.h>
32 #include <sys/cred.h>
33 #include <sys/proc.h>
34 #include <sys/user.h>
35 #include <sys/vfs.h>
36 #include <sys/vnode.h>
37 #include <sys/pathname.h>
38 #include <sys/uio.h>
39 #include <sys/tiuser.h>
40 #include <sys/sysmacros.h>
41 #include <sys/kmem.h>
42 #include <sys/mount.h>
43 #include <sys/ioctl.h>
44 #include <sys/statvfs.h>
45 #include <sys/errno.h>
46 #include <sys/debug.h>
47 #include <sys/cmn_err.h>
48 #include <sys/utsname.h>
49 #include <sys/modctl.h>
50 #include <sys/file.h>
51 #include <sys/stat.h>
52 #include <sys/fcntl.h>
53 #include <sys/fbuf.h>
54 #include <sys/dnlc.h>
55 #include <sys/callb.h>
56 #include <sys/kobj.h>
57 #include <sys/rwlock.h>
58 
59 #include <sys/vmsystm.h>
60 #include <vm/hat.h>
61 #include <vm/as.h>
62 #include <vm/page.h>
63 #include <vm/pvn.h>
64 #include <vm/seg.h>
65 #include <vm/seg_map.h>
66 #include <vm/seg_vn.h>
67 #include <vm/rm.h>
68 #include <sys/fs/cachefs_fs.h>
69 #include <sys/fs/cachefs_log.h>
70 #include <sys/fs/cachefs_dir.h>
71 
72 extern struct seg *segkmap;
73 caddr_t segmap_getmap();
74 int segmap_release();
75 
76 extern struct cnode *cachefs_freeback;
77 extern struct cnode *cachefs_freefront;
78 extern cachefscache_t *cachefs_cachelist;
79 
80 #ifdef CFSDEBUG
81 int cachefsdebug = 0;
82 #endif
83 
84 int cachefs_max_threads = CFS_MAX_THREADS;
85 ino64_t cachefs_check_fileno = 0;
86 struct kmem_cache *cachefs_cache_kmcache = NULL;
87 struct kmem_cache *cachefs_req_cache = NULL;
88 
89 static int
90 cachefs_async_populate_reg(struct cachefs_populate_req *, cred_t *,
91     vnode_t *, vnode_t *);
92 
93 /*
94  * Cache routines
95  */
96 
97 /*
98  * ------------------------------------------------------------------
99  *
100  *		cachefs_cache_create
101  *
102  * Description:
103  *	Creates a cachefscache_t object and initializes it to
104  *	be NOCACHE and NOFILL mode.
105  * Arguments:
106  * Returns:
107  *	Returns a pointer to the created object or NULL if
108  *	threads could not be created.
109  * Preconditions:
110  */
111 
112 cachefscache_t *
113 cachefs_cache_create(void)
114 {
115 	cachefscache_t *cachep;
116 	struct cachefs_req *rp;
117 
118 	/* allocate zeroed memory for the object */
119 	cachep = kmem_cache_alloc(cachefs_cache_kmcache, KM_SLEEP);
120 
121 	bzero(cachep, sizeof (*cachep));
122 
123 	cv_init(&cachep->c_cwcv, NULL, CV_DEFAULT, NULL);
124 	cv_init(&cachep->c_cwhaltcv, NULL, CV_DEFAULT, NULL);
125 	mutex_init(&cachep->c_contentslock, NULL, MUTEX_DEFAULT, NULL);
126 	mutex_init(&cachep->c_fslistlock, NULL, MUTEX_DEFAULT, NULL);
127 	mutex_init(&cachep->c_log_mutex, NULL, MUTEX_DEFAULT, NULL);
128 
129 	/* set up the work queue and get the sync thread created */
130 	cachefs_workq_init(&cachep->c_workq);
131 	cachep->c_workq.wq_keepone = 1;
132 	cachep->c_workq.wq_cachep = cachep;
133 	rp = kmem_cache_alloc(cachefs_req_cache, KM_SLEEP);
134 	rp->cfs_cmd = CFS_NOOP;
135 	rp->cfs_cr = kcred;
136 	rp->cfs_req_u.cu_fs_sync.cf_cachep = cachep;
137 	crhold(rp->cfs_cr);
138 	cachefs_addqueue(rp, &cachep->c_workq);
139 	cachep->c_flags |= CACHE_NOCACHE | CACHE_NOFILL | CACHE_ALLOC_PENDING;
140 
141 	return (cachep);
142 }
143 
144 /*
145  * ------------------------------------------------------------------
146  *
147  *		cachefs_cache_destroy
148  *
149  * Description:
150  *	Destroys the cachefscache_t object.
151  * Arguments:
152  *	cachep	the cachefscache_t object to destroy
153  * Returns:
154  * Preconditions:
155  *	precond(cachep)
156  */
157 
158 void
159 cachefs_cache_destroy(cachefscache_t *cachep)
160 {
161 	clock_t tend;
162 	int error = 0;
163 #ifdef CFSRLDEBUG
164 	uint_t index;
165 #endif /* CFSRLDEBUG */
166 
167 	/* stop async threads */
168 	while (cachep->c_workq.wq_thread_count > 0)
169 		(void) cachefs_async_halt(&cachep->c_workq, 1);
170 
171 	/* kill off the cachep worker thread */
172 	mutex_enter(&cachep->c_contentslock);
173 	while (cachep->c_flags & CACHE_CACHEW_THREADRUN) {
174 		cachep->c_flags |= CACHE_CACHEW_THREADEXIT;
175 		cv_signal(&cachep->c_cwcv);
176 		tend = lbolt + (60 * hz);
177 		(void) cv_timedwait(&cachep->c_cwhaltcv,
178 			&cachep->c_contentslock, tend);
179 	}
180 
181 	if ((cachep->c_flags & CACHE_ALLOC_PENDING) == 0) {
182 		cachep->c_usage.cu_flags &= ~CUSAGE_ACTIVE;
183 		(void) cachefs_cache_rssync(cachep);
184 	}
185 	mutex_exit(&cachep->c_contentslock);
186 
187 	/* if there is a cache */
188 	if ((cachep->c_flags & CACHE_NOCACHE) == 0) {
189 		if ((cachep->c_flags & CACHE_NOFILL) == 0) {
190 #ifdef CFSRLDEBUG
191 			/* blow away dangling rl debugging info */
192 			mutex_enter(&cachep->c_contentslock);
193 			for (index = 0;
194 			    index <= cachep->c_rlinfo.rl_entries;
195 			    index++) {
196 				rl_entry_t *rlent;
197 
198 				error = cachefs_rl_entry_get(cachep, index,
199 									rlent);
200 				/*
201 				 * Since we are destroying the cache,
202 				 * better to ignore and proceed
203 				 */
204 				if (error)
205 					break;
206 				cachefs_rl_debug_destroy(rlent);
207 			}
208 			mutex_exit(&cachep->c_contentslock);
209 #endif /* CFSRLDEBUG */
210 
211 			/* sync the cache */
212 			if (!error)
213 				cachefs_cache_sync(cachep);
214 		} else {
215 			/* get rid of any unused fscache objects */
216 			mutex_enter(&cachep->c_fslistlock);
217 			fscache_list_gc(cachep);
218 			mutex_exit(&cachep->c_fslistlock);
219 		}
220 		ASSERT(cachep->c_fslist == NULL);
221 
222 		VN_RELE(cachep->c_resfilevp);
223 		VN_RELE(cachep->c_dirvp);
224 		VN_RELE(cachep->c_lockvp);
225 		VN_RELE(cachep->c_lostfoundvp);
226 	}
227 
228 	if (cachep->c_log_ctl != NULL)
229 		cachefs_kmem_free(cachep->c_log_ctl,
230 		    sizeof (cachefs_log_control_t));
231 	if (cachep->c_log != NULL)
232 		cachefs_log_destroy_cookie(cachep->c_log);
233 
234 	cv_destroy(&cachep->c_cwcv);
235 	cv_destroy(&cachep->c_cwhaltcv);
236 	mutex_destroy(&cachep->c_contentslock);
237 	mutex_destroy(&cachep->c_fslistlock);
238 	mutex_destroy(&cachep->c_log_mutex);
239 
240 	kmem_cache_free(cachefs_cache_kmcache, cachep);
241 }
242 
243 /*
244  * ------------------------------------------------------------------
245  *
246  *		cachefs_cache_active_ro
247  *
248  * Description:
249  *	Activates the cachefscache_t object for a read-only file system.
250  * Arguments:
251  *	cachep	the cachefscache_t object to activate
252  *	cdvp	the vnode of the cache directory
253  * Returns:
254  *	Returns 0 for success, !0 if there is a problem with the cache.
255  * Preconditions:
256  *	precond(cachep)
257  *	precond(cdvp)
258  *	precond(cachep->c_flags & CACHE_NOCACHE)
259  */
260 
261 int
262 cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
263 {
264 	cachefs_log_control_t *lc;
265 	vnode_t *labelvp = NULL;
266 	vnode_t *rifvp = NULL;
267 	vnode_t *lockvp = NULL;
268 	vnode_t *statevp = NULL;
269 	vnode_t *lostfoundvp = NULL;
270 	struct vattr *attrp = NULL;
271 	int error;
272 
273 	ASSERT(cachep->c_flags & CACHE_NOCACHE);
274 	mutex_enter(&cachep->c_contentslock);
275 
276 	attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP);
277 
278 	/* get the mode bits of the cache directory */
279 	attrp->va_mask = AT_ALL;
280 	error = VOP_GETATTR(cdvp, attrp, 0, kcred);
281 	if (error)
282 		goto out;
283 
284 	/* ensure the mode bits are 000 to keep out casual users */
285 	if (attrp->va_mode & S_IAMB) {
286 		cmn_err(CE_WARN, "cachefs: Cache Directory Mode must be 000\n");
287 		error = EPERM;
288 		goto out;
289 	}
290 
291 	/* Get the lock file */
292 	error = VOP_LOOKUP(cdvp, CACHEFS_LOCK_FILE, &lockvp, NULL, 0, NULL,
293 		kcred);
294 	if (error) {
295 		cmn_err(CE_WARN, "cachefs: activate_a: cache corruption"
296 			" run fsck.\n");
297 		goto out;
298 	}
299 
300 	/* Get the label file */
301 	error = VOP_LOOKUP(cdvp, CACHELABEL_NAME, &labelvp, NULL, 0, NULL,
302 		kcred);
303 	if (error) {
304 		cmn_err(CE_WARN, "cachefs: activate_b: cache corruption"
305 			" run fsck.\n");
306 		goto out;
307 	}
308 
309 	/* read in the label */
310 	error = vn_rdwr(UIO_READ, labelvp, (caddr_t)&cachep->c_label,
311 			sizeof (struct cache_label), 0LL, UIO_SYSSPACE,
312 			0, (rlim64_t)0, kcred, NULL);
313 	if (error) {
314 		cmn_err(CE_WARN, "cachefs: activate_c: cache corruption"
315 			" run fsck.\n");
316 		goto out;
317 	}
318 
319 	/* Verify that we can handle the version this cache was created under */
320 	if (cachep->c_label.cl_cfsversion != CFSVERSION) {
321 		cmn_err(CE_WARN, "cachefs: Invalid Cache Version, run fsck\n");
322 		error = EINVAL;
323 		goto out;
324 	}
325 
326 	/* Open the resource file */
327 	error = VOP_LOOKUP(cdvp, RESOURCE_NAME, &rifvp, NULL, 0, NULL, kcred);
328 	if (error) {
329 		cmn_err(CE_WARN, "cachefs: activate_d: cache corruption"
330 			" run fsck.\n");
331 		goto out;
332 	}
333 
334 	/*  Read the usage struct for this cache */
335 	error = vn_rdwr(UIO_READ, rifvp, (caddr_t)&cachep->c_usage,
336 			sizeof (struct cache_usage), 0LL, UIO_SYSSPACE, 0,
337 			(rlim64_t)0, kcred, NULL);
338 	if (error) {
339 		cmn_err(CE_WARN, "cachefs: activate_e: cache corruption"
340 			" run fsck.\n");
341 		goto out;
342 	}
343 
344 	if (cachep->c_usage.cu_flags & CUSAGE_ACTIVE) {
345 		cmn_err(CE_WARN, "cachefs: cache not clean.  Run fsck\n");
346 		/* ENOSPC is what UFS uses for clean flag check */
347 		error = ENOSPC;
348 		goto out;
349 	}
350 
351 	/*  Read the rlinfo for this cache */
352 	error = vn_rdwr(UIO_READ, rifvp, (caddr_t)&cachep->c_rlinfo,
353 	sizeof (cachefs_rl_info_t), (offset_t)sizeof (struct cache_usage),
354 			UIO_SYSSPACE, 0, 0, kcred, NULL);
355 	if (error) {
356 		cmn_err(CE_WARN, "cachefs: activate_f: cache corruption"
357 			" run fsck.\n");
358 		goto out;
359 	}
360 
361 	/* Open the lost+found directory */
362 	error = VOP_LOOKUP(cdvp, CACHEFS_LOSTFOUND_NAME, &lostfoundvp,
363 	    NULL, 0, NULL, kcred);
364 	if (error) {
365 		cmn_err(CE_WARN, "cachefs: activate_g: cache corruption"
366 			" run fsck.\n");
367 		goto out;
368 	}
369 
370 	VN_HOLD(rifvp);
371 	VN_HOLD(cdvp);
372 	VN_HOLD(lockvp);
373 	VN_HOLD(lostfoundvp);
374 	cachep->c_resfilevp = rifvp;
375 	cachep->c_dirvp = cdvp;
376 	cachep->c_lockvp = lockvp;
377 	cachep->c_lostfoundvp = lostfoundvp;
378 
379 	/* get the cachep worker thread created */
380 	cachep->c_flags |= CACHE_CACHEW_THREADRUN;
381 	(void) thread_create(NULL, 0, cachefs_cachep_worker_thread,
382 	    cachep, 0, &p0, TS_RUN, minclsyspri);
383 
384 	/* allocate the `logging control' field */
385 	mutex_enter(&cachep->c_log_mutex);
386 	cachep->c_log_ctl =
387 	    cachefs_kmem_zalloc(sizeof (cachefs_log_control_t), KM_SLEEP);
388 	lc = (cachefs_log_control_t *)cachep->c_log_ctl;
389 
390 	/* if the LOG_STATUS_NAME file exists, read it in and set up logging */
391 	error = VOP_LOOKUP(cachep->c_dirvp, LOG_STATUS_NAME, &statevp,
392 	    NULL, 0, NULL, kcred);
393 	if (error == 0) {
394 		int vnrw_error;
395 
396 		vnrw_error = vn_rdwr(UIO_READ, statevp, (caddr_t)lc,
397 		    sizeof (*lc), 0LL, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY,
398 		    kcred, NULL);
399 		VN_RELE(statevp);
400 
401 		if (vnrw_error == 0) {
402 			if ((cachep->c_log = cachefs_log_create_cookie(lc))
403 			    == NULL)
404 				cachefs_log_error(cachep, ENOMEM, 0);
405 			else if ((lc->lc_magic != CACHEFS_LOG_MAGIC) ||
406 			    (lc->lc_path[0] != '/') ||
407 			    (cachefs_log_logfile_open(cachep,
408 			    lc->lc_path) != 0))
409 				cachefs_log_error(cachep, EINVAL, 0);
410 		}
411 	} else {
412 		error = 0;
413 	}
414 	lc->lc_magic = CACHEFS_LOG_MAGIC;
415 	lc->lc_cachep = (uint64_t)(uintptr_t)cachep;
416 	mutex_exit(&cachep->c_log_mutex);
417 
418 out:
419 	if (error == 0) {
420 		cachep->c_flags &= ~(CACHE_NOCACHE | CACHE_ALLOC_PENDING);
421 	}
422 	if (attrp)
423 		cachefs_kmem_free(attrp, sizeof (struct vattr));
424 	if (labelvp != NULL)
425 		VN_RELE(labelvp);
426 	if (rifvp != NULL)
427 		VN_RELE(rifvp);
428 	if (lockvp)
429 		VN_RELE(lockvp);
430 	if (lostfoundvp)
431 		VN_RELE(lostfoundvp);
432 
433 	mutex_exit(&cachep->c_contentslock);
434 	return (error);
435 }
436 
437 int
438 cachefs_stop_cache(cnode_t *cp)
439 {
440 	fscache_t *fscp = C_TO_FSCACHE(cp);
441 	cachefscache_t *cachep = fscp->fs_cache;
442 	filegrp_t *fgp;
443 	int i;
444 	clock_t tend;
445 	int error = 0;
446 
447 	/* XXX verify lock-ordering for this function */
448 
449 	mutex_enter(&cachep->c_contentslock);
450 
451 	/*
452 	 * no work if we're already in nocache mode.  hopefully this
453 	 * will be the usual case.
454 	 */
455 
456 	if (cachep->c_flags & CACHE_NOCACHE) {
457 		mutex_exit(&cachep->c_contentslock);
458 		return (0);
459 	}
460 
461 	if ((cachep->c_flags & CACHE_NOFILL) == 0) {
462 		mutex_exit(&cachep->c_contentslock);
463 		return (EINVAL);
464 	}
465 
466 	mutex_exit(&cachep->c_contentslock);
467 
468 	/* We are already not caching if nfsv4 */
469 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
470 		return (0);
471 	}
472 
473 #ifdef CFSDEBUG
474 	mutex_enter(&cachep->c_fslistlock);
475 	ASSERT(fscp == cachep->c_fslist);
476 	ASSERT(fscp->fs_next == NULL);
477 	mutex_exit(&cachep->c_fslistlock);
478 
479 	printf("cachefs_stop_cache: resetting CACHE_NOCACHE\n");
480 #endif
481 
482 	/* XXX should i worry about disconnected during boot? */
483 	error = cachefs_cd_access(fscp, 1, 1);
484 	if (error)
485 		goto out;
486 
487 	error = cachefs_async_halt(&fscp->fs_workq, 1);
488 	ASSERT(error == 0);
489 	error = cachefs_async_halt(&cachep->c_workq, 1);
490 	ASSERT(error == 0);
491 	/* sigh -- best to keep going if async_halt failed. */
492 	error = 0;
493 
494 	/* XXX current order: cnode, fgp, fscp, cache. okay? */
495 
496 	cachefs_cnode_traverse(fscp, cachefs_cnode_disable_caching);
497 
498 	for (i = 0; i < CFS_FS_FGP_BUCKET_SIZE; i++) {
499 		for (fgp = fscp->fs_filegrp[i]; fgp != NULL;
500 		fgp = fgp->fg_next) {
501 			mutex_enter(&fgp->fg_mutex);
502 
503 			ASSERT((fgp->fg_flags &
504 			    (CFS_FG_WRITE | CFS_FG_UPDATED)) == 0);
505 			fgp->fg_flags |=
506 			    CFS_FG_ALLOC_FILE |
507 			    CFS_FG_ALLOC_ATTR;
508 			fgp->fg_flags &= ~CFS_FG_READ;
509 
510 			if (fgp->fg_dirvp) {
511 				fgp->fg_flags |= CFS_FG_ALLOC_FILE;
512 				VN_RELE(fgp->fg_dirvp);
513 				fgp->fg_dirvp = NULL;
514 			}
515 			if (fgp->fg_attrvp) {
516 				fgp->fg_flags |= CFS_FG_ALLOC_ATTR;
517 				VN_RELE(fgp->fg_attrvp);
518 				fgp->fg_attrvp = NULL;
519 			}
520 
521 			mutex_exit(&fgp->fg_mutex);
522 		}
523 	}
524 
525 	mutex_enter(&fscp->fs_fslock);
526 	ASSERT((fscp->fs_flags & (CFS_FS_WRITE)) == 0);
527 	fscp->fs_flags &= ~(CFS_FS_READ | CFS_FS_DIRTYINFO);
528 
529 	if (fscp->fs_fscdirvp) {
530 		VN_RELE(fscp->fs_fscdirvp);
531 		fscp->fs_fscdirvp = NULL;
532 	}
533 	if (fscp->fs_fsattrdir) {
534 		VN_RELE(fscp->fs_fsattrdir);
535 		fscp->fs_fsattrdir = NULL;
536 	}
537 	if (fscp->fs_infovp) {
538 		VN_RELE(fscp->fs_infovp);
539 		fscp->fs_infovp = NULL;
540 	}
541 	/* XXX dlog stuff? */
542 
543 	mutex_exit(&fscp->fs_fslock);
544 
545 	/*
546 	 * release resources grabbed in cachefs_cache_activate_ro
547 	 */
548 
549 	mutex_enter(&cachep->c_contentslock);
550 
551 	/* kill off the cachep worker thread */
552 	while (cachep->c_flags & CACHE_CACHEW_THREADRUN) {
553 		cachep->c_flags |= CACHE_CACHEW_THREADEXIT;
554 		cv_signal(&cachep->c_cwcv);
555 		tend = lbolt + (60 * hz);
556 		(void) cv_timedwait(&cachep->c_cwhaltcv,
557 			&cachep->c_contentslock, tend);
558 	}
559 
560 	if (cachep->c_resfilevp) {
561 		VN_RELE(cachep->c_resfilevp);
562 		cachep->c_resfilevp = NULL;
563 	}
564 	if (cachep->c_dirvp) {
565 		VN_RELE(cachep->c_dirvp);
566 		cachep->c_dirvp = NULL;
567 	}
568 	if (cachep->c_lockvp) {
569 		VN_RELE(cachep->c_lockvp);
570 		cachep->c_lockvp = NULL;
571 	}
572 	if (cachep->c_lostfoundvp) {
573 		VN_RELE(cachep->c_lostfoundvp);
574 		cachep->c_lostfoundvp = NULL;
575 	}
576 
577 	mutex_enter(&cachep->c_log_mutex);
578 	if (cachep->c_log_ctl) {
579 		cachefs_kmem_free(cachep->c_log_ctl,
580 		    sizeof (cachefs_log_control_t));
581 		cachep->c_log_ctl = NULL;
582 	}
583 	if (cachep->c_log) {
584 		cachefs_log_destroy_cookie(cachep->c_log);
585 		cachep->c_log = NULL;
586 	}
587 	mutex_exit(&cachep->c_log_mutex);
588 
589 	/* XXX do what mountroot_init does when ! foundcache */
590 
591 	cachep->c_flags |= CACHE_NOCACHE;
592 	mutex_exit(&cachep->c_contentslock);
593 
594 	/* XXX should i release this here? */
595 	cachefs_cd_release(fscp);
596 
597 out:
598 
599 	return (error);
600 }
601 
602 /*
603  * ------------------------------------------------------------------
604  *
605  *		cachefs_cache_active_rw
606  *
607  * Description:
608  *	Activates the cachefscache_t object for a read-write file system.
609  * Arguments:
610  *	cachep	the cachefscache_t object to activate
611  * Returns:
612  * Preconditions:
613  *	precond(cachep)
614  *	precond((cachep->c_flags & CACHE_NOCACHE) == 0)
615  *	precond(cachep->c_flags & CACHE_NOFILL)
616  */
617 
618 void
619 cachefs_cache_activate_rw(cachefscache_t *cachep)
620 {
621 	cachefs_rl_listhead_t *lhp;
622 
623 	ASSERT((cachep->c_flags & CACHE_NOCACHE) == 0);
624 	ASSERT(cachep->c_flags & CACHE_NOFILL);
625 
626 	mutex_enter(&cachep->c_contentslock);
627 	cachep->c_flags &= ~CACHE_NOFILL;
628 
629 	/* move the active list to the rl list */
630 	cachefs_rl_cleanup(cachep);
631 
632 	lhp = &cachep->c_rlinfo.rl_items[
633 	    CACHEFS_RL_INDEX(CACHEFS_RL_PACKED_PENDING)];
634 	if (lhp->rli_itemcnt != 0)
635 		cachep->c_flags |= CACHE_PACKED_PENDING;
636 	cachefs_cache_dirty(cachep, 0);
637 	mutex_exit(&cachep->c_contentslock);
638 }
639 
640 /*
641  * ------------------------------------------------------------------
642  *
643  *		cachefs_cache_dirty
644  *
645  * Description:
646  *	Marks the cache as dirty (active).
647  * Arguments:
648  *	cachep	the cachefscache_t to mark as dirty
649  *	lockit	1 means grab contents lock, 0 means caller grabbed it
650  * Returns:
651  * Preconditions:
652  *	precond(cachep)
653  *	precond(cache is in rw mode)
654  */
655 
656 void
657 cachefs_cache_dirty(struct cachefscache *cachep, int lockit)
658 {
659 	int error;
660 
661 	ASSERT((cachep->c_flags & (CACHE_NOCACHE | CACHE_NOFILL)) == 0);
662 
663 	if (lockit) {
664 		mutex_enter(&cachep->c_contentslock);
665 	} else {
666 		ASSERT(MUTEX_HELD(&cachep->c_contentslock));
667 	}
668 	if (cachep->c_flags & CACHE_DIRTY) {
669 		ASSERT(cachep->c_usage.cu_flags & CUSAGE_ACTIVE);
670 	} else {
671 		/*
672 		 * turn on the "cache active" (dirty) flag and write it
673 		 * synchronously to disk
674 		 */
675 		cachep->c_flags |= CACHE_DIRTY;
676 		cachep->c_usage.cu_flags |= CUSAGE_ACTIVE;
677 		if (error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp,
678 		    (caddr_t)&cachep->c_usage, sizeof (struct cache_usage),
679 		    0LL, UIO_SYSSPACE, FSYNC, (rlim64_t)RLIM_INFINITY,
680 				kcred, NULL)) {
681 			cmn_err(CE_WARN,
682 			    "cachefs: clean flag write error: %d\n", error);
683 		}
684 	}
685 
686 	if (lockit)
687 		mutex_exit(&cachep->c_contentslock);
688 }
689 
690 /*
691  * ------------------------------------------------------------------
692  *
693  *		cachefs_cache_rssync
694  *
695  * Description:
696  *	Syncs out the resource file for the cachefscache_t object.
697  * Arguments:
698  *	cachep	the cachefscache_t object to operate on
699  * Returns:
700  *	Returns 0 for success, !0 on an error writing data.
701  * Preconditions:
702  *	precond(cachep)
703  *	precond(cache is in rw mode)
704  */
705 
706 int
707 cachefs_cache_rssync(struct cachefscache *cachep)
708 {
709 	int error;
710 
711 	ASSERT((cachep->c_flags & (CACHE_NOCACHE | CACHE_NOFILL |
712 	    CACHE_ALLOC_PENDING)) == 0);
713 
714 	if (cachep->c_rl_entries != NULL) {
715 		error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp,
716 		    (caddr_t)cachep->c_rl_entries, MAXBSIZE,
717 		    (offset_t)((cachep->c_rl_window + 1) * MAXBSIZE),
718 		    UIO_SYSSPACE, FSYNC, RLIM_INFINITY, kcred, NULL);
719 		if (error)
720 		    cmn_err(CE_WARN, "cachefs: Can't Write rl entries Info\n");
721 		cachefs_kmem_free(cachep->c_rl_entries, MAXBSIZE);
722 		cachep->c_rl_entries = NULL;
723 	}
724 
725 	/* write the usage struct for this cache */
726 	error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp,
727 		(caddr_t)&cachep->c_usage, sizeof (struct cache_usage),
728 		0LL, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY, kcred, NULL);
729 	if (error) {
730 		cmn_err(CE_WARN, "cachefs: Can't Write Cache Usage Info\n");
731 	}
732 
733 	/* write the rlinfo for this cache */
734 	error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp,
735 			(caddr_t)&cachep->c_rlinfo, sizeof (cachefs_rl_info_t),
736 			(offset_t)sizeof (struct cache_usage), UIO_SYSSPACE,
737 			0, (rlim64_t)RLIM_INFINITY, kcred, NULL);
738 	if (error) {
739 		cmn_err(CE_WARN, "cachefs: Can't Write Cache RL Info\n");
740 	}
741 	error = VOP_FSYNC(cachep->c_resfilevp, FSYNC, kcred);
742 	return (error);
743 }
744 
745 /*
746  * ------------------------------------------------------------------
747  *
748  *		cachefs_cache_sync
749  *
750  * Description:
751  *	Sync a cache which includes all of its fscaches.
752  * Arguments:
753  *	cachep	the cachefscache_t object to sync
754  * Returns:
755  * Preconditions:
756  *	precond(cachep)
757  *	precond(cache is in rw mode)
758  */
759 
760 void
761 cachefs_cache_sync(struct cachefscache *cachep)
762 {
763 	struct fscache *fscp;
764 	struct fscache **syncfsc;
765 	int nfscs, fscidx;
766 	int try;
767 	int done;
768 
769 	if (cachep->c_flags & (CACHE_NOCACHE | CACHE_NOFILL))
770 		return;
771 
772 	done = 0;
773 	for (try = 0; (try < 2) && !done; try++) {
774 
775 		nfscs = 0;
776 
777 		/*
778 		 * here we turn off the cache-wide DIRTY flag.  If it's still
779 		 * off when the sync completes we can write the clean flag to
780 		 * disk telling fsck it has no work to do.
781 		 */
782 #ifdef CFSCLEANFLAG
783 		mutex_enter(&cachep->c_contentslock);
784 		cachep->c_flags &= ~CACHE_DIRTY;
785 		mutex_exit(&cachep->c_contentslock);
786 #endif /* CFSCLEANFLAG */
787 
788 		cachefs_log_process_queue(cachep, 1);
789 
790 		mutex_enter(&cachep->c_fslistlock);
791 		syncfsc = cachefs_kmem_alloc(
792 		    cachep->c_refcnt * sizeof (struct fscache *), KM_SLEEP);
793 		for (fscp = cachep->c_fslist; fscp; fscp = fscp->fs_next) {
794 			fscache_hold(fscp);
795 			ASSERT(nfscs < cachep->c_refcnt);
796 			syncfsc[nfscs++] = fscp;
797 		}
798 		ASSERT(nfscs == cachep->c_refcnt);
799 		mutex_exit(&cachep->c_fslistlock);
800 		for (fscidx = 0; fscidx < nfscs; fscidx++) {
801 			fscp = syncfsc[fscidx];
802 			fscache_sync(fscp);
803 			fscache_rele(fscp);
804 		}
805 
806 		/* get rid of any unused fscache objects */
807 		mutex_enter(&cachep->c_fslistlock);
808 		fscache_list_gc(cachep);
809 		mutex_exit(&cachep->c_fslistlock);
810 
811 		/*
812 		 * here we check the cache-wide DIRTY flag.
813 		 * If it's off,
814 		 * we can write the clean flag to disk.
815 		 */
816 #ifdef CFSCLEANFLAG
817 		mutex_enter(&cachep->c_contentslock);
818 		if ((cachep->c_flags & CACHE_DIRTY) == 0) {
819 			if (cachep->c_usage.cu_flags & CUSAGE_ACTIVE) {
820 				cachep->c_usage.cu_flags &= ~CUSAGE_ACTIVE;
821 				if (cachefs_cache_rssync(cachep) == 0) {
822 					done = 1;
823 				} else {
824 					cachep->c_usage.cu_flags |=
825 						CUSAGE_ACTIVE;
826 				}
827 			} else {
828 				done = 1;
829 			}
830 		}
831 		mutex_exit(&cachep->c_contentslock);
832 #else /* CFSCLEANFLAG */
833 		mutex_enter(&cachep->c_contentslock);
834 		(void) cachefs_cache_rssync(cachep);
835 		mutex_exit(&cachep->c_contentslock);
836 		done = 1;
837 #endif /* CFSCLEANFLAG */
838 		cachefs_kmem_free(syncfsc, nfscs * sizeof (struct fscache *));
839 	}
840 }
841 
842 /*
843  * ------------------------------------------------------------------
844  *
845  *		cachefs_cache_unique
846  *
847  * Description:
848  * Arguments:
849  * Returns:
850  *	Returns a unique number.
851  * Preconditions:
852  *	precond(cachep)
853  */
854 
855 uint_t
856 cachefs_cache_unique(cachefscache_t *cachep)
857 {
858 	uint_t unique = 0;
859 	int error = 0;
860 
861 	mutex_enter(&cachep->c_contentslock);
862 	if (cachep->c_usage.cu_flags & CUSAGE_NEED_ADJUST ||
863 		++(cachep->c_unique) == 0) {
864 		cachep->c_usage.cu_unique++;
865 
866 		if (cachep->c_unique == 0)
867 			cachep->c_unique = 1;
868 		cachep->c_flags &= ~CUSAGE_NEED_ADJUST;
869 		error = cachefs_cache_rssync(cachep);
870 	}
871 	if (error == 0)
872 		unique = (cachep->c_usage.cu_unique << 16) + cachep->c_unique;
873 	mutex_exit(&cachep->c_contentslock);
874 	return (unique);
875 }
876 
877 /*
878  * Called from c_getfrontfile. Shouldn't be called from anywhere else !
879  */
880 static int
881 cachefs_createfrontfile(cnode_t *cp, struct filegrp *fgp)
882 {
883 	char name[CFS_FRONTFILE_NAME_SIZE];
884 	struct vattr *attrp = NULL;
885 	int error = 0;
886 	int mode;
887 	int alloc = 0;
888 	int freefile = 0;
889 	int ffrele = 0;
890 	int rlfree = 0;
891 	rl_entry_t rl_ent;
892 
893 #ifdef CFSDEBUG
894 	CFS_DEBUG(CFSDEBUG_FRONT)
895 		printf("c_createfrontfile: ENTER cp %p fgp %p\n",
896 			(void *)cp, (void *)fgp);
897 #endif
898 
899 	ASSERT(cp->c_frontvp == NULL);
900 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
901 
902 	/* quit if we cannot write to the filegrp */
903 	if ((fgp->fg_flags & CFS_FG_WRITE) == 0) {
904 		error = ENOENT;
905 		goto out;
906 	}
907 
908 	/* find or create the filegrp attrcache file if necessary */
909 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
910 		error = filegrp_allocattr(fgp);
911 		if (error)
912 			goto out;
913 	}
914 
915 	make_ascii_name(&cp->c_id, name);
916 
917 	/* set up attributes for the front file we want to create */
918 	attrp = cachefs_kmem_zalloc(sizeof (struct vattr), KM_SLEEP);
919 	alloc++;
920 	attrp->va_mode = S_IFREG | 0666;
921 	mode = 0666;
922 	attrp->va_uid = 0;
923 	attrp->va_gid = 0;
924 	attrp->va_type = VREG;
925 	attrp->va_size = 0;
926 	attrp->va_mask = AT_SIZE | AT_TYPE | AT_MODE | AT_UID | AT_GID;
927 
928 	/* get a file from the resource counts */
929 	error = cachefs_allocfile(fgp->fg_fscp->fs_cache);
930 	if (error) {
931 		error = EINVAL;
932 		goto out;
933 	}
934 	freefile++;
935 
936 	/* create the metadata slot if necessary */
937 	if (cp->c_flags & CN_ALLOC_PENDING) {
938 		error = filegrp_create_metadata(fgp, &cp->c_metadata,
939 		    &cp->c_id);
940 		if (error) {
941 			error = EINVAL;
942 			goto out;
943 		}
944 		cp->c_flags &= ~CN_ALLOC_PENDING;
945 		cp->c_flags |= CN_UPDATED;
946 	}
947 
948 	/* get an rl entry if necessary */
949 	if (cp->c_metadata.md_rlno == 0) {
950 		rl_ent.rl_fileno = cp->c_id.cid_fileno;
951 		rl_ent.rl_local = (cp->c_id.cid_flags & CFS_CID_LOCAL) ? 1 : 0;
952 		rl_ent.rl_fsid = fgp->fg_fscp->fs_cfsid;
953 		rl_ent.rl_attrc = 0;
954 		error = cachefs_rl_alloc(fgp->fg_fscp->fs_cache, &rl_ent,
955 		    &cp->c_metadata.md_rlno);
956 		if (error)
957 			goto out;
958 		cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
959 		    CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno,
960 		    cp->c_metadata.md_frontblks);
961 		cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE;
962 		rlfree++;
963 		cp->c_flags |= CN_UPDATED; /* XXX sam: do we need this? */
964 
965 		/* increment number of front files */
966 		error = filegrp_ffhold(fgp);
967 		if (error) {
968 			error = EINVAL;
969 			goto out;
970 		}
971 		ffrele++;
972 	}
973 
974 	if (cp->c_flags & CN_ASYNC_POP_WORKING) {
975 		/* lookup the already created front file */
976 		error = VOP_LOOKUP(fgp->fg_dirvp, name, &cp->c_frontvp,
977 		    NULL, 0, NULL, kcred);
978 	} else {
979 		/* create the front file */
980 		error = VOP_CREATE(fgp->fg_dirvp, name, attrp, EXCL, mode,
981 		    &cp->c_frontvp, kcred, 0);
982 	}
983 	if (error) {
984 #ifdef CFSDEBUG
985 		CFS_DEBUG(CFSDEBUG_FRONT)
986 			printf("c_createfrontfile: Can't create cached object"
987 			    " error %u, fileno %llx\n", error,
988 			    (u_longlong_t)cp->c_id.cid_fileno);
989 #endif
990 		goto out;
991 	}
992 
993 	/* get a copy of the fid of the front file */
994 	cp->c_metadata.md_fid.fid_len = MAXFIDSZ;
995 	error = VOP_FID(cp->c_frontvp, &cp->c_metadata.md_fid);
996 	if (error) {
997 		/*
998 		 * If we get back ENOSPC then the fid we passed in was too
999 		 * small.  For now we don't do anything and map to EINVAL.
1000 		 */
1001 		if (error == ENOSPC) {
1002 			error = EINVAL;
1003 		}
1004 		goto out;
1005 	}
1006 
1007 	dnlc_purge_vp(cp->c_frontvp);
1008 
1009 	cp->c_metadata.md_flags |= MD_FILE;
1010 	cp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
1011 
1012 out:
1013 	if (error) {
1014 		if (cp->c_frontvp) {
1015 			VN_RELE(cp->c_frontvp);
1016 			(void) VOP_REMOVE(fgp->fg_dirvp, name, kcred);
1017 			cp->c_frontvp = NULL;
1018 		}
1019 		if (ffrele)
1020 			filegrp_ffrele(fgp);
1021 		if (freefile)
1022 			cachefs_freefile(fgp->fg_fscp->fs_cache);
1023 		if (rlfree) {
1024 #ifdef CFSDEBUG
1025 			cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
1026 			    CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno);
1027 #endif /* CFSDEBUG */
1028 			cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
1029 			    CACHEFS_RL_FREE, cp->c_metadata.md_rlno, 0);
1030 			cp->c_metadata.md_rlno = 0;
1031 			cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
1032 		}
1033 		cachefs_nocache(cp);
1034 	}
1035 	if (alloc)
1036 		cachefs_kmem_free(attrp, sizeof (struct vattr));
1037 #ifdef CFSDEBUG
1038 	CFS_DEBUG(CFSDEBUG_FRONT)
1039 		printf("c_createfrontfile: EXIT error = %d name %s\n", error,
1040 			name);
1041 #endif
1042 	return (error);
1043 }
1044 
1045 /*
1046  * Releases resources associated with the front file.
1047  * Only call this routine if a ffhold has been done.
1048  * Its okay to call this routine if the front file does not exist.
1049  * Note: this routine is used even if there is no front file.
1050  */
1051 void
1052 cachefs_removefrontfile(cachefs_metadata_t *mdp, cfs_cid_t *cidp,
1053     filegrp_t *fgp)
1054 {
1055 	int error, enoent;
1056 	char name[CFS_FRONTFILE_NAME_SIZE + 2];
1057 
1058 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
1059 
1060 	enoent = 0;
1061 	if (mdp->md_flags & MD_FILE) {
1062 		if (fgp->fg_dirvp == NULL) {
1063 			cmn_err(CE_WARN, "cachefs: remove error, run fsck\n");
1064 			return;
1065 		}
1066 		make_ascii_name(cidp, name);
1067 		error = VOP_REMOVE(fgp->fg_dirvp, name, kcred);
1068 		if (error == ENOENT)
1069 			enoent = 1;
1070 		if ((error) && (error != ENOENT)) {
1071 			cmn_err(CE_WARN, "UFS remove error %s %d, run fsck\n",
1072 			    name, error);
1073 		}
1074 		if (mdp->md_flags & MD_ACLDIR) {
1075 			(void) strcat(name, ".d");
1076 			error = VOP_RMDIR(fgp->fg_dirvp, name, fgp->fg_dirvp,
1077 			    kcred);
1078 			if ((error) && (error != ENOENT)) {
1079 				cmn_err(CE_WARN, "frontfs rmdir error %s %d"
1080 				    "; run fsck\n", name, error);
1081 			}
1082 		}
1083 		mdp->md_flags &= ~(MD_FILE | MD_POPULATED | MD_ACL | MD_ACLDIR);
1084 		bzero(&mdp->md_allocinfo, mdp->md_allocents *
1085 			sizeof (struct cachefs_allocmap));
1086 		cachefs_freefile(fgp->fg_fscp->fs_cache);
1087 	}
1088 
1089 	/*
1090 	 * Clear packed bit, fastsymlinks and special files
1091 	 * do not have a front file.
1092 	 */
1093 	mdp->md_flags &= ~MD_PACKED;
1094 
1095 	/* XXX either rename routine or move this to caller */
1096 	if (enoent == 0)
1097 		filegrp_ffrele(fgp);
1098 
1099 	if (mdp->md_frontblks) {
1100 		cachefs_freeblocks(fgp->fg_fscp->fs_cache, mdp->md_frontblks,
1101 		    mdp->md_rltype);
1102 		mdp->md_frontblks = 0;
1103 	}
1104 }
1105 
1106 /*
1107  * This is the interface to the rest of CFS. This takes a cnode, and returns
1108  * the frontvp (stuffs it in the cnode). This creates an attrcache slot and
1109  * and frontfile if necessary.
1110  */
1111 
1112 int
1113 cachefs_getfrontfile(cnode_t *cp)
1114 {
1115 	struct filegrp *fgp = cp->c_filegrp;
1116 	int error;
1117 	struct vattr va;
1118 
1119 #ifdef CFSDEBUG
1120 	CFS_DEBUG(CFSDEBUG_SUBR)
1121 		printf("c_getfrontfile: ENTER cp %p\n", (void *)cp);
1122 #endif
1123 
1124 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
1125 	ASSERT(MUTEX_HELD(&cp->c_statelock));
1126 
1127 	/*
1128 	 * Now we check to see if there is a front file for this entry.
1129 	 * If there is, we get the vnode for it and stick it in the cnode.
1130 	 * Otherwise, we create a front file, get the vnode for it and stick
1131 	 * it in the cnode.
1132 	 */
1133 	if (cp->c_flags & CN_STALE) {
1134 		cp->c_flags |= CN_NOCACHE;
1135 		error = ESTALE;
1136 		goto out;
1137 	}
1138 
1139 	/*
1140 	 * If the cnode is being populated, and we're not the populating
1141 	 * thread, then block until the pop thread completes.  If we are the
1142 	 * pop thread, then we may come in here, but not to nuke the directory
1143 	 * cnode at a critical juncture.  If we return from a cv_wait and the
1144 	 * cnode is now stale, don't bother trying to get the front file.
1145 	 */
1146 	while ((cp->c_flags & CN_ASYNC_POP_WORKING) &&
1147 	    (cp->c_popthrp != curthread)) {
1148 		cv_wait(&cp->c_popcv, &cp->c_statelock);
1149 		if (cp->c_flags & CN_STALE) {
1150 			cp->c_flags |= CN_NOCACHE;
1151 			error = ESTALE;
1152 			goto out;
1153 		}
1154 	}
1155 
1156 	if ((cp->c_metadata.md_flags & MD_FILE) == 0) {
1157 #ifdef CFSDEBUG
1158 		if (cp->c_frontvp != NULL)
1159 			CFS_DEBUG(CFSDEBUG_FRONT)
1160 				printf(
1161 		"c_getfrontfile: !MD_FILE and frontvp not null cp %p\n",
1162 				    (void *)cp);
1163 #endif
1164 		if (CTOV(cp)->v_type == VDIR)
1165 			ASSERT((cp->c_metadata.md_flags & MD_POPULATED) == 0);
1166 		error = cachefs_createfrontfile(cp, fgp);
1167 		if (error)
1168 			goto out;
1169 	} else {
1170 		/*
1171 		 * A front file exists, all we need to do is to grab the fid,
1172 		 * do a VFS_VGET() on the fid, stuff the vnode in the cnode,
1173 		 * and return.
1174 		 */
1175 		if (fgp->fg_dirvp == NULL) {
1176 			cmn_err(CE_WARN, "cachefs: gff0: corrupted file system"
1177 				" run fsck\n");
1178 			cachefs_inval_object(cp);
1179 			cp->c_flags |= CN_NOCACHE;
1180 			error = ESTALE;
1181 			goto out;
1182 		}
1183 		error = VFS_VGET(fgp->fg_dirvp->v_vfsp, &cp->c_frontvp,
1184 				&cp->c_metadata.md_fid);
1185 		if (error || (cp->c_frontvp == NULL)) {
1186 #ifdef CFSDEBUG
1187 			CFS_DEBUG(CFSDEBUG_FRONT)
1188 				printf("cachefs: "
1189 				    "gff1: front file system error %d\n",
1190 				    error);
1191 #endif /* CFSDEBUG */
1192 			cachefs_inval_object(cp);
1193 			cp->c_flags |= CN_NOCACHE;
1194 			error = ESTALE;
1195 			goto out;
1196 		}
1197 
1198 		/* don't need to check timestamps if need_front_sync is set */
1199 		if (cp->c_flags & CN_NEED_FRONT_SYNC) {
1200 			error = 0;
1201 			goto out;
1202 		}
1203 
1204 		/* don't need to check empty directories */
1205 		if (CTOV(cp)->v_type == VDIR &&
1206 		    ((cp->c_metadata.md_flags & MD_POPULATED) == 0)) {
1207 			error = 0;
1208 			goto out;
1209 		}
1210 
1211 		/* get modify time of the front file */
1212 		va.va_mask = AT_MTIME;
1213 		error = VOP_GETATTR(cp->c_frontvp, &va, 0, kcred);
1214 		if (error) {
1215 			cmn_err(CE_WARN, "cachefs: gff2: front file"
1216 				" system error %d", error);
1217 			cachefs_inval_object(cp);
1218 			error = (cp->c_flags & CN_NOCACHE) ? ESTALE : 0;
1219 			goto out;
1220 		}
1221 
1222 		/* compare with modify time stored in metadata */
1223 		if (bcmp(&va.va_mtime, &cp->c_metadata.md_timestamp,
1224 		    sizeof (timestruc_t)) != 0) {
1225 #ifdef CFSDEBUG
1226 			CFS_DEBUG(CFSDEBUG_GENERAL | CFSDEBUG_INVALIDATE) {
1227 				long sec, nsec;
1228 				sec = cp->c_metadata.md_timestamp.tv_sec;
1229 				nsec = cp->c_metadata.md_timestamp.tv_nsec;
1230 				printf("c_getfrontfile: timestamps don't"
1231 					" match fileno %lld va %lx %lx"
1232 					" meta %lx %lx\n",
1233 					(u_longlong_t)cp->c_id.cid_fileno,
1234 					va.va_mtime.tv_sec,
1235 					va.va_mtime.tv_nsec, sec, nsec);
1236 			}
1237 #endif
1238 			cachefs_inval_object(cp);
1239 			error = (cp->c_flags & CN_NOCACHE) ? ESTALE : 0;
1240 		}
1241 	}
1242 out:
1243 
1244 #ifdef CFSDEBUG
1245 	CFS_DEBUG(CFSDEBUG_FRONT)
1246 		printf("c_getfrontfile: EXIT error = %d\n", error);
1247 #endif
1248 	return (error);
1249 }
1250 
1251 void
1252 cachefs_inval_object(cnode_t *cp)
1253 {
1254 	cachefscache_t *cachep = C_TO_FSCACHE(cp)->fs_cache;
1255 	struct filegrp *fgp = cp->c_filegrp;
1256 	int error;
1257 
1258 	ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(cp)) == 0);
1259 	ASSERT(MUTEX_HELD(&cp->c_statelock));
1260 	ASSERT((cp->c_flags & CN_ASYNC_POP_WORKING) == 0 ||
1261 		cp->c_popthrp == curthread);
1262 #if 0
1263 	CFS_DEBUG(CFSDEBUG_SUBR)
1264 		printf("c_inval_object: ENTER cp %p\n", (void *)cp);
1265 	if (cp->c_flags & (CN_ASYNC_POPULATE | CN_ASYNC_POP_WORKING))
1266 		debug_enter("inval object during async pop");
1267 #endif
1268 	cp->c_flags |= CN_NOCACHE;
1269 
1270 	/* if we cannot modify the cache */
1271 	if (C_TO_FSCACHE(cp)->fs_cache->c_flags &
1272 	    (CACHE_NOFILL | CACHE_NOCACHE)) {
1273 		goto out;
1274 	}
1275 
1276 	/* if there is a front file */
1277 	if (cp->c_metadata.md_flags & MD_FILE) {
1278 		if (fgp->fg_dirvp == NULL)
1279 			goto out;
1280 
1281 		/* get the front file vp if necessary */
1282 		if (cp->c_frontvp == NULL) {
1283 
1284 			error = VFS_VGET(fgp->fg_dirvp->v_vfsp, &cp->c_frontvp,
1285 				&cp->c_metadata.md_fid);
1286 			if (error || (cp->c_frontvp == NULL)) {
1287 #ifdef CFSDEBUG
1288 				CFS_DEBUG(CFSDEBUG_FRONT)
1289 					printf("cachefs: "
1290 					    "io: front file error %d\n", error);
1291 #endif /* CFSDEBUG */
1292 				goto out;
1293 			}
1294 		}
1295 
1296 		/* truncate the file to zero size */
1297 		error = cachefs_frontfile_size(cp, 0);
1298 		if (error)
1299 			goto out;
1300 		cp->c_flags &= ~CN_NOCACHE;
1301 
1302 		/* if a directory, v_type is zero if called from initcnode */
1303 		if (cp->c_attr.va_type == VDIR) {
1304 			if (cp->c_usage < CFS_DIRCACHE_COST) {
1305 				cp->c_invals++;
1306 				if (cp->c_invals > CFS_DIRCACHE_INVAL) {
1307 					cp->c_invals = 0;
1308 				}
1309 			} else
1310 				cp->c_invals = 0;
1311 			cp->c_usage = 0;
1312 		}
1313 	} else {
1314 		cp->c_flags &= ~CN_NOCACHE;
1315 	}
1316 
1317 out:
1318 	if ((cp->c_metadata.md_flags & MD_PACKED) &&
1319 	    (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) &&
1320 	    ((cachep->c_flags & CACHE_NOFILL) == 0)) {
1321 		ASSERT(cp->c_metadata.md_rlno != 0);
1322 		if (cp->c_metadata.md_rltype != CACHEFS_RL_PACKED_PENDING) {
1323 			cachefs_rlent_moveto(cachep,
1324 			    CACHEFS_RL_PACKED_PENDING,
1325 			    cp->c_metadata.md_rlno,
1326 			    cp->c_metadata.md_frontblks);
1327 			cp->c_metadata.md_rltype = CACHEFS_RL_PACKED_PENDING;
1328 			/* unconditionally set CN_UPDATED below */
1329 		}
1330 	}
1331 
1332 	cachefs_purgeacl(cp);
1333 
1334 	if (cp->c_flags & CN_ASYNC_POP_WORKING)
1335 		cp->c_flags |= CN_NOCACHE;
1336 	cp->c_metadata.md_flags &= ~(MD_POPULATED | MD_INVALREADDIR |
1337 	    MD_FASTSYMLNK);
1338 	cp->c_flags &= ~CN_NEED_FRONT_SYNC;
1339 	cp->c_flags |= CN_UPDATED;
1340 
1341 	/*
1342 	 * If the object invalidated is a directory, the dnlc should be purged
1343 	 * to elide all references to this (directory) vnode.
1344 	 */
1345 	if (CTOV(cp)->v_type == VDIR)
1346 		dnlc_purge_vp(CTOV(cp));
1347 
1348 #ifdef CFSDEBUG
1349 	CFS_DEBUG(CFSDEBUG_SUBR)
1350 		printf("c_inval_object: EXIT\n");
1351 #endif
1352 }
1353 
1354 void
1355 make_ascii_name(cfs_cid_t *cidp, char *strp)
1356 {
1357 	int i = sizeof (uint_t) * 4;
1358 	u_longlong_t index;
1359 	ino64_t name;
1360 
1361 	if (cidp->cid_flags & CFS_CID_LOCAL)
1362 		*strp++ = 'L';
1363 	name = (ino64_t)cidp->cid_fileno;
1364 	do {
1365 		index = (((u_longlong_t)name) & 0xf000000000000000) >> 60;
1366 		index &= (u_longlong_t)0xf;
1367 		ASSERT(index < (u_longlong_t)16);
1368 		*strp++ = "0123456789abcdef"[index];
1369 		name <<= 4;
1370 	} while (--i);
1371 	*strp = '\0';
1372 }
1373 
1374 void
1375 cachefs_nocache(cnode_t *cp)
1376 {
1377 	fscache_t *fscp = C_TO_FSCACHE(cp);
1378 	cachefscache_t *cachep = fscp->fs_cache;
1379 
1380 #ifdef CFSDEBUG
1381 	CFS_DEBUG(CFSDEBUG_SUBR)
1382 		printf("c_nocache: ENTER cp %p\n", (void *)cp);
1383 #endif
1384 
1385 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1386 	ASSERT(MUTEX_HELD(&cp->c_statelock));
1387 	if ((cp->c_flags & CN_NOCACHE) == 0) {
1388 #ifdef CFSDEBUG
1389 		CFS_DEBUG(CFSDEBUG_INVALIDATE)
1390 			printf("cachefs_nocache: invalidating %llu\n",
1391 			    (u_longlong_t)cp->c_id.cid_fileno);
1392 #endif
1393 		/*
1394 		 * Here we are waiting until inactive time to do
1395 		 * the inval_object.  In case we don't get to inactive
1396 		 * (because of a crash, say) we set up a timestamp mismatch
1397 		 * such that getfrontfile will blow the front file away
1398 		 * next time we try to use it.
1399 		 */
1400 		cp->c_metadata.md_timestamp.tv_sec = 0;
1401 		cp->c_metadata.md_timestamp.tv_nsec = 0;
1402 		cp->c_metadata.md_flags &= ~(MD_POPULATED | MD_INVALREADDIR |
1403 		    MD_FASTSYMLNK);
1404 		cp->c_flags &= ~CN_NEED_FRONT_SYNC;
1405 
1406 		cachefs_purgeacl(cp);
1407 
1408 		/*
1409 		 * It is possible we can nocache while disconnected.
1410 		 * A directory could be nocached by running out of space.
1411 		 * A regular file should only be nocached if an I/O error
1412 		 * occurs to the front fs.
1413 		 * We count on the item staying on the modified list
1414 		 * so we do not loose the cid to fid mapping for directories.
1415 		 */
1416 
1417 		if ((cp->c_metadata.md_flags & MD_PACKED) &&
1418 		    (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) &&
1419 		    ((cachep->c_flags & CACHE_NOFILL) == 0)) {
1420 			ASSERT(cp->c_metadata.md_rlno != 0);
1421 			if (cp->c_metadata.md_rltype !=
1422 			    CACHEFS_RL_PACKED_PENDING) {
1423 				cachefs_rlent_moveto(cachep,
1424 				    CACHEFS_RL_PACKED_PENDING,
1425 				    cp->c_metadata.md_rlno,
1426 				    cp->c_metadata.md_frontblks);
1427 				cp->c_metadata.md_rltype =
1428 				    CACHEFS_RL_PACKED_PENDING;
1429 				/* unconditionally set CN_UPDATED below */
1430 			}
1431 		}
1432 
1433 		if (CTOV(cp)->v_type == VDIR)
1434 			dnlc_purge_vp(CTOV(cp));
1435 		cp->c_flags |= (CN_NOCACHE | CN_UPDATED);
1436 	}
1437 
1438 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_NOCACHE))
1439 		cachefs_log_nocache(cachep, 0, fscp->fs_cfsvfsp,
1440 		    &cp->c_metadata.md_cookie, cp->c_id.cid_fileno);
1441 
1442 #ifdef CFSDEBUG
1443 	CFS_DEBUG(CFSDEBUG_SUBR)
1444 		printf("c_nocache: EXIT cp %p\n", (void *)cp);
1445 #endif
1446 }
1447 
1448 /*
1449  * Checks to see if the page is in the disk cache, by checking the allocmap.
1450  */
1451 int
1452 cachefs_check_allocmap(cnode_t *cp, u_offset_t off)
1453 {
1454 	int i;
1455 	size_t dbl_size_to_look = cp->c_attr.va_size - off;
1456 	uint_t	size_to_look;
1457 
1458 	if (dbl_size_to_look > (u_offset_t)PAGESIZE)
1459 		size_to_look = (uint_t)PAGESIZE;
1460 	else
1461 		/*LINTED alignment okay*/
1462 		size_to_look = (uint_t)dbl_size_to_look;
1463 
1464 	for (i = 0; i < cp->c_metadata.md_allocents; i++) {
1465 		struct cachefs_allocmap *allocp =
1466 				cp->c_metadata.md_allocinfo + i;
1467 
1468 		if (off >= allocp->am_start_off) {
1469 			if ((off + size_to_look) <=
1470 			    (allocp->am_start_off + allocp->am_size)) {
1471 				struct fscache *fscp = C_TO_FSCACHE(cp);
1472 				cachefscache_t *cachep = fscp->fs_cache;
1473 
1474 				if (CACHEFS_LOG_LOGGING(cachep,
1475 				    CACHEFS_LOG_CALLOC))
1476 					cachefs_log_calloc(cachep, 0,
1477 					    fscp->fs_cfsvfsp,
1478 					    &cp->c_metadata.md_cookie,
1479 					    cp->c_id.cid_fileno,
1480 					    off, size_to_look);
1481 			/*
1482 			 * Found the page in the CFS disk cache.
1483 			 */
1484 				return (1);
1485 			}
1486 		} else {
1487 			return (0);
1488 		}
1489 	}
1490 	return (0);
1491 }
1492 
1493 /*
1494  * Merges adjacent allocmap entries together where possible, e.g.
1495  *   offset=0x0,     size=0x40000
1496  *   offset=0x40000, size=0x20000	becomes just offset=0x0, size-0x90000
1497  *   offset=0x60000, size=0x30000
1498  */
1499 
1500 
1501 void
1502 cachefs_coalesce_allocmap(struct cachefs_metadata *cmd)
1503 {
1504 	int i, reduced = 0;
1505 	struct cachefs_allocmap *allocp, *nallocp;
1506 
1507 	nallocp = allocp = cmd->md_allocinfo;
1508 	allocp++;
1509 	for (i = 1; i < cmd->md_allocents; i++, allocp++) {
1510 		if (nallocp->am_start_off + nallocp->am_size ==
1511 						allocp->am_start_off) {
1512 			nallocp->am_size += allocp->am_size;
1513 			reduced++;
1514 		} else {
1515 			nallocp++;
1516 			nallocp->am_start_off = allocp->am_start_off;
1517 			nallocp->am_size = allocp->am_size;
1518 		}
1519 	}
1520 	cmd->md_allocents -= reduced;
1521 }
1522 
1523 /*
1524  * Updates the allocmap to reflect a new chunk of data that has been
1525  * populated.
1526  */
1527 void
1528 cachefs_update_allocmap(cnode_t *cp, u_offset_t off, size_t size)
1529 {
1530 	int i;
1531 	struct cachefs_allocmap *allocp;
1532 	struct fscache *fscp =  C_TO_FSCACHE(cp);
1533 	cachefscache_t *cachep = fscp->fs_cache;
1534 	u_offset_t saveoff;
1535 	u_offset_t savesize;
1536 	u_offset_t logoff = off;
1537 	size_t logsize = size;
1538 	u_offset_t endoff;
1539 	u_offset_t tmpendoff;
1540 
1541 	/*
1542 	 * We try to see if we can coalesce the current block into an existing
1543 	 * allocation and mark it as such.
1544 	 * If we can't do that then we make a new entry in the allocmap.
1545 	 * when we run out of allocmaps, put the cnode in NOCACHE mode.
1546 	 */
1547 again:
1548 	allocp = cp->c_metadata.md_allocinfo;
1549 	for (i = 0; i < cp->c_metadata.md_allocents; i++, allocp++) {
1550 
1551 		if (off <= (allocp->am_start_off)) {
1552 			endoff = off + size;
1553 			if (endoff >= allocp->am_start_off) {
1554 				tmpendoff = allocp->am_start_off +
1555 						allocp->am_size;
1556 				if (endoff < tmpendoff)
1557 					endoff = tmpendoff;
1558 				allocp->am_size = endoff - off;
1559 				allocp->am_start_off = off;
1560 				cachefs_coalesce_allocmap(&cp->c_metadata);
1561 				allocp = cp->c_metadata.md_allocinfo;
1562 				if (allocp->am_size >= cp->c_size)
1563 					cp->c_metadata.md_flags |= MD_POPULATED;
1564 				return;
1565 			} else {
1566 				saveoff = off;
1567 				savesize = size;
1568 				off = allocp->am_start_off;
1569 				size = allocp->am_size;
1570 				allocp->am_size = savesize;
1571 				allocp->am_start_off = saveoff;
1572 				goto again;
1573 			}
1574 		} else {
1575 			endoff = allocp->am_start_off + allocp->am_size;
1576 			if (off < endoff) {
1577 				tmpendoff = off + size;
1578 				if (endoff < tmpendoff)
1579 					endoff = tmpendoff;
1580 				allocp->am_size = endoff - allocp->am_start_off;
1581 				cachefs_coalesce_allocmap(&cp->c_metadata);
1582 				allocp = cp->c_metadata.md_allocinfo;
1583 				if (allocp->am_size >= cp->c_size)
1584 					cp->c_metadata.md_flags |= MD_POPULATED;
1585 				return;
1586 			}
1587 			if (off == (allocp->am_start_off + allocp->am_size)) {
1588 				allocp->am_size += size;
1589 				cachefs_coalesce_allocmap(&cp->c_metadata);
1590 				allocp = cp->c_metadata.md_allocinfo;
1591 				if (allocp->am_size >= cp->c_size)
1592 					cp->c_metadata.md_flags |= MD_POPULATED;
1593 				return;
1594 			}
1595 		}
1596 	}
1597 	if (i == C_MAX_ALLOCINFO_SLOTS) {
1598 #ifdef CFSDEBUG
1599 		CFS_DEBUG(CFSDEBUG_ALLOCMAP)
1600 			printf("c_update_alloc_map: "
1601 			    "Too many allinfo entries cp %p fileno %llu %p\n",
1602 			    (void *)cp, (u_longlong_t)cp->c_id.cid_fileno,
1603 			    (void *)cp->c_metadata.md_allocinfo);
1604 #endif
1605 		cachefs_nocache(cp);
1606 		return;
1607 	}
1608 	allocp->am_start_off = off;
1609 	allocp->am_size = (u_offset_t)size;
1610 	if (allocp->am_size >= cp->c_size)
1611 		cp->c_metadata.md_flags |= MD_POPULATED;
1612 	cp->c_metadata.md_allocents++;
1613 
1614 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_UALLOC))
1615 		cachefs_log_ualloc(cachep, 0, fscp->fs_cfsvfsp,
1616 		    &cp->c_metadata.md_cookie, cp->c_id.cid_fileno,
1617 		    logoff, logsize);
1618 }
1619 
1620 /*
1621  * CFS population function
1622  *
1623  * before async population, this function used to turn on the cnode
1624  * flags CN_UPDATED, CN_NEED_FRONT_SYNC, and CN_POPULATION_PENDING.
1625  * now, however, it's the responsibility of the caller to do this if
1626  * this function returns 0 (no error).
1627  */
1628 
1629 int
1630 cachefs_populate(cnode_t *cp, u_offset_t off, size_t popsize, vnode_t *frontvp,
1631     vnode_t *backvp, u_offset_t cpsize, cred_t *cr)
1632 {
1633 	int error = 0;
1634 	caddr_t addr;
1635 	u_offset_t upto;
1636 	uint_t size;
1637 	u_offset_t from = off;
1638 	cachefscache_t *cachep = C_TO_FSCACHE(cp)->fs_cache;
1639 	ssize_t resid;
1640 	struct fbuf *fbp;
1641 	caddr_t buf = kmem_alloc(MAXBSIZE, KM_SLEEP);
1642 
1643 #ifdef CFSDEBUG
1644 	CFS_DEBUG(CFSDEBUG_VOPS)
1645 		printf("cachefs_populate: ENTER cp %p off %lld\n",
1646 		    (void *)cp, off);
1647 #endif
1648 
1649 	upto = MIN((off + popsize), cpsize);
1650 
1651 	while (from < upto) {
1652 		u_offset_t blkoff = (from & (offset_t)MAXBMASK);
1653 		uint_t n = from - blkoff;
1654 
1655 		size = upto - from;
1656 		if (upto > (blkoff + MAXBSIZE))
1657 			size = MAXBSIZE - n;
1658 
1659 		error = fbread(backvp, (offset_t)blkoff, n + size,
1660 			S_OTHER, &fbp);
1661 		if (CFS_TIMEOUT(C_TO_FSCACHE(cp), error))
1662 			goto out;
1663 		else if (error) {
1664 #ifdef CFSDEBUG
1665 			CFS_DEBUG(CFSDEBUG_BACK)
1666 				printf("cachefs_populate: fbread error %d\n",
1667 				    error);
1668 #endif
1669 			goto out;
1670 		}
1671 
1672 		addr = fbp->fb_addr;
1673 		ASSERT(addr != NULL);
1674 		ASSERT(n + size <= MAXBSIZE);
1675 		bcopy(addr, buf, n + size);
1676 		fbrelse(fbp, S_OTHER);
1677 
1678 		if (n == 0 || cachefs_check_allocmap(cp, blkoff) == 0) {
1679 			if (error = cachefs_allocblocks(cachep, 1,
1680 			    cp->c_metadata.md_rltype))
1681 				goto out;
1682 			cp->c_metadata.md_frontblks++;
1683 		}
1684 		resid = 0;
1685 		error = vn_rdwr(UIO_WRITE, frontvp, buf + n, size,
1686 				(offset_t)from, UIO_SYSSPACE, 0,
1687 				(rlim64_t)RLIM64_INFINITY, cr, &resid);
1688 		if (error) {
1689 #ifdef CFSDEBUG
1690 			CFS_DEBUG(CFSDEBUG_FRONT)
1691 				printf("cachefs_populate: "
1692 				    "Got error = %d from vn_rdwr\n", error);
1693 #endif
1694 			goto out;
1695 		}
1696 #ifdef CFSDEBUG
1697 		if (resid)
1698 			CFS_DEBUG(CFSDEBUG_FRONT)
1699 				printf("cachefs_populate: non-zero resid %ld\n",
1700 				    resid);
1701 #endif
1702 		from += size;
1703 	}
1704 	(void) cachefs_update_allocmap(cp, off, upto - off);
1705 out:
1706 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_POPULATE))
1707 		cachefs_log_populate(cachep, error,
1708 		    C_TO_FSCACHE(cp)->fs_cfsvfsp,
1709 		    &cp->c_metadata.md_cookie, cp->c_id.cid_fileno, off,
1710 		    popsize);
1711 
1712 #ifdef CFSDEBUG
1713 	CFS_DEBUG(CFSDEBUG_VOPS)
1714 		printf("cachefs_populate: EXIT cp %p error %d\n",
1715 		    (void *)cp, error);
1716 #endif
1717 	kmem_free(buf, MAXBSIZE);
1718 
1719 	return (error);
1720 }
1721 
1722 /*
1723  * due to compiler error we shifted cnode to the last argument slot.
1724  * occured during large files project - XXX.
1725  */
1726 void
1727 cachefs_cluster_allocmap(u_offset_t off, u_offset_t *popoffp,
1728     size_t *popsizep, size_t size, struct cnode *cp)
1729 {
1730 	int i;
1731 	u_offset_t lastoff = 0;
1732 	u_offset_t forward_diff = 0;
1733 	u_offset_t backward_diff = 0;
1734 
1735 	ASSERT(size <= C_TO_FSCACHE(cp)->fs_info.fi_popsize);
1736 
1737 #ifdef CFSDEBUG
1738 	CFS_DEBUG(CFSDEBUG_SUBR)
1739 		printf("cachefs_cluster_allocmap: off %llx, size %llx, "
1740 			"c_size %llx\n", off, size, (longlong_t)cp->c_size);
1741 #endif /* CFSDEBUG */
1742 	for (i = 0; i < cp->c_metadata.md_allocents; i++) {
1743 		struct cachefs_allocmap *allocp =
1744 			cp->c_metadata.md_allocinfo + i;
1745 
1746 		if (allocp->am_start_off > off) {
1747 			if ((off + size) > allocp->am_start_off) {
1748 				forward_diff = allocp->am_start_off - off;
1749 				backward_diff = size - forward_diff;
1750 				if (backward_diff > off)
1751 					backward_diff = off;
1752 				if (lastoff > (off - backward_diff))
1753 					backward_diff = off - lastoff;
1754 			} else {
1755 				forward_diff = size;
1756 			}
1757 			*popoffp = (off - backward_diff) & (offset_t)PAGEMASK;
1758 			*popsizep = ((off + forward_diff) - *popoffp) &
1759 				(offset_t)PAGEMASK;
1760 			return;
1761 		} else {
1762 			lastoff = allocp->am_start_off + allocp->am_size;
1763 		}
1764 	}
1765 	if ((lastoff + size) > off) {
1766 		*popoffp = (lastoff & (offset_t)PAGEMASK);
1767 	} else {
1768 		 *popoffp = off & (offset_t)PAGEMASK;
1769 	}
1770 
1771 	/*
1772 	 * 64bit project: popsize is the chunk size used to populate the
1773 	 * cache (default 64K). As such, 32 bit should suffice.
1774 	 */
1775 	if ((*popoffp + size) > cp->c_size)
1776 		*popsizep = (cp->c_size - *popoffp + PAGEOFFSET) &
1777 			(offset_t)PAGEMASK;
1778 	else if (size < PAGESIZE)
1779 		*popsizep = (size + PAGEOFFSET) &
1780 			(offset_t)PAGEMASK;
1781 	else
1782 		*popsizep = size & (offset_t)PAGEMASK;
1783 
1784 #ifdef CFSDEBUG
1785 	CFS_DEBUG(CFSDEBUG_SUBR)
1786 		printf("cachefs_cluster_allocmap: popoff %llx, popsize %llx\n",
1787 			(u_longlong_t)(*popoffp), (u_longlong_t)(*popsizep));
1788 #endif /* CFSDEBUG */
1789 }
1790 
1791 /*
1792  * "populate" a symlink in the cache
1793  */
1794 int
1795 cachefs_stuffsymlink(cnode_t *cp, caddr_t buf, int buflen)
1796 {
1797 	int error = 0;
1798 	struct fscache *fscp = C_TO_FSCACHE(cp);
1799 	cachefscache_t *cachep = fscp->fs_cache;
1800 	struct cachefs_metadata *mdp = &cp->c_metadata;
1801 
1802 	ASSERT(RW_WRITE_HELD(&cp->c_rwlock));
1803 	ASSERT(MUTEX_HELD(&cp->c_statelock));
1804 
1805 	if (CFS_ISFS_BACKFS_NFSV4(fscp))
1806 		goto out;
1807 
1808 	if (cp->c_flags & CN_NOCACHE)
1809 		return (ENOENT);
1810 
1811 	cp->c_size = (u_offset_t)buflen;
1812 
1813 	/* if can create a fast sym link */
1814 	if (buflen <= C_FSL_SIZE) {
1815 		/* give up the front file resources */
1816 		if (mdp->md_rlno) {
1817 			cachefs_removefrontfile(mdp, &cp->c_id, cp->c_filegrp);
1818 			cachefs_rlent_moveto(cachep, CACHEFS_RL_FREE,
1819 			    mdp->md_rlno, 0);
1820 			mdp->md_rlno = 0;
1821 			mdp->md_rltype = CACHEFS_RL_NONE;
1822 		}
1823 		/* put sym link contents in allocinfo in metadata */
1824 		bzero(mdp->md_allocinfo, C_FSL_SIZE);
1825 		bcopy(buf, mdp->md_allocinfo, buflen);
1826 
1827 		mdp->md_flags |= MD_FASTSYMLNK;
1828 		cp->c_flags &= ~CN_NEED_FRONT_SYNC;
1829 		cp->c_flags |= CN_UPDATED;
1830 		goto out;
1831 	}
1832 
1833 	/* else create a sym link in a front file */
1834 	if (cp->c_frontvp == NULL)
1835 		error = cachefs_getfrontfile(cp);
1836 	if (error)
1837 		goto out;
1838 
1839 	/* truncate front file */
1840 	error = cachefs_frontfile_size(cp, 0);
1841 	mdp->md_flags &= ~(MD_FASTSYMLNK | MD_POPULATED);
1842 	if (error)
1843 		goto out;
1844 
1845 	/* get space for the sym link */
1846 	error = cachefs_allocblocks(cachep, 1, cp->c_metadata.md_rltype);
1847 	if (error)
1848 		goto out;
1849 
1850 	/* write the sym link to the front file */
1851 	error = vn_rdwr(UIO_WRITE, cp->c_frontvp, buf, buflen, 0,
1852 	    UIO_SYSSPACE, 0, RLIM_INFINITY, kcred, NULL);
1853 	if (error) {
1854 		cachefs_freeblocks(cachep, 1, cp->c_metadata.md_rltype);
1855 		goto out;
1856 	}
1857 
1858 	cp->c_metadata.md_flags |= MD_POPULATED;
1859 	cp->c_flags |= CN_NEED_FRONT_SYNC;
1860 	cp->c_flags |= CN_UPDATED;
1861 
1862 out:
1863 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_CSYMLINK))
1864 		cachefs_log_csymlink(cachep, error, fscp->fs_cfsvfsp,
1865 		    &cp->c_metadata.md_cookie, cp->c_id.cid_fileno, buflen);
1866 
1867 	return (error);
1868 }
1869 
1870 /*
1871  * Reads the full contents of the symbolic link from the back file system.
1872  * *bufp is set to a MAXPATHLEN buffer that must be freed when done
1873  * *buflenp is the length of the link
1874  */
1875 int
1876 cachefs_readlink_back(cnode_t *cp, cred_t *cr, caddr_t *bufp, int *buflenp)
1877 {
1878 	int error;
1879 	struct uio uio;
1880 	struct iovec iov;
1881 	caddr_t buf;
1882 	fscache_t *fscp = C_TO_FSCACHE(cp);
1883 
1884 	ASSERT(MUTEX_HELD(&cp->c_statelock));
1885 
1886 	*bufp = NULL;
1887 
1888 	/* get back vnode */
1889 	if (cp->c_backvp == NULL) {
1890 		error = cachefs_getbackvp(fscp, cp);
1891 		if (error)
1892 			return (error);
1893 	}
1894 
1895 	/* set up for the readlink */
1896 	bzero(&uio, sizeof (struct uio));
1897 	bzero(&iov, sizeof (struct iovec));
1898 	buf = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
1899 	iov.iov_base = buf;
1900 	iov.iov_len = MAXPATHLEN;
1901 	uio.uio_iov = &iov;
1902 	uio.uio_iovcnt = 1;
1903 	uio.uio_resid = MAXPATHLEN;
1904 	uio.uio_segflg = UIO_SYSSPACE;
1905 	uio.uio_loffset = 0;
1906 	uio.uio_fmode = 0;
1907 	uio.uio_extflg = UIO_COPY_CACHED;
1908 	uio.uio_llimit = MAXOFFSET_T;
1909 
1910 	/* get the link data */
1911 	CFS_DPRINT_BACKFS_NFSV4(fscp,
1912 		("cachefs_readlink (nfsv4): cnode %p, backvp %p\n",
1913 		cp, cp->c_backvp));
1914 	error = VOP_READLINK(cp->c_backvp, &uio, cr);
1915 	if (error) {
1916 		cachefs_kmem_free(buf, MAXPATHLEN);
1917 	} else {
1918 		*bufp = buf;
1919 		/*LINTED alignment okay*/
1920 		*buflenp = MAXPATHLEN - (int)uio.uio_resid;
1921 	}
1922 
1923 	return (error);
1924 }
1925 
1926 int
1927 cachefs_getbackvp(struct fscache *fscp, struct cnode *cp)
1928 {
1929 	int error = 0;
1930 	int flag;
1931 
1932 #ifdef CFSDEBUG
1933 	CFS_DEBUG(CFSDEBUG_CHEAT | CFSDEBUG_BACK)
1934 		printf("cachefs_getbackvp: ENTER fscp %p cp %p\n",
1935 		    (void *)fscp, (void *)cp);
1936 #endif
1937 	ASSERT(cp != NULL);
1938 	ASSERT(MUTEX_HELD(&cp->c_statelock));
1939 	ASSERT(cp->c_backvp == NULL);
1940 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1941 
1942 	/*
1943 	 * If destroy is set then the last link to a file has been
1944 	 * removed.  Oddly enough NFS will still return a vnode
1945 	 * for the file if the timeout has not expired.
1946 	 * This causes headaches for cachefs_push because the
1947 	 * vnode is really stale.
1948 	 * So we just short circuit the problem here.
1949 	 */
1950 	if (cp->c_flags & CN_DESTROY)
1951 		return (ESTALE);
1952 
1953 	ASSERT(fscp->fs_backvfsp);
1954 	if (fscp->fs_backvfsp == NULL)
1955 		return (ETIMEDOUT);
1956 	error = VFS_VGET(fscp->fs_backvfsp, &cp->c_backvp,
1957 	    (struct fid *)&cp->c_cookie);
1958 	if (cp->c_backvp && cp->c_cred &&
1959 	    ((cp->c_flags & CN_NEEDOPEN) || (cp->c_attr.va_type == VREG))) {
1960 		/*
1961 		 * XXX bob: really should pass in the correct flag,
1962 		 * fortunately nobody pays attention to it
1963 		 */
1964 		flag = 0;
1965 		/*
1966 		 * If NEEDOOPEN is set, then this file was opened VOP_OPEN'd
1967 		 * but the backvp was not.  So, for the sake of the vnode
1968 		 * open counts used by delegation, we need to OPEN the backvp
1969 		 * with the same flags that were used for this cnode.  That way
1970 		 * when the file is VOP_CLOSE'd the counts won't go negative.
1971 		 */
1972 		if (cp->c_flags & CN_NEEDOPEN) {
1973 			cp->c_flags &= ~CN_NEEDOPEN;
1974 			if (cp->c_rdcnt > 0) {
1975 				cp->c_rdcnt--;
1976 				flag |= FREAD;
1977 			}
1978 			if (cp->c_wrcnt > 0) {
1979 				cp->c_wrcnt--;
1980 				flag |= FWRITE;
1981 			}
1982 		}
1983 		error = VOP_OPEN(&cp->c_backvp, flag, cp->c_cred);
1984 		if (error) {
1985 			VN_RELE(cp->c_backvp);
1986 			cp->c_backvp = NULL;
1987 		}
1988 	}
1989 
1990 #ifdef CFSDEBUG
1991 	CFS_DEBUG(CFSDEBUG_GENERAL | CFSDEBUG_BACK) {
1992 		if (error || cp->c_backvp == NULL) {
1993 			printf("Stale cookie cp %p fileno %llu type %d \n",
1994 			    (void *)cp, (u_longlong_t)cp->c_id.cid_fileno,
1995 			    CTOV(cp)->v_type);
1996 		}
1997 	}
1998 #endif
1999 
2000 #ifdef CFSDEBUG
2001 	CFS_DEBUG(CFSDEBUG_CHEAT | CFSDEBUG_BACK)
2002 		printf("cachefs_getbackvp: EXIT error = %d\n", error);
2003 #endif
2004 	return (error);
2005 }
2006 
2007 int
2008 cachefs_getcookie(
2009 	vnode_t *vp,
2010 	struct fid *cookiep,
2011 	struct vattr *attrp,
2012 	cred_t *cr,
2013 	uint32_t valid_fid)
2014 {
2015 	int error = 0;
2016 
2017 #ifdef CFSDEBUG
2018 	CFS_DEBUG(CFSDEBUG_CHEAT)
2019 		printf("cachefs_getcookie: ENTER vp %p\n", (void *)vp);
2020 #endif
2021 	/*
2022 	 * Get the FID only if the caller has indicated it is valid,
2023 	 * otherwise, zero the cookie.
2024 	 */
2025 	if (valid_fid) {
2026 		/*
2027 		 * This assumes that the cookie is a full size fid, if we go to
2028 		 * variable length fids we will need to change this.
2029 		 */
2030 		cookiep->fid_len = MAXFIDSZ;
2031 		error = VOP_FID(vp, cookiep);
2032 	} else {
2033 		bzero(cookiep, sizeof (*cookiep));
2034 	}
2035 
2036 	if (!error) {
2037 		if (attrp) {
2038 			ASSERT(attrp != NULL);
2039 			attrp->va_mask = AT_ALL;
2040 			error = VOP_GETATTR(vp, attrp, 0, cr);
2041 		}
2042 	} else {
2043 		if (error == ENOSPC) {
2044 			/*
2045 			 * This is an indication that the underlying filesystem
2046 			 * needs a bigger fid.  For now just map to EINVAL.
2047 			 */
2048 			error = EINVAL;
2049 		}
2050 	}
2051 #ifdef CFSDEBUG
2052 	CFS_DEBUG(CFSDEBUG_CHEAT)
2053 		printf("cachefs_getcookie: EXIT error = %d\n", error);
2054 #endif
2055 	return (error);
2056 }
2057 
2058 void
2059 cachefs_workq_init(struct cachefs_workq *qp)
2060 {
2061 	qp->wq_head = qp->wq_tail = NULL;
2062 	qp->wq_length =
2063 	    qp->wq_thread_count =
2064 	    qp->wq_max_len =
2065 	    qp->wq_halt_request = 0;
2066 	qp->wq_keepone = 0;
2067 	cv_init(&qp->wq_req_cv, NULL, CV_DEFAULT, NULL);
2068 	cv_init(&qp->wq_halt_cv, NULL, CV_DEFAULT, NULL);
2069 	mutex_init(&qp->wq_queue_lock, NULL, MUTEX_DEFAULT, NULL);
2070 }
2071 
2072 /*
2073  * return non-zero if it's `okay' to queue more requests (policy)
2074  */
2075 
2076 static int cachefs_async_max = 512;
2077 static int cachefs_async_count = 0;
2078 kmutex_t cachefs_async_lock;
2079 
2080 int
2081 cachefs_async_okay(void)
2082 {
2083 	/*
2084 	 * a value of -1 for max means to ignore freemem
2085 	 */
2086 
2087 	if (cachefs_async_max == -1)
2088 		return (1);
2089 
2090 	if (freemem < minfree)
2091 		return (0);
2092 
2093 	/*
2094 	 * a value of 0 for max means no arbitrary limit (only `freemen')
2095 	 */
2096 
2097 	if (cachefs_async_max == 0)
2098 		return (1);
2099 
2100 	ASSERT(cachefs_async_max > 0);
2101 
2102 	/*
2103 	 * check the global count against the max.
2104 	 *
2105 	 * we don't need to grab cachefs_async_lock -- we're just
2106 	 * looking, and a little bit of `fuzz' is okay.
2107 	 */
2108 
2109 	if (cachefs_async_count >= cachefs_async_max)
2110 		return (0);
2111 
2112 	return (1);
2113 }
2114 
2115 void
2116 cachefs_async_start(struct cachefs_workq *qp)
2117 {
2118 	struct cachefs_req *rp;
2119 	int left;
2120 	callb_cpr_t cprinfo;
2121 
2122 	CALLB_CPR_INIT(&cprinfo, &qp->wq_queue_lock, callb_generic_cpr, "cas");
2123 	mutex_enter(&qp->wq_queue_lock);
2124 	left = 1;
2125 	for (;;) {
2126 		/* if there are no pending requests */
2127 		if ((qp->wq_head == NULL) && (qp->wq_logwork == 0)) {
2128 			/* see if thread should exit */
2129 			if (qp->wq_halt_request || (left == -1)) {
2130 				if ((qp->wq_thread_count > 1) ||
2131 				    (qp->wq_keepone == 0))
2132 					break;
2133 			}
2134 
2135 			/* wake up thread in async_halt if necessary */
2136 			if (qp->wq_halt_request)
2137 				cv_broadcast(&qp->wq_halt_cv);
2138 
2139 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
2140 			/* sleep until there is something to do */
2141 			left = cv_timedwait(&qp->wq_req_cv,
2142 				&qp->wq_queue_lock, CFS_ASYNC_TIMEOUT + lbolt);
2143 			CALLB_CPR_SAFE_END(&cprinfo,
2144 				&qp->wq_queue_lock);
2145 			if ((qp->wq_head == NULL) && (qp->wq_logwork == 0))
2146 				continue;
2147 		}
2148 		left = 1;
2149 
2150 		if (qp->wq_logwork) {
2151 			qp->wq_logwork = 0;
2152 			mutex_exit(&qp->wq_queue_lock);
2153 			cachefs_log_process_queue(qp->wq_cachep, 1);
2154 			mutex_enter(&qp->wq_queue_lock);
2155 			continue;
2156 		}
2157 
2158 		/* remove request from the list */
2159 		rp = qp->wq_head;
2160 		qp->wq_head = rp->cfs_next;
2161 		if (rp->cfs_next == NULL)
2162 			qp->wq_tail = NULL;
2163 
2164 		/* do the request */
2165 		mutex_exit(&qp->wq_queue_lock);
2166 		cachefs_do_req(rp);
2167 		mutex_enter(&qp->wq_queue_lock);
2168 
2169 		/* decrement count of requests */
2170 		qp->wq_length--;
2171 		mutex_enter(&cachefs_async_lock);
2172 		--cachefs_async_count;
2173 		mutex_exit(&cachefs_async_lock);
2174 	}
2175 	ASSERT(qp->wq_head == NULL);
2176 	qp->wq_thread_count--;
2177 	if (qp->wq_halt_request && qp->wq_thread_count == 0)
2178 		cv_broadcast(&qp->wq_halt_cv);
2179 	CALLB_CPR_EXIT(&cprinfo);
2180 	thread_exit();
2181 	/*NOTREACHED*/
2182 }
2183 
2184 /*
2185  * attempt to halt all the async threads associated with a given workq
2186  */
2187 int
2188 cachefs_async_halt(struct cachefs_workq *qp, int force)
2189 {
2190 	int error = 0;
2191 	clock_t tend;
2192 
2193 	mutex_enter(&qp->wq_queue_lock);
2194 	if (force)
2195 		qp->wq_keepone = 0;
2196 
2197 	if (qp->wq_thread_count > 0) {
2198 		qp->wq_halt_request++;
2199 		cv_broadcast(&qp->wq_req_cv);
2200 		tend = lbolt + (60 * hz);
2201 		(void) cv_timedwait(&qp->wq_halt_cv,
2202 			&qp->wq_queue_lock, tend);
2203 		qp->wq_halt_request--;
2204 		if (qp->wq_thread_count > 0) {
2205 			if ((qp->wq_thread_count == 1) &&
2206 			    (qp->wq_length == 0) && qp->wq_keepone)
2207 				error = EAGAIN;
2208 			else
2209 				error = EBUSY;
2210 		} else {
2211 			ASSERT(qp->wq_length == 0 && qp->wq_head == NULL);
2212 		}
2213 	}
2214 	mutex_exit(&qp->wq_queue_lock);
2215 	return (error);
2216 }
2217 
2218 void
2219 cachefs_addqueue(struct cachefs_req *rp, struct cachefs_workq *qp)
2220 {
2221 	mutex_enter(&qp->wq_queue_lock);
2222 	if (qp->wq_thread_count < cachefs_max_threads) {
2223 		if (qp->wq_thread_count == 0 ||
2224 		    (qp->wq_length >= (qp->wq_thread_count * 2))) {
2225 			(void) thread_create(NULL, 0, cachefs_async_start,
2226 			    qp, 0, &p0, TS_RUN, minclsyspri);
2227 			qp->wq_thread_count++;
2228 		}
2229 	}
2230 	mutex_enter(&rp->cfs_req_lock);
2231 	if (qp->wq_tail)
2232 		qp->wq_tail->cfs_next = rp;
2233 	else
2234 		qp->wq_head = rp;
2235 	qp->wq_tail = rp;
2236 	rp->cfs_next = NULL;
2237 	qp->wq_length++;
2238 	if (qp->wq_length > qp->wq_max_len)
2239 		qp->wq_max_len = qp->wq_length;
2240 	mutex_enter(&cachefs_async_lock);
2241 	++cachefs_async_count;
2242 	mutex_exit(&cachefs_async_lock);
2243 
2244 	cv_signal(&qp->wq_req_cv);
2245 	mutex_exit(&rp->cfs_req_lock);
2246 	mutex_exit(&qp->wq_queue_lock);
2247 }
2248 
2249 void
2250 cachefs_async_putpage(struct cachefs_putpage_req *prp, cred_t *cr)
2251 {
2252 	struct cnode *cp = VTOC(prp->cp_vp);
2253 
2254 	ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(cp)) == 0);
2255 
2256 	(void) VOP_PUTPAGE(prp->cp_vp, prp->cp_off, prp->cp_len,
2257 		prp->cp_flags, cr);
2258 
2259 	mutex_enter(&cp->c_iomutex);
2260 	if (--cp->c_nio == 0)
2261 		cv_broadcast(&cp->c_iocv);
2262 	if (prp->cp_off == 0 && prp->cp_len == 0 &&
2263 	    (cp->c_ioflags & CIO_PUTPAGES)) {
2264 		cp->c_ioflags &= ~CIO_PUTPAGES;
2265 	}
2266 	mutex_exit(&cp->c_iomutex);
2267 }
2268 
2269 void
2270 cachefs_async_populate(struct cachefs_populate_req *pop, cred_t *cr)
2271 {
2272 	struct cnode *cp = VTOC(pop->cpop_vp);
2273 	struct fscache *fscp = C_TO_FSCACHE(cp);
2274 	struct filegrp *fgp = cp->c_filegrp;
2275 	int error = 0; /* not returned -- used as a place-holder */
2276 	vnode_t *frontvp = NULL, *backvp = NULL;
2277 	int havelock = 0;
2278 	vattr_t va;
2279 
2280 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
2281 
2282 	if (((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0) ||
2283 	    (fscp->fs_cdconnected != CFS_CD_CONNECTED)) {
2284 		mutex_enter(&cp->c_statelock);
2285 		cp->c_flags &= ~CN_ASYNC_POPULATE;
2286 		mutex_exit(&cp->c_statelock);
2287 		return; /* goto out */
2288 	}
2289 
2290 	error = cachefs_cd_access(fscp, 0, 0);
2291 	if (error) {
2292 #ifdef CFSDEBUG
2293 		CFS_DEBUG(CFSDEBUG_ASYNCPOP)
2294 			printf("async_pop: cd_access: err %d con %d\n",
2295 			    error, fscp->fs_cdconnected);
2296 #endif /* CFSDEBUG */
2297 		mutex_enter(&cp->c_statelock);
2298 		cp->c_flags &= ~CN_ASYNC_POPULATE;
2299 		mutex_exit(&cp->c_statelock);
2300 		return; /* goto out */
2301 	}
2302 
2303 	/*
2304 	 * grab the statelock for some minimal things
2305 	 */
2306 
2307 	rw_enter(&cp->c_rwlock, RW_WRITER);
2308 	mutex_enter(&cp->c_statelock);
2309 	havelock = 1;
2310 
2311 	if ((cp->c_flags & CN_ASYNC_POPULATE) == 0)
2312 		goto out;
2313 
2314 	/* there can be only one */
2315 	ASSERT((cp->c_flags & CN_ASYNC_POP_WORKING) == 0);
2316 	cp->c_flags |= CN_ASYNC_POP_WORKING;
2317 	cp->c_popthrp = curthread;
2318 
2319 	if (cp->c_metadata.md_flags & MD_POPULATED)
2320 		goto out;
2321 
2322 	if (cp->c_flags & CN_NOCACHE) {
2323 #ifdef CFSDEBUG
2324 		CFS_DEBUG(CFSDEBUG_ASYNCPOP)
2325 			printf("cachefs_async_populate: nocache bit on\n");
2326 #endif /* CFSDEBUG */
2327 		error = EINVAL;
2328 		goto out;
2329 	}
2330 
2331 	if (cp->c_frontvp == NULL) {
2332 		if ((cp->c_metadata.md_flags & MD_FILE) == 0) {
2333 			struct cfs_cid cid = cp->c_id;
2334 
2335 			mutex_exit(&cp->c_statelock);
2336 			havelock = 0;
2337 
2338 			/*
2339 			 * if frontfile doesn't exist, drop the lock
2340 			 * to do some of the file creation stuff.
2341 			 */
2342 
2343 			if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
2344 				error = filegrp_allocattr(fgp);
2345 				if (error != 0)
2346 					goto out;
2347 			}
2348 			if (fgp->fg_flags & CFS_FG_ALLOC_FILE) {
2349 				mutex_enter(&fgp->fg_mutex);
2350 				if (fgp->fg_flags & CFS_FG_ALLOC_FILE) {
2351 					if (fgp->fg_header->ach_nffs == 0)
2352 						error = filegrpdir_create(fgp);
2353 					else
2354 						error = filegrpdir_find(fgp);
2355 					if (error != 0) {
2356 						mutex_exit(&fgp->fg_mutex);
2357 						goto out;
2358 					}
2359 				}
2360 				mutex_exit(&fgp->fg_mutex);
2361 			}
2362 
2363 			if (fgp->fg_dirvp != NULL) {
2364 				char name[CFS_FRONTFILE_NAME_SIZE];
2365 				struct vattr *attrp;
2366 
2367 				attrp = cachefs_kmem_zalloc(
2368 				    sizeof (struct vattr), KM_SLEEP);
2369 				attrp->va_mode = S_IFREG | 0666;
2370 				attrp->va_uid = 0;
2371 				attrp->va_gid = 0;
2372 				attrp->va_type = VREG;
2373 				attrp->va_size = 0;
2374 				attrp->va_mask =
2375 				    AT_SIZE | AT_TYPE | AT_MODE |
2376 				    AT_UID | AT_GID;
2377 
2378 				make_ascii_name(&cid, name);
2379 
2380 				(void) VOP_CREATE(fgp->fg_dirvp, name, attrp,
2381 				    EXCL, 0666, &frontvp, kcred, 0);
2382 
2383 				cachefs_kmem_free(attrp,
2384 				    sizeof (struct vattr));
2385 			}
2386 
2387 			mutex_enter(&cp->c_statelock);
2388 			havelock = 1;
2389 		}
2390 		error = cachefs_getfrontfile(cp);
2391 		ASSERT((error != 0) ||
2392 		    (frontvp == NULL) ||
2393 		    (frontvp == cp->c_frontvp));
2394 	}
2395 	if ((error != 0) || (cp->c_frontvp == NULL))
2396 		goto out;
2397 
2398 	if (frontvp != NULL)
2399 		VN_RELE(frontvp);
2400 
2401 	frontvp = cp->c_frontvp;
2402 	VN_HOLD(frontvp);
2403 
2404 	if (cp->c_backvp == NULL) {
2405 		error = cachefs_getbackvp(fscp, cp);
2406 		if ((error != 0) || (cp->c_backvp == NULL))
2407 			goto out;
2408 	}
2409 	backvp = cp->c_backvp;
2410 	VN_HOLD(backvp);
2411 
2412 	switch (pop->cpop_vp->v_type) {
2413 	case VREG:
2414 		mutex_exit(&cp->c_statelock);
2415 		havelock = 0;
2416 		error = cachefs_async_populate_reg(pop, cr, backvp, frontvp);
2417 		break;
2418 	case VDIR:
2419 		error = cachefs_async_populate_dir(pop, cr, backvp, frontvp);
2420 		mutex_exit(&cp->c_statelock);
2421 		havelock = 0;
2422 		break;
2423 	default:
2424 #ifdef CFSDEBUG
2425 		printf("cachefs_async_populate: warning: vnode type = %d\n",
2426 		    pop->cpop_vp->v_type);
2427 		ASSERT(0);
2428 #endif /* CFSDEBUG */
2429 		error = EINVAL;
2430 		break;
2431 	}
2432 
2433 	if (error != 0)
2434 		goto out;
2435 
2436 	error = VOP_FSYNC(frontvp, FSYNC, cr);
2437 	if (error != 0) {
2438 #ifdef CFSDEBUG
2439 		CFS_DEBUG(CFSDEBUG_ASYNCPOP)
2440 			printf("cachefs_async_populate: fsync\n");
2441 #endif /* CFSDEBUG */
2442 		goto out;
2443 	}
2444 
2445 	/* grab the lock and finish up */
2446 	mutex_enter(&cp->c_statelock);
2447 	havelock = 1;
2448 
2449 	/* if went nocache while lock was dropped, get out */
2450 	if ((cp->c_flags & CN_NOCACHE) || (cp->c_frontvp == NULL)) {
2451 		error = EINVAL;
2452 		goto out;
2453 	}
2454 
2455 	va.va_mask = AT_MTIME;
2456 	error = VOP_GETATTR(cp->c_frontvp, &va, 0, cr);
2457 	if (error) {
2458 #ifdef CFSDEBUG
2459 		CFS_DEBUG(CFSDEBUG_ASYNCPOP)
2460 			printf("cachefs_async_populate: getattr\n");
2461 #endif /* CFSDEBUG */
2462 		goto out;
2463 	}
2464 	cp->c_metadata.md_timestamp = va.va_mtime;
2465 	cp->c_metadata.md_flags |= MD_POPULATED;
2466 	cp->c_metadata.md_flags &= ~MD_INVALREADDIR;
2467 	cp->c_flags |= CN_UPDATED;
2468 
2469 out:
2470 	if (! havelock)
2471 		mutex_enter(&cp->c_statelock);
2472 
2473 	/* see if an error happened behind our backs */
2474 	if ((error == 0) && (cp->c_flags & CN_NOCACHE)) {
2475 #ifdef CFSDEBUG
2476 		CFS_DEBUG(CFSDEBUG_ASYNCPOP)
2477 			printf("cachefs_async_populate: "
2478 			    "nocache behind our backs\n");
2479 #endif /* CFSDEBUG */
2480 		error = EINVAL;
2481 	}
2482 
2483 	cp->c_flags &= ~(CN_NEED_FRONT_SYNC | CN_POPULATION_PENDING |
2484 	    CN_ASYNC_POPULATE | CN_ASYNC_POP_WORKING);
2485 	cp->c_popthrp = NULL;
2486 
2487 	if (error != 0)
2488 		cachefs_nocache(cp);
2489 
2490 	/* unblock any threads waiting for populate to finish */
2491 	cv_broadcast(&cp->c_popcv);
2492 	mutex_exit(&cp->c_statelock);
2493 	rw_exit(&cp->c_rwlock);
2494 	cachefs_cd_release(fscp);
2495 
2496 	if (backvp != NULL) {
2497 		VN_RELE(backvp);
2498 	}
2499 	if (frontvp != NULL) {
2500 		VN_RELE(frontvp);
2501 	}
2502 }
2503 
2504 /*
2505  * only to be called from cachefs_async_populate
2506  */
2507 
2508 static int
2509 cachefs_async_populate_reg(struct cachefs_populate_req *pop, cred_t *cr,
2510     vnode_t *backvp, vnode_t *frontvp)
2511 {
2512 	struct cnode *cp = VTOC(pop->cpop_vp);
2513 	int error = 0;
2514 	u_offset_t popoff;
2515 	size_t popsize;
2516 
2517 	cachefs_cluster_allocmap(pop->cpop_off, &popoff,
2518 	    &popsize, pop->cpop_size, cp);
2519 	if (popsize == 0) {
2520 #ifdef CFSDEBUG
2521 		CFS_DEBUG(CFSDEBUG_ASYNCPOP)
2522 			printf("cachefs_async_populate: popsize == 0\n");
2523 #endif /* CFSDEBUG */
2524 		goto out;
2525 	}
2526 
2527 	error = cachefs_populate(cp, popoff, popsize, frontvp, backvp,
2528 	    cp->c_size, cr);
2529 	if (error != 0) {
2530 #ifdef CFSDEBUG
2531 		CFS_DEBUG(CFSDEBUG_ASYNCPOP)
2532 			printf("cachefs_async_populate: cachefs_populate\n");
2533 #endif /* CFSDEBUG */
2534 		goto out;
2535 	}
2536 
2537 out:
2538 	return (error);
2539 }
2540 
2541 void
2542 cachefs_do_req(struct cachefs_req *rp)
2543 {
2544 	struct cachefscache *cachep;
2545 
2546 	mutex_enter(&rp->cfs_req_lock);
2547 	switch (rp->cfs_cmd) {
2548 	case CFS_INVALID:
2549 		panic("cachefs_do_req: CFS_INVALID operation on queue");
2550 		/*NOTREACHED*/
2551 	case CFS_CACHE_SYNC:
2552 		cachep = rp->cfs_req_u.cu_fs_sync.cf_cachep;
2553 		cachefs_cache_sync(cachep);
2554 		break;
2555 	case CFS_IDLE:
2556 		cachefs_cnode_idle(rp->cfs_req_u.cu_idle.ci_vp, rp->cfs_cr);
2557 		break;
2558 	case CFS_PUTPAGE:
2559 		cachefs_async_putpage(&rp->cfs_req_u.cu_putpage, rp->cfs_cr);
2560 		VN_RELE(rp->cfs_req_u.cu_putpage.cp_vp);
2561 		break;
2562 	case CFS_POPULATE:
2563 		cachefs_async_populate(&rp->cfs_req_u.cu_populate, rp->cfs_cr);
2564 		VN_RELE(rp->cfs_req_u.cu_populate.cpop_vp);
2565 		break;
2566 	case CFS_NOOP:
2567 		break;
2568 	default:
2569 		panic("c_do_req: Invalid CFS async operation");
2570 	}
2571 	crfree(rp->cfs_cr);
2572 	rp->cfs_cmd = CFS_INVALID;
2573 	mutex_exit(&rp->cfs_req_lock);
2574 	kmem_cache_free(cachefs_req_cache, rp);
2575 }
2576 
2577 
2578 
2579 
2580 ssize_t cachefs_mem_usage = 0;
2581 
2582 struct km_wrap {
2583 	size_t kw_size;
2584 	struct km_wrap *kw_other;
2585 };
2586 
2587 kmutex_t cachefs_kmem_lock;
2588 
2589 void *
2590 cachefs_kmem_alloc(size_t size, int flag)
2591 {
2592 #ifdef DEBUG
2593 	caddr_t mp = NULL;
2594 	struct km_wrap *kwp;
2595 	size_t n = (size + (2 * sizeof (struct km_wrap)) + 7) & ~7;
2596 
2597 	ASSERT(n >= (size + 8));
2598 	mp = kmem_alloc(n, flag);
2599 	if (mp == NULL) {
2600 		return (NULL);
2601 	}
2602 	/*LINTED alignment okay*/
2603 	kwp = (struct km_wrap *)mp;
2604 	kwp->kw_size = n;
2605 	/*LINTED alignment okay*/
2606 	kwp->kw_other = (struct km_wrap *)(mp + n - sizeof (struct km_wrap));
2607 	kwp = (struct km_wrap *)kwp->kw_other;
2608 	kwp->kw_size = n;
2609 	/*LINTED alignment okay*/
2610 	kwp->kw_other = (struct km_wrap *)mp;
2611 
2612 	mutex_enter(&cachefs_kmem_lock);
2613 	ASSERT(cachefs_mem_usage >= 0);
2614 	cachefs_mem_usage += n;
2615 	mutex_exit(&cachefs_kmem_lock);
2616 
2617 	return (mp + sizeof (struct km_wrap));
2618 #else /* DEBUG */
2619 	return (kmem_alloc(size, flag));
2620 #endif /* DEBUG */
2621 }
2622 
2623 void *
2624 cachefs_kmem_zalloc(size_t size, int flag)
2625 {
2626 #ifdef DEBUG
2627 	caddr_t mp = NULL;
2628 	struct km_wrap *kwp;
2629 	size_t n = (size + (2 * sizeof (struct km_wrap)) + 7) & ~7;
2630 
2631 	ASSERT(n >= (size + 8));
2632 	mp = kmem_zalloc(n, flag);
2633 	if (mp == NULL) {
2634 		return (NULL);
2635 	}
2636 	/*LINTED alignment okay*/
2637 	kwp = (struct km_wrap *)mp;
2638 	kwp->kw_size = n;
2639 	/*LINTED alignment okay*/
2640 	kwp->kw_other = (struct km_wrap *)(mp + n - sizeof (struct km_wrap));
2641 	kwp = (struct km_wrap *)kwp->kw_other;
2642 	kwp->kw_size = n;
2643 	/*LINTED alignment okay*/
2644 	kwp->kw_other = (struct km_wrap *)mp;
2645 
2646 	mutex_enter(&cachefs_kmem_lock);
2647 	ASSERT(cachefs_mem_usage >= 0);
2648 	cachefs_mem_usage += n;
2649 	mutex_exit(&cachefs_kmem_lock);
2650 
2651 	return (mp + sizeof (struct km_wrap));
2652 #else /* DEBUG */
2653 	return (kmem_zalloc(size, flag));
2654 #endif /* DEBUG */
2655 }
2656 
2657 void
2658 cachefs_kmem_free(void *mp, size_t size)
2659 {
2660 #ifdef DEBUG
2661 	struct km_wrap *front_kwp;
2662 	struct km_wrap *back_kwp;
2663 	size_t n = (size + (2 * sizeof (struct km_wrap)) + 7) & ~7;
2664 	void *p;
2665 
2666 	ASSERT(n >= (size + 8));
2667 	front_kwp = (struct km_wrap *)((uintptr_t)mp - sizeof (struct km_wrap));
2668 	back_kwp = (struct km_wrap *)
2669 		((uintptr_t)front_kwp + n - sizeof (struct km_wrap));
2670 
2671 	ASSERT(front_kwp->kw_other == back_kwp);
2672 	ASSERT(front_kwp->kw_size == n);
2673 	ASSERT(back_kwp->kw_other == front_kwp);
2674 	ASSERT(back_kwp->kw_size == n);
2675 
2676 	mutex_enter(&cachefs_kmem_lock);
2677 	cachefs_mem_usage -= n;
2678 	ASSERT(cachefs_mem_usage >= 0);
2679 	mutex_exit(&cachefs_kmem_lock);
2680 
2681 	p = front_kwp;
2682 	front_kwp->kw_size = back_kwp->kw_size = 0;
2683 	front_kwp->kw_other = back_kwp->kw_other = NULL;
2684 	kmem_free(p, n);
2685 #else /* DEBUG */
2686 	kmem_free(mp, size);
2687 #endif /* DEBUG */
2688 }
2689 
2690 char *
2691 cachefs_strdup(char *s)
2692 {
2693 	char *rc;
2694 
2695 	ASSERT(s != NULL);
2696 
2697 	rc = cachefs_kmem_alloc(strlen(s) + 1, KM_SLEEP);
2698 	(void) strcpy(rc, s);
2699 
2700 	return (rc);
2701 }
2702 
2703 int
2704 cachefs_stats_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
2705 {
2706 	struct fscache *fscp = (struct fscache *)ksp->ks_data;
2707 	cachefscache_t *cachep = fscp->fs_cache;
2708 	int	error = 0;
2709 
2710 	if (rw == KSTAT_WRITE) {
2711 		bcopy(buf, &fscp->fs_stats, sizeof (fscp->fs_stats));
2712 		cachep->c_gc_count = fscp->fs_stats.st_gc_count;
2713 		CACHEFS_CFS_TIME_TO_TIME_COPY(fscp->fs_stats.st_gc_time,
2714 			cachep->c_gc_time);
2715 		CACHEFS_CFS_TIME_TO_TIME_COPY(fscp->fs_stats.st_gc_before_atime,
2716 			cachep->c_gc_before);
2717 		CACHEFS_CFS_TIME_TO_TIME_COPY(fscp->fs_stats.st_gc_after_atime,
2718 			cachep->c_gc_after);
2719 		return (error);
2720 	}
2721 
2722 	fscp->fs_stats.st_gc_count = cachep->c_gc_count;
2723 	CACHEFS_TIME_TO_CFS_TIME_COPY(cachep->c_gc_time,
2724 			fscp->fs_stats.st_gc_time, error);
2725 	CACHEFS_TIME_TO_CFS_TIME_COPY(cachep->c_gc_before,
2726 			fscp->fs_stats.st_gc_before_atime, error);
2727 	CACHEFS_TIME_TO_CFS_TIME_COPY(cachep->c_gc_after,
2728 			fscp->fs_stats.st_gc_after_atime, error);
2729 	bcopy(&fscp->fs_stats, buf, sizeof (fscp->fs_stats));
2730 
2731 	return (error);
2732 }
2733 
2734 #ifdef DEBUG
2735 cachefs_debug_info_t *
2736 cachefs_debug_save(cachefs_debug_info_t *oldcdb, int chain,
2737     char *message, uint_t flags, int number, void *pointer,
2738     cachefscache_t *cachep, struct fscache *fscp, struct cnode *cp)
2739 {
2740 	cachefs_debug_info_t *cdb;
2741 
2742 	if ((chain) || (oldcdb == NULL))
2743 		cdb = cachefs_kmem_zalloc(sizeof (*cdb), KM_SLEEP);
2744 	else
2745 		cdb = oldcdb;
2746 	if (chain)
2747 		cdb->cdb_next = oldcdb;
2748 
2749 	if (message != NULL) {
2750 		if (cdb->cdb_message != NULL)
2751 			cachefs_kmem_free(cdb->cdb_message,
2752 			    strlen(cdb->cdb_message) + 1);
2753 		cdb->cdb_message = cachefs_kmem_alloc(strlen(message) + 1,
2754 		    KM_SLEEP);
2755 		(void) strcpy(cdb->cdb_message, message);
2756 	}
2757 	cdb->cdb_flags = flags;
2758 	cdb->cdb_int = number;
2759 	cdb->cdb_pointer = pointer;
2760 
2761 	cdb->cdb_count++;
2762 
2763 	cdb->cdb_cnode = cp;
2764 	if (cp != NULL) {
2765 		cdb->cdb_frontvp = cp->c_frontvp;
2766 		cdb->cdb_backvp = cp->c_backvp;
2767 	}
2768 	if (fscp != NULL)
2769 		cdb->cdb_fscp = fscp;
2770 	else if (cp != NULL)
2771 		cdb->cdb_fscp = C_TO_FSCACHE(cp);
2772 	if (cachep != NULL)
2773 		cdb->cdb_cachep = cachep;
2774 	else if (cdb->cdb_fscp != NULL)
2775 		cdb->cdb_cachep = cdb->cdb_fscp->fs_cache;
2776 
2777 	cdb->cdb_thread = curthread;
2778 	cdb->cdb_timestamp = gethrtime();
2779 	cdb->cdb_depth = getpcstack(cdb->cdb_stack, CACHEFS_DEBUG_DEPTH);
2780 
2781 	return (cdb);
2782 }
2783 
2784 void
2785 cachefs_debug_show(cachefs_debug_info_t *cdb)
2786 {
2787 	hrtime_t now = gethrtime();
2788 	timestruc_t ts;
2789 	int i;
2790 
2791 	while (cdb != NULL) {
2792 		hrt2ts(now - cdb->cdb_timestamp, &ts);
2793 		printf("cdb: %p count: %d timelapse: %ld.%9ld\n",
2794 		    (void *)cdb, cdb->cdb_count, ts.tv_sec, ts.tv_nsec);
2795 		if (cdb->cdb_message != NULL)
2796 			printf("message: %s", cdb->cdb_message);
2797 		printf("flags: %x int: %d pointer: %p\n",
2798 		    cdb->cdb_flags, cdb->cdb_int, (void *)cdb->cdb_pointer);
2799 
2800 		printf("cnode: %p fscp: %p cachep: %p\n",
2801 		    (void *)cdb->cdb_cnode,
2802 		    (void *)cdb->cdb_fscp, (void *)cdb->cdb_cachep);
2803 		printf("frontvp: %p backvp: %p\n",
2804 		    (void *)cdb->cdb_frontvp, (void *)cdb->cdb_backvp);
2805 
2806 		printf("thread: %p stack...\n", (void *)cdb->cdb_thread);
2807 		for (i = 0; i < cdb->cdb_depth; i++) {
2808 			ulong_t off;
2809 			char *sym;
2810 
2811 			sym = kobj_getsymname(cdb->cdb_stack[i], &off);
2812 			printf("%s+%lx\n", sym ? sym : "?", off);
2813 		}
2814 		delay(2*hz);
2815 		cdb = cdb->cdb_next;
2816 	}
2817 	debug_enter(NULL);
2818 }
2819 #endif /* DEBUG */
2820 
2821 /*
2822  * Changes the size of the front file.
2823  * Returns 0 for success or error if cannot set file size.
2824  * NOCACHE bit is ignored.
2825  * c_size is ignored.
2826  * statelock must be held, frontvp must be set.
2827  * File must be populated if setting to a size other than zero.
2828  */
2829 int
2830 cachefs_frontfile_size(cnode_t *cp, u_offset_t length)
2831 {
2832 	cachefscache_t *cachep = C_TO_FSCACHE(cp)->fs_cache;
2833 	vattr_t va;
2834 	size_t nblks, blkdelta;
2835 	int error = 0;
2836 	int alloc = 0;
2837 	struct cachefs_allocmap *allocp;
2838 
2839 	ASSERT(MUTEX_HELD(&cp->c_statelock));
2840 	ASSERT(cp->c_frontvp);
2841 
2842 	/* if growing the file, allocate space first, we charge for holes */
2843 	if (length) {
2844 		ASSERT(cp->c_metadata.md_flags & MD_POPULATED);
2845 
2846 		nblks = (length + MAXBSIZE - 1) / MAXBSIZE;
2847 		if (nblks > cp->c_metadata.md_frontblks) {
2848 			blkdelta = nblks - cp->c_metadata.md_frontblks;
2849 			error = cachefs_allocblocks(cachep, blkdelta,
2850 			    cp->c_metadata.md_rltype);
2851 			if (error)
2852 				goto out;
2853 			alloc = 1;
2854 		}
2855 	}
2856 
2857 	/* change the size of the front file */
2858 	va.va_mask = AT_SIZE;
2859 	va.va_size = length;
2860 	error = VOP_SETATTR(cp->c_frontvp, &va, 0, kcred, NULL);
2861 	if (error)
2862 		goto out;
2863 
2864 	/* zero out the alloc map */
2865 	bzero(&cp->c_metadata.md_allocinfo,
2866 	    cp->c_metadata.md_allocents * sizeof (struct cachefs_allocmap));
2867 	cp->c_metadata.md_allocents = 0;
2868 
2869 	if (length == 0) {
2870 		/* free up blocks */
2871 		if (cp->c_metadata.md_frontblks) {
2872 			cachefs_freeblocks(cachep, cp->c_metadata.md_frontblks,
2873 			    cp->c_metadata.md_rltype);
2874 			cp->c_metadata.md_frontblks = 0;
2875 		}
2876 	} else {
2877 		/* update number of blocks if shrinking file */
2878 		nblks = (length + MAXBSIZE - 1) / MAXBSIZE;
2879 		if (nblks < cp->c_metadata.md_frontblks) {
2880 			blkdelta = cp->c_metadata.md_frontblks - nblks;
2881 			cachefs_freeblocks(cachep, blkdelta,
2882 			    cp->c_metadata.md_rltype);
2883 			cp->c_metadata.md_frontblks = (uint_t)nblks;
2884 		}
2885 
2886 		/* fix up alloc map to reflect new size */
2887 		allocp = cp->c_metadata.md_allocinfo;
2888 		allocp->am_start_off = 0;
2889 		allocp->am_size = length;
2890 		cp->c_metadata.md_allocents = 1;
2891 	}
2892 	cp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
2893 
2894 out:
2895 	if (error && alloc)
2896 		cachefs_freeblocks(cachep, blkdelta, cp->c_metadata.md_rltype);
2897 	return (error);
2898 }
2899 
2900 /*ARGSUSED*/
2901 int
2902 cachefs_req_create(void *voidp, void *cdrarg, int kmflags)
2903 {
2904 	struct cachefs_req *rp = (struct cachefs_req *)voidp;
2905 
2906 	/*
2907 	 * XXX don't do this!  if you need this, you can't use this
2908 	 * constructor.
2909 	 */
2910 
2911 	bzero(rp, sizeof (struct cachefs_req));
2912 
2913 	mutex_init(&rp->cfs_req_lock, NULL, MUTEX_DEFAULT, NULL);
2914 	return (0);
2915 }
2916 
2917 /*ARGSUSED*/
2918 void
2919 cachefs_req_destroy(void *voidp, void *cdrarg)
2920 {
2921 	struct cachefs_req *rp = (struct cachefs_req *)voidp;
2922 
2923 	mutex_destroy(&rp->cfs_req_lock);
2924 }
2925