xref: /titanic_41/usr/src/uts/common/fs/cachefs/cachefs_resource.c (revision d3d50737e566cade9a08d73d2af95105ac7cd960)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/param.h>
27 #include <sys/types.h>
28 #include <sys/systm.h>
29 #include <sys/cred.h>
30 #include <sys/proc.h>
31 #include <sys/user.h>
32 #include <sys/vfs.h>
33 #include <sys/vnode.h>
34 #include <sys/pathname.h>
35 #include <sys/uio.h>
36 #include <sys/tiuser.h>
37 #include <sys/sysmacros.h>
38 #include <sys/kmem.h>
39 #include <sys/kobj.h>
40 #include <sys/mount.h>
41 #include <sys/ioctl.h>
42 #include <sys/statvfs.h>
43 #include <sys/errno.h>
44 #include <sys/debug.h>
45 #include <sys/cmn_err.h>
46 #include <sys/utsname.h>
47 #include <sys/modctl.h>
48 #include <sys/file.h>
49 #include <sys/stat.h>
50 #include <sys/fcntl.h>
51 #include <sys/callb.h>
52 
53 #include <vm/hat.h>
54 #include <vm/as.h>
55 #include <vm/page.h>
56 #include <vm/pvn.h>
57 #include <vm/seg.h>
58 #include <vm/seg_map.h>
59 #include <vm/seg_vn.h>
60 #include <vm/rm.h>
61 #include <sys/fs/cachefs_fs.h>
62 
63 extern time_t time;
64 
65 /* forward references */
66 int cachefs_rl_entry_get(cachefscache_t *, uint_t, rl_entry_t **);
67 void cachefs_garbage_collect_queue(cachefscache_t *cachep);
68 static time_t cachefs_gc_front_atime(cachefscache_t *cachep);
69 static void cachefs_garbage_collect(cachefscache_t *cachep);
70 static void cachefs_packed_pending(cachefscache_t *cachep);
71 
72 
73 #define	RL_HEAD(cachep, type) \
74 	(&(cachep->c_rlinfo.rl_items[CACHEFS_RL_INDEX(type)]))
75 
76 /*
77  * This function moves an RL entry from wherever it currently is to
78  * the back of the requested list.
79  */
80 void
cachefs_rlent_moveto(cachefscache_t * cachep,enum cachefs_rl_type type,uint_t entno,size_t blks)81 cachefs_rlent_moveto(cachefscache_t *cachep,
82     enum cachefs_rl_type type, uint_t entno, size_t blks)
83 {
84 	mutex_enter(&cachep->c_contentslock);
85 	cachefs_cache_dirty(cachep, 0);
86 	cachefs_rlent_moveto_nolock(cachep, type, entno, blks);
87 	mutex_exit(&cachep->c_contentslock);
88 }
89 
90 void
cachefs_rlent_moveto_nolock(cachefscache_t * cachep,enum cachefs_rl_type type,uint_t entno,size_t blks)91 cachefs_rlent_moveto_nolock(cachefscache_t *cachep,
92     enum cachefs_rl_type type, uint_t entno, size_t blks)
93 {
94 	rl_entry_t *rl_ent;
95 	uint_t prev, next;
96 	cachefs_rl_listhead_t *lhp;
97 	enum cachefs_rl_type otype;
98 	int error;
99 
100 	ASSERT(entno != 0);
101 	ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0);
102 	ASSERT(MUTEX_HELD(&cachep->c_contentslock));
103 	ASSERT((CACHEFS_RL_START <= type) && (type <= CACHEFS_RL_END));
104 
105 	error = cachefs_rl_entry_get(cachep, entno, &rl_ent);
106 	if (error)
107 		return;
108 	next = rl_ent->rl_fwd_idx;
109 	prev = rl_ent->rl_bkwd_idx;
110 	otype = rl_ent->rl_current;
111 	ASSERT((CACHEFS_RL_START <= otype) && (otype <= CACHEFS_RL_END));
112 	rl_ent->rl_current = CACHEFS_RL_NONE;
113 
114 	if (type == CACHEFS_RL_PACKED_PENDING) {
115 		/* XXX sam: is this the right place to turn this on? */
116 		cachep->c_flags |= CACHE_PACKED_PENDING;
117 	}
118 
119 	/* remove entry from its previous list */
120 
121 	lhp = RL_HEAD(cachep, otype);
122 	if ((lhp->rli_back == 0) || (lhp->rli_front == 0))
123 		ASSERT((lhp->rli_back == 0) && (lhp->rli_front == 0));
124 
125 	if (lhp->rli_back == entno)
126 		lhp->rli_back = next;
127 	if (lhp->rli_front == entno)
128 		lhp->rli_front = prev;
129 	if (prev != 0) {
130 		error = cachefs_rl_entry_get(cachep, prev, &rl_ent);
131 		if (error)
132 			return;
133 		rl_ent->rl_fwd_idx = next;
134 	}
135 	if (next != 0) {
136 		error = cachefs_rl_entry_get(cachep, next, &rl_ent);
137 		if (error)
138 			return;
139 		rl_ent->rl_bkwd_idx = prev;
140 	}
141 	lhp->rli_blkcnt -= blks;
142 	lhp->rli_itemcnt--;
143 
144 	/* add entry to its new list */
145 
146 	lhp = RL_HEAD(cachep, type);
147 	error = cachefs_rl_entry_get(cachep, entno, &rl_ent);
148 	if (error)
149 		return;
150 	rl_ent->rl_current = type;
151 	rl_ent->rl_bkwd_idx = 0;
152 	rl_ent->rl_fwd_idx = lhp->rli_back;
153 
154 	if (lhp->rli_back != 0) {
155 		ASSERT(lhp->rli_front != 0);
156 		error = cachefs_rl_entry_get(cachep, lhp->rli_back, &rl_ent);
157 		if (error)
158 			return;
159 		rl_ent->rl_bkwd_idx = entno;
160 	} else {
161 		ASSERT(lhp->rli_front == 0);
162 		lhp->rli_front = entno;
163 	}
164 	lhp->rli_back = entno;
165 	lhp->rli_blkcnt += blks;
166 	lhp->rli_itemcnt++;
167 }
168 
169 /*
170  * This function verifies that an rl entry is of the `correct' type.
171  * it's used for debugging (only?).
172  */
173 
174 /*ARGSUSED*/
175 void
cachefs_rlent_verify(cachefscache_t * cachep,enum cachefs_rl_type type,uint_t entno)176 cachefs_rlent_verify(cachefscache_t *cachep,
177     enum cachefs_rl_type type, uint_t entno)
178 {
179 #ifdef CFSDEBUG
180 	rl_entry_t *rl_ent;
181 	int error;
182 
183 	ASSERT((CACHEFS_RL_START <= type) && (type <= CACHEFS_RL_END));
184 
185 	mutex_enter(&cachep->c_contentslock);
186 
187 	error = cachefs_rl_entry_get(cachep, entno, &rl_ent);
188 	if (!error && rl_ent->rl_current != type) {
189 #ifdef CFSRLDEBUG
190 		printf("cachefs_rldebug: type should be %x\n", type);
191 		cachefs_rl_debug_show(rl_ent);
192 		debug_enter("cachefs_rlent_verify");
193 #else /* CFSRLDEBUG */
194 		cmn_err(CE_WARN, "rl entry %x type = %x should be %x\n",
195 		    entno, rl_ent->rl_current, type);
196 #endif /* CFSRLDEBUG */
197 	}
198 
199 	mutex_exit(&cachep->c_contentslock);
200 #endif /* CFSDEBUG */
201 }
202 
203 /*
204  * Returns the rl data of the front of the specified resource list.
205  * Returns 0 for success, !0 if the list is empty.
206  */
207 int
cachefs_rlent_data(cachefscache_t * cachep,rl_entry_t * valp,uint_t * entnop)208 cachefs_rlent_data(cachefscache_t *cachep, rl_entry_t *valp, uint_t *entnop)
209 {
210 	uint_t entno;
211 	rl_entry_t *rl_ent;
212 	int error = 0;
213 	cachefs_rl_listhead_t *lhp;
214 	enum cachefs_rl_type type;
215 
216 	ASSERT((cachep->c_flags & CACHE_NOCACHE) == 0);
217 
218 	if (entnop == NULL)
219 		entnop = &entno;
220 	*entnop = 0;
221 
222 	mutex_enter(&cachep->c_contentslock);
223 
224 	type = valp->rl_current;
225 	ASSERT((CACHEFS_RL_START <= type) && (type <= CACHEFS_RL_END));
226 	lhp = RL_HEAD(cachep, type);
227 	entno = lhp->rli_front;
228 
229 	if (*entnop == 0) {
230 		error = ENOENT;
231 	} else {
232 		error = cachefs_rl_entry_get(cachep, *entnop, &rl_ent);
233 		if (!error)
234 			*valp = *rl_ent;
235 	}
236 	mutex_exit(&cachep->c_contentslock);
237 	return (error);
238 }
239 
240 /*
241  * This function plucks a slot from the RL free list and creates an RL entry.
242  */
243 int
cachefs_rl_alloc(struct cachefscache * cachep,rl_entry_t * valp,uint_t * entnop)244 cachefs_rl_alloc(struct cachefscache *cachep, rl_entry_t *valp, uint_t *entnop)
245 {
246 	int error = 0;
247 	uint_t entno;
248 	rl_entry_t *rl_ent;
249 	cachefs_rl_listhead_t *lhp;
250 
251 	ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0);
252 	mutex_enter(&cachep->c_contentslock);
253 
254 	cachefs_cache_dirty(cachep, 0);
255 	lhp = RL_HEAD(cachep, CACHEFS_RL_FREE);
256 	entno = lhp->rli_front;
257 	if (entno == 0) {
258 		if (cachep->c_rlinfo.rl_entries >=
259 		    cachep->c_label.cl_maxinodes) {
260 			error = ENOMEM;
261 			goto out;
262 		}
263 		entno = ++(cachep->c_rlinfo.rl_entries);
264 		lhp->rli_itemcnt++;
265 		error = cachefs_rl_entry_get(cachep, entno, &rl_ent);
266 		if (error)
267 			goto out;
268 		rl_ent->rl_current = CACHEFS_RL_NONE;
269 		rl_ent->rl_fwd_idx = 0;
270 		rl_ent->rl_bkwd_idx = 0;
271 	}
272 
273 	cachefs_rlent_moveto_nolock(cachep, CACHEFS_RL_NONE, entno, 0);
274 
275 	error = cachefs_rl_entry_get(cachep, entno, &rl_ent);
276 	if (error)
277 		goto out;
278 	rl_ent->rl_fsid = valp->rl_fsid;
279 	rl_ent->rl_fileno = valp->rl_fileno;
280 	rl_ent->rl_local = valp->rl_local;
281 	rl_ent->rl_attrc = valp->rl_attrc;
282 	rl_ent->rl_fsck = 0;
283 out:
284 	mutex_exit(&cachep->c_contentslock);
285 	if (error == 0)
286 		*entnop = entno;
287 	return (error);
288 }
289 
290 /*
291  * Call to change a local fileno in an rl entry to a normal fileno.
292  */
293 void
cachefs_rl_changefileno(cachefscache_t * cachep,uint_t entno,ino64_t fileno)294 cachefs_rl_changefileno(cachefscache_t *cachep, uint_t entno, ino64_t fileno)
295 {
296 	rl_entry_t *rl_ent;
297 	int error;
298 
299 	mutex_enter(&cachep->c_contentslock);
300 	error = cachefs_rl_entry_get(cachep, entno, &rl_ent);
301 	if (!error) {
302 		ASSERT(rl_ent->rl_local);
303 		rl_ent->rl_local = 0;
304 		rl_ent->rl_fileno = fileno;
305 	}
306 	mutex_exit(&cachep->c_contentslock);
307 }
308 
309 /*
310  * Moves the files on the modified list for this file system to
311  * the modified fix list.
312  */
313 void
cachefs_move_modified_to_mf(cachefscache_t * cachep,fscache_t * fscp)314 cachefs_move_modified_to_mf(cachefscache_t *cachep, fscache_t *fscp)
315 {
316 	rl_entry_t *list_ent;
317 	uint_t curp, nextp;
318 	cachefs_rl_listhead_t *lhp;
319 	int error;
320 
321 	ASSERT(MUTEX_HELD(&cachep->c_mflock));
322 
323 	mutex_enter(&cachep->c_contentslock);
324 
325 	lhp = RL_HEAD(cachep, CACHEFS_RL_MF);
326 	ASSERT(lhp->rli_front == 0);
327 	ASSERT(lhp->rli_back == 0);
328 	ASSERT(lhp->rli_itemcnt == 0);
329 	lhp->rli_blkcnt = 0;
330 
331 	cachefs_cache_dirty(cachep, 0);
332 
333 	/* walk the modified list */
334 	lhp = RL_HEAD(cachep, CACHEFS_RL_MODIFIED);
335 	for (curp = lhp->rli_front; curp != 0; curp = nextp) {
336 		/* get the next element */
337 		error = cachefs_rl_entry_get(cachep, curp, &list_ent);
338 		if (error) {
339 			mutex_exit(&cachep->c_contentslock);
340 			return;
341 		}
342 		nextp = list_ent->rl_bkwd_idx;
343 
344 		/* skip if element is not in this file system */
345 		if (list_ent->rl_fsid != fscp->fs_cfsid)
346 			continue;
347 
348 		/* move from modified list to mf list */
349 		cachefs_rlent_moveto_nolock(cachep, CACHEFS_RL_MF, curp, 0);
350 	}
351 	mutex_exit(&cachep->c_contentslock);
352 }
353 
354 /*
355  * Moves the contents of the active list to the rl list.
356  * Leave modified files on the active list, so they are not
357  * garbage collected.
358  */
359 void
cachefs_rl_cleanup(cachefscache_t * cachep)360 cachefs_rl_cleanup(cachefscache_t *cachep)
361 {
362 	cachefs_rl_listhead_t *lhp;
363 	rl_entry_t *rlp;
364 	uint_t entno, next;
365 	int error;
366 
367 	ASSERT(MUTEX_HELD(&cachep->c_contentslock));
368 
369 	/*
370 	 * if fsck ran, then both of these lists should be empty.  the
371 	 * only time this isn't the case is when we've done a cachefs
372 	 * boot with a clean cache.  then, the cache may have been
373 	 * clean, but files and attrfiles were left dangling.
374 	 *
375 	 * when this happens, we just fix the linked lists here.  this
376 	 * means that the attrcache header and cnode metadata might
377 	 * have incorrect information about which resource lists an
378 	 * entity is currently on.  so, we set CACHE_CHECK_RLTYPE,
379 	 * which says cache-wide to double-check and go with whatever
380 	 * is in the resource list at the time such an object is
381 	 * loaded into memory.
382 	 */
383 
384 	lhp = RL_HEAD(cachep, CACHEFS_RL_ACTIVE);
385 	if (lhp->rli_itemcnt > 0) {
386 		cachep->c_flags |= CACHE_CHECK_RLTYPE;
387 		cachefs_cache_dirty(cachep, 0);
388 	}
389 	for (entno = lhp->rli_front; entno != 0; entno = next) {
390 		error = cachefs_rl_entry_get(cachep, entno, &rlp);
391 		if (error)
392 			return;
393 		next = rlp->rl_bkwd_idx;
394 
395 		ASSERT(rlp->rl_current == CACHEFS_RL_ACTIVE);
396 		cachefs_rlent_moveto_nolock(cachep, CACHEFS_RL_GC, entno, 0);
397 	}
398 
399 #if 0
400 	lhp = RL_HEAD(cachep, CACHEFS_RL_ATTRFILE);
401 	if (lhp->rli_itemcnt > 0) {
402 		cachep->c_flags |= CACHE_CHECK_RLTYPE;
403 		cachefs_cache_dirty(cachep, 0);
404 	}
405 	for (entno = lhp->rli_front; entno != 0; entno = next) {
406 		error = cachefs_rl_entry_get(cachep, entno, &rlp);
407 		if (error)
408 			return;
409 		next = rlp->rl_bkwd_idx;
410 
411 		ASSERT(rlp->rl_current == CACHEFS_RL_ATTRFILE);
412 		cachefs_rlent_moveto_nolock(cachep, CACHEFS_RL_GC, entno, 0);
413 	}
414 #endif
415 }
416 
417 int
cachefs_allocfile(cachefscache_t * cachep)418 cachefs_allocfile(cachefscache_t *cachep)
419 {
420 	int error = 0;
421 	int collect = 0;
422 	struct statvfs64 sb;
423 	fsfilcnt64_t used;
424 
425 	(void) VFS_STATVFS(cachep->c_dirvp->v_vfsp, &sb);
426 	used = sb.f_files - sb.f_ffree;
427 
428 	mutex_enter(&cachep->c_contentslock);
429 
430 	/* if there are no more available inodes */
431 	if ((cachep->c_usage.cu_filesused >= cachep->c_label.cl_maxinodes) ||
432 	    ((cachep->c_usage.cu_filesused > cachep->c_label.cl_filemin) &&
433 	    (used > cachep->c_label.cl_filetresh))) {
434 		error = ENOSPC;
435 		if ((cachep->c_flags & CACHE_GARBAGE_COLLECT) == 0)
436 			collect = 1;
437 	}
438 
439 	/* else if there are more available inodes */
440 	else {
441 		cachefs_cache_dirty(cachep, 0);
442 		cachep->c_usage.cu_filesused++;
443 		if (((cachep->c_flags & CACHE_GARBAGE_COLLECT) == 0) &&
444 		    (cachep->c_usage.cu_filesused >=
445 		    cachep->c_label.cl_filehiwat))
446 			collect = 1;
447 	}
448 
449 	mutex_exit(&cachep->c_contentslock);
450 
451 	if (collect)
452 		cachefs_garbage_collect_queue(cachep);
453 
454 	return (error);
455 }
456 
457 void
cachefs_freefile(cachefscache_t * cachep)458 cachefs_freefile(cachefscache_t *cachep)
459 {
460 	mutex_enter(&cachep->c_contentslock);
461 	ASSERT(cachep->c_usage.cu_filesused > 0);
462 	cachefs_cache_dirty(cachep, 0);
463 	cachep->c_usage.cu_filesused--;
464 	mutex_exit(&cachep->c_contentslock);
465 }
466 
467 /*ARGSUSED*/
468 int
cachefs_allocblocks(cachefscache_t * cachep,size_t nblks,enum cachefs_rl_type type)469 cachefs_allocblocks(cachefscache_t *cachep, size_t nblks,
470     enum cachefs_rl_type type)
471 {
472 	int error = 0;
473 	int collect = 0;
474 	struct statvfs64 sb;
475 	size_t used;
476 	size_t blocks;
477 
478 	ASSERT(type != CACHEFS_RL_FREE);
479 
480 	(void) VFS_STATVFS(cachep->c_dirvp->v_vfsp, &sb);
481 	used = ((sb.f_blocks - sb.f_bfree) * sb.f_frsize) / MAXBSIZE;
482 
483 	mutex_enter(&cachep->c_contentslock);
484 
485 	/* if there are no more available blocks */
486 	blocks = cachep->c_usage.cu_blksused + nblks;
487 	if ((blocks >= cachep->c_label.cl_maxblks) ||
488 	    ((blocks > cachep->c_label.cl_blockmin) &&
489 	    (used > cachep->c_label.cl_blocktresh))) {
490 		error = ENOSPC;
491 		if ((cachep->c_flags & CACHE_GARBAGE_COLLECT) == 0)
492 			collect = 1;
493 	}
494 
495 	/* else if there are more available blocks */
496 	else {
497 		cachefs_cache_dirty(cachep, 0);
498 		cachep->c_usage.cu_blksused += (uint_t)nblks;
499 		ASSERT((CACHEFS_RL_START <= type) && (type <= CACHEFS_RL_END));
500 		RL_HEAD(cachep, type)->rli_blkcnt += nblks;
501 
502 		if (((cachep->c_flags & CACHE_GARBAGE_COLLECT) == 0) &&
503 		    (cachep->c_usage.cu_blksused >=
504 		    cachep->c_label.cl_blkhiwat))
505 			collect = 1;
506 	}
507 
508 	mutex_exit(&cachep->c_contentslock);
509 
510 	if (collect)
511 		cachefs_garbage_collect_queue(cachep);
512 
513 	return (error);
514 }
515 
516 void
cachefs_freeblocks(cachefscache_t * cachep,size_t nblks,enum cachefs_rl_type type)517 cachefs_freeblocks(cachefscache_t *cachep, size_t nblks,
518 		enum cachefs_rl_type type)
519 {
520 	mutex_enter(&cachep->c_contentslock);
521 	cachefs_cache_dirty(cachep, 0);
522 	cachep->c_usage.cu_blksused -= (uint_t)nblks;
523 	ASSERT(cachep->c_usage.cu_blksused >= 0);
524 	ASSERT((CACHEFS_RL_START <= type) && (type <= CACHEFS_RL_END));
525 	ASSERT(type != CACHEFS_RL_FREE);
526 	RL_HEAD(cachep, type)->rli_blkcnt -= nblks;
527 	mutex_exit(&cachep->c_contentslock);
528 }
529 
530 int
cachefs_victim(cachefscache_t * cachep)531 cachefs_victim(cachefscache_t *cachep)
532 {
533 	uint_t entno;
534 	rl_entry_t *rl_ent;
535 	int error = 0;
536 	ino64_t fsid;
537 	cfs_cid_t cid;
538 	struct fscache *fscp;
539 	struct filegrp *fgp;
540 	struct cachefs_metadata md;
541 	struct cnode *cp;
542 	int isattrc;
543 	cachefs_rl_listhead_t *lhp;
544 
545 	ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0);
546 	fscp = NULL;
547 	fgp = NULL;
548 
549 	/* get the file and fsid of the first item on the rl list */
550 	/* XXX call rlent_data() instead */
551 	mutex_enter(&cachep->c_contentslock);
552 	lhp = RL_HEAD(cachep, CACHEFS_RL_GC);
553 	entno = lhp->rli_front;
554 	if (entno == 0) {
555 		mutex_exit(&cachep->c_contentslock);
556 		error = ENOSPC;
557 		goto out;
558 	}
559 	error = cachefs_rl_entry_get(cachep, entno, &rl_ent);
560 	if (error) {
561 		mutex_exit(&cachep->c_contentslock);
562 		goto out;
563 	}
564 	fsid = rl_ent->rl_fsid;
565 	cid.cid_fileno = rl_ent->rl_fileno;
566 	ASSERT(rl_ent->rl_local == 0);
567 	cid.cid_flags = 0;
568 	isattrc = rl_ent->rl_attrc;
569 	mutex_exit(&cachep->c_contentslock);
570 
571 	/* get the file system cache object for this fsid */
572 	mutex_enter(&cachep->c_fslistlock);
573 	fscp = fscache_list_find(cachep, fsid);
574 	if (fscp == NULL) {
575 		fscp = fscache_create(cachep);
576 		error = fscache_activate(fscp, fsid, NULL, NULL, 0);
577 		if (error) {
578 			cmn_err(CE_WARN,
579 			    "cachefs: cache corruption, run fsck\n");
580 			fscache_destroy(fscp);
581 			fscp = NULL;
582 			mutex_exit(&cachep->c_fslistlock);
583 			error = 0;
584 			goto out;
585 		}
586 		fscache_list_add(cachep, fscp);
587 	}
588 	fscache_hold(fscp);
589 	mutex_exit(&cachep->c_fslistlock);
590 
591 	/* get the file group object for this file */
592 	mutex_enter(&fscp->fs_fslock);
593 	fgp = filegrp_list_find(fscp, &cid);
594 	if (fgp == NULL) {
595 		fgp = filegrp_create(fscp, &cid);
596 		filegrp_list_add(fscp, fgp);
597 	}
598 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
599 		if (isattrc == 0) {
600 			cmn_err(CE_WARN,
601 			    "cachefs: cache corruption, run fsck\n");
602 			delay(5*hz);
603 		}
604 		filegrp_list_remove(fscp, fgp);
605 		filegrp_destroy(fgp);
606 		error = 0;
607 		fgp = NULL;
608 		mutex_exit(&fscp->fs_fslock);
609 		goto out;
610 	}
611 
612 	/* if we are victimizing an attrcache file */
613 	if (isattrc) {
614 		mutex_enter(&fgp->fg_mutex);
615 		/* if the filegrp is not writable */
616 		if ((fgp->fg_flags & CFS_FG_WRITE) == 0) {
617 			mutex_exit(&fgp->fg_mutex);
618 			error = EROFS;
619 			fgp = NULL;
620 			mutex_exit(&fscp->fs_fslock);
621 			goto out;
622 		}
623 
624 		/* if the filegrp did not go active on us */
625 		if ((fgp->fg_count == 0) && (fgp->fg_header->ach_nffs == 0)) {
626 			mutex_exit(&fgp->fg_mutex);
627 			filegrp_list_remove(fscp, fgp);
628 			fgp->fg_header->ach_count = 0;
629 			filegrp_destroy(fgp);
630 		} else {
631 #ifdef CFSDEBUG
632 			CFS_DEBUG(CFSDEBUG_RESOURCE)
633 				printf("c_victim: filegrp went active"
634 				    " %p %llu %d %d %lld\n",
635 				    (void *) fgp,
636 				    (u_longlong_t)fgp->fg_id.cid_fileno,
637 				    fgp->fg_header->ach_rlno,
638 				    fgp->fg_count, fgp->fg_header->ach_nffs);
639 #endif
640 			ASSERT(fgp->fg_header->ach_rl_current !=
641 			    CACHEFS_RL_GC);
642 			mutex_exit(&fgp->fg_mutex);
643 		}
644 		fgp = NULL;
645 		error = 0;
646 		mutex_exit(&fscp->fs_fslock);
647 		goto out;
648 	}
649 	ASSERT((fgp->fg_flags & CFS_FG_ALLOC_FILE) == 0);
650 	filegrp_hold(fgp);
651 	mutex_exit(&fscp->fs_fslock);
652 
653 	/* grab the cnode list lock */
654 	mutex_enter(&fgp->fg_cnodelock);
655 
656 	/* see if a cnode exists for this file */
657 	(void) cachefs_cnode_find(fgp, &cid, NULL, &cp, NULL, NULL);
658 	if (cp) {
659 		VN_HOLD(CTOV(cp));
660 
661 		/* move file from rl to active list */
662 		cachefs_rlent_moveto(fscp->fs_cache,
663 		    CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno,
664 		    cp->c_metadata.md_frontblks);
665 		cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE;
666 		mutex_exit(&cp->c_statelock);
667 		mutex_exit(&fgp->fg_cnodelock);
668 		VN_RELE(CTOV(cp));
669 		error = 0;
670 		goto out;
671 	}
672 
673 	/*
674 	 * The cnode does not exist and since we hold the hashlock
675 	 * it cannot be created until we are done.
676 	 */
677 
678 	/* see if the item is no longer on the rl list, it could happen */
679 	mutex_enter(&cachep->c_contentslock);
680 	lhp = RL_HEAD(cachep, CACHEFS_RL_GC);
681 	entno = lhp->rli_front;
682 	if (entno == 0) {
683 		mutex_exit(&cachep->c_contentslock);
684 		mutex_exit(&fgp->fg_cnodelock);
685 		error = ENOSPC;
686 		goto out;
687 	}
688 	error = cachefs_rl_entry_get(cachep, entno, &rl_ent);
689 	if (error) {
690 		mutex_exit(&cachep->c_contentslock);
691 		mutex_exit(&fgp->fg_cnodelock);
692 		goto out;
693 	}
694 	if ((fsid != rl_ent->rl_fsid) ||
695 	    (cid.cid_fileno != rl_ent->rl_fileno)) {
696 		mutex_exit(&cachep->c_contentslock);
697 		mutex_exit(&fgp->fg_cnodelock);
698 		error = 0;
699 		goto out;
700 	}
701 	mutex_exit(&cachep->c_contentslock);
702 
703 	/* Get the metadata from the attrcache file */
704 	ASSERT((fgp->fg_flags & CFS_FG_ALLOC_ATTR) == 0);
705 	error = filegrp_read_metadata(fgp, &cid, &md);
706 	ASSERT(error == 0);
707 
708 	/* md.md_rltype may be incorrect, but we know file isn't active. */
709 	if (error) {
710 		/* XXX this should never happen, fix on panic */
711 		mutex_exit(&fgp->fg_cnodelock);
712 		error = 0;
713 		goto out;
714 	}
715 
716 	/* destroy the frontfile */
717 	cachefs_removefrontfile(&md, &cid, fgp);
718 
719 	/* remove the victim from the gc list */
720 	cachefs_rlent_moveto(fscp->fs_cache, CACHEFS_RL_FREE, entno, 0);
721 
722 	/* destroy the metadata */
723 	(void) filegrp_destroy_metadata(fgp, &cid);
724 
725 	mutex_exit(&fgp->fg_cnodelock);
726 	error = 0;
727 out:
728 	if (fgp) {
729 		filegrp_rele(fgp);
730 	}
731 	if (fscp) {
732 		fscache_rele(fscp);
733 	}
734 	return (error);
735 }
736 
737 static void
cachefs_garbage_collect(cachefscache_t * cachep)738 cachefs_garbage_collect(cachefscache_t *cachep)
739 {
740 	fsfilcnt64_t filelowat, filelowatmax, maxfiles, threshfiles;
741 	fsblkcnt64_t blocklowat, blocklowatmax, maxblks, threshblks;
742 	int error;
743 	struct cache_usage *cup = &cachep->c_usage;
744 
745 	ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0);
746 	mutex_enter(&cachep->c_contentslock);
747 	ASSERT(cachep->c_flags & CACHE_GARBAGE_COLLECT);
748 	filelowat = cachep->c_label.cl_filelowat;
749 	blocklowat = cachep->c_label.cl_blklowat;
750 	maxblks = cachep->c_label.cl_maxblks;
751 	maxfiles = cachep->c_label.cl_maxinodes;
752 	threshblks = cachep->c_label.cl_blocktresh;
753 	threshfiles = cachep->c_label.cl_filetresh;
754 	mutex_exit(&cachep->c_contentslock);
755 
756 	cachep->c_gc_count++;
757 	cachep->c_gc_time = time;
758 	cachep->c_gc_before = cachefs_gc_front_atime(cachep);
759 
760 	/*
761 	 * since we're here, we're running out of blocks or files.
762 	 * file and block lowat are what determine how low we garbage
763 	 * collect.  in order to do any good, we should drop below
764 	 * maxblocks, threshblocks, or the current blocks, whichever
765 	 * is smaller (same goes for files).  however, we won't go
766 	 * below an arbitrary (small) minimum for each.
767 	 */
768 
769 	/* move down for maxfiles and maxblocks */
770 	if ((filelowatmax = (maxfiles * 7) / 10) < filelowat)
771 		filelowat = filelowatmax;
772 	if ((blocklowatmax = (maxblks * 7) / 10) < blocklowat)
773 		blocklowat = blocklowatmax;
774 
775 	/* move down for threshfiles and threshblocks */
776 	if ((filelowatmax = (threshfiles * 7) / 10) < filelowat)
777 		filelowat = filelowatmax;
778 	if ((blocklowatmax = (threshblks * 7) / 10) < blocklowat)
779 		blocklowat = blocklowatmax;
780 
781 	/* move down for current files and blocks */
782 	if ((filelowatmax = ((fsfilcnt64_t)cup->cu_filesused * 7) / 10) <
783 	    filelowat)
784 		filelowat = filelowatmax;
785 	if ((blocklowatmax = ((fsblkcnt64_t)cup->cu_blksused * 7) / 10) <
786 	    blocklowat)
787 		blocklowat = blocklowatmax;
788 
789 	/* move up for an arbitrary minimum */
790 #define	MIN_BLKLO	640		/* 640*8192 == 5MB */
791 #define	MIN_FILELO	1000
792 	if (filelowat < MIN_FILELO)
793 		filelowat = MIN_FILELO;
794 	if (blocklowat < MIN_BLKLO)
795 		blocklowat = MIN_BLKLO;
796 
797 	while (cup->cu_filesused > filelowat || cup->cu_blksused > blocklowat) {
798 		/* if the thread is to terminate */
799 		if (cachep->c_flags & CACHE_CACHEW_THREADEXIT)
800 			break;
801 
802 		error = cachefs_victim(cachep);
803 		if (error)
804 			break;
805 	}
806 
807 	cachep->c_gc_after = cachefs_gc_front_atime(cachep);
808 	CACHEFS_TIME_TO_CFS_TIME_COPY(cachep->c_gc_after,
809 	    cachep->c_rlinfo.rl_gctime, error);
810 }
811 
812 /*
813  * traverse the packed pending list, repacking files when possible.
814  */
815 
816 static void
cachefs_packed_pending(cachefscache_t * cachep)817 cachefs_packed_pending(cachefscache_t *cachep)
818 {
819 	rl_entry_t rl;
820 	int error = 0; /* not returned -- used as placeholder */
821 	fscache_t *fscp = NULL;
822 	cfs_cid_t cid;
823 	cnode_t *cp;
824 	uint_t entno;
825 	int count = 0;
826 	cachefs_rl_listhead_t *lhp;
827 
828 	ASSERT(MUTEX_HELD(&cachep->c_contentslock));
829 
830 	lhp = RL_HEAD(cachep, CACHEFS_RL_PACKED_PENDING);
831 	count = lhp->rli_itemcnt;
832 
833 	mutex_exit(&cachep->c_contentslock);
834 
835 	rl.rl_current = CACHEFS_RL_PACKED_PENDING;
836 	while (cachefs_rlent_data(cachep, &rl, &entno) == 0) {
837 		if (count-- <= 0) {
838 #ifdef CFSDEBUG
839 			CFS_DEBUG(CFSDEBUG_RESOURCE)
840 				printf("cachefs_ppending: count exceeded\n");
841 #endif /* CFSDEBUG */
842 			break;
843 		}
844 		if ((cachep->c_flags &
845 		    (CACHE_PACKED_PENDING | CACHE_CACHEW_THREADEXIT)) !=
846 		    CACHE_PACKED_PENDING) {
847 #ifdef CFSDEBUG
848 			CFS_DEBUG(CFSDEBUG_RESOURCE)
849 				printf("cachefs_ppending: early exit\n");
850 #endif /* CFSDEBUG */
851 			break;
852 		}
853 		if (rl.rl_current != CACHEFS_RL_PACKED_PENDING) {
854 #ifdef CFSDEBUG
855 			CFS_DEBUG(CFSDEBUG_RESOURCE)
856 				printf("cachefs_ppending: gone from list\n");
857 #endif /* CFSDEBUG */
858 			break;
859 		}
860 
861 		/* if the fscp we have does not match */
862 		if ((fscp == NULL) || (fscp->fs_cfsid != rl.rl_fsid)) {
863 			if (fscp) {
864 				cachefs_cd_release(fscp);
865 				fscache_rele(fscp);
866 				fscp = NULL;
867 			}
868 
869 			/* get the file system cache object for this fsid */
870 			mutex_enter(&cachep->c_fslistlock);
871 			fscp = fscache_list_find(cachep, rl.rl_fsid);
872 			if (fscp == NULL) {
873 
874 				/*
875 				 * uh oh, the filesystem probably
876 				 * isn't mounted.  we `move' this
877 				 * entry onto the same list that it's
878 				 * on, which really just moves it to
879 				 * the back of the list.  we need not
880 				 * worry about an infinite loop, due
881 				 * to the counter.
882 				 */
883 
884 				cachefs_rlent_moveto(cachep,
885 				    CACHEFS_RL_PACKED_PENDING, entno, 0);
886 #ifdef CFSDEBUG
887 				CFS_DEBUG(CFSDEBUG_RESOURCE)
888 					printf("cachefs_ppending: "
889 					    "fscp find failed\n");
890 #endif /* CFSDEBUG */
891 				continue;
892 			}
893 			fscache_hold(fscp);
894 			mutex_exit(&cachep->c_fslistlock);
895 
896 			/* get access to the file system */
897 			error = cachefs_cd_access(fscp, 0, 0);
898 			if ((error) ||
899 			    (fscp->fs_cdconnected != CFS_CD_CONNECTED)) {
900 #ifdef CFSDEBUG
901 				CFS_DEBUG(CFSDEBUG_RESOURCE)
902 					printf("cachefs: "
903 					    "ppending: err %d con %d\n",
904 					    error, fscp->fs_cdconnected);
905 #endif /* CFSDEBUG */
906 				fscache_rele(fscp);
907 				fscp = NULL;
908 				break;
909 			}
910 		}
911 
912 		/* get the cnode for the file */
913 		cid.cid_fileno = rl.rl_fileno;
914 		cid.cid_flags = rl.rl_local ? CFS_CID_LOCAL : 0;
915 		error = cachefs_cnode_make(&cid, fscp,
916 		    NULL, NULL, NULL, kcred, 0, &cp);
917 		if (error) {
918 #ifdef CFSDEBUG
919 			CFS_DEBUG(CFSDEBUG_RESOURCE)
920 				printf("cachefs: "
921 				    "ppending: could not find %llu\n",
922 				    (u_longlong_t)cid.cid_fileno);
923 			delay(5*hz);
924 #endif /* CFSDEBUG */
925 			break;
926 		}
927 
928 		mutex_enter(&cp->c_statelock);
929 		if (cp->c_flags & CN_STALE) {
930 			/* back file went away behind our back */
931 			ASSERT(cp->c_metadata.md_rlno == 0);
932 			mutex_exit(&cp->c_statelock);
933 
934 #ifdef CFSDEBUG
935 			CFS_DEBUG(CFSDEBUG_RESOURCE)
936 				printf("cachefs: ppending: stale\n");
937 #endif /* CFSDEBUG */
938 
939 			VN_RELE(CTOV(cp));
940 			continue;
941 		}
942 		mutex_exit(&cp->c_statelock);
943 
944 		error = cachefs_pack_common(CTOV(cp),
945 		    (cp->c_cred) ? cp->c_cred : kcred);
946 		VN_RELE(CTOV(cp));
947 
948 		if (error != 0) {
949 #ifdef CFSDEBUG
950 			CFS_DEBUG(CFSDEBUG_RESOURCE)
951 				printf("cachefs: "
952 				    "ppending: pack_common: error = %d\n",
953 				    error);
954 #endif /* CFSDEBUG */
955 			break;
956 		}
957 	}
958 
959 	if (fscp != NULL) {
960 		cachefs_cd_release(fscp);
961 		fscache_rele(fscp);
962 	}
963 
964 	mutex_enter(&cachep->c_contentslock);
965 	if (lhp->rli_itemcnt == 0)
966 		cachep->c_flags &= ~CACHE_PACKED_PENDING;
967 }
968 
969 /* seconds; interval to do ppend list */
970 static time_t cachefs_ppend_time = 900;
971 
972 /* main routine for the cachep worker thread */
973 void
cachefs_cachep_worker_thread(cachefscache_t * cachep)974 cachefs_cachep_worker_thread(cachefscache_t *cachep)
975 {
976 	int error;
977 	struct flock64 fl;
978 	callb_cpr_t cprinfo;
979 	kmutex_t cpr_lock;
980 	clock_t wakeup;
981 
982 	/* lock the lock file for exclusive write access */
983 	fl.l_type = F_WRLCK;
984 	fl.l_whence = 0;
985 	fl.l_start = (offset_t)0;
986 	fl.l_len = (offset_t)1024;
987 	fl.l_sysid = 0;
988 	fl.l_pid = 0;
989 	error = VOP_FRLOCK(cachep->c_lockvp, F_SETLK, &fl, FWRITE, (offset_t)0,
990 	    NULL, kcred, NULL);
991 	if (error) {
992 		cmn_err(CE_WARN,
993 		    "cachefs: Can't lock Cache Lock File(r); Error %d\n",
994 		    error);
995 	}
996 
997 	mutex_init(&cpr_lock, NULL, MUTEX_DEFAULT, NULL);
998 	CALLB_CPR_INIT(&cprinfo, &cpr_lock, callb_generic_cpr, "cfs_gct");
999 	mutex_enter(&cpr_lock);
1000 	mutex_enter(&cachep->c_contentslock);
1001 
1002 	wakeup = (clock_t)(cachefs_ppend_time * hz);
1003 
1004 	/* loop while the thread is allowed to run */
1005 	while ((cachep->c_flags & CACHE_CACHEW_THREADEXIT) == 0) {
1006 		/* wait for a wakeup call */
1007 		cachep->c_flags &= ~CACHE_GARBAGE_COLLECT;
1008 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
1009 		mutex_exit(&cpr_lock);
1010 		(void) cv_reltimedwait(&cachep->c_cwcv,
1011 		    &cachep->c_contentslock, wakeup, TR_CLOCK_TICK);
1012 		mutex_enter(&cpr_lock);
1013 		CALLB_CPR_SAFE_END(&cprinfo, &cpr_lock);
1014 
1015 		/* if the thread is to terminate */
1016 		if (cachep->c_flags & CACHE_CACHEW_THREADEXIT)
1017 			break;
1018 
1019 		/* thread is running during nofill, but just to hold lock */
1020 		if (cachep->c_flags & CACHE_NOFILL)
1021 			continue;
1022 
1023 		/* if garbage collection is to run */
1024 		if (cachep->c_flags & CACHE_GARBAGE_COLLECT) {
1025 			mutex_exit(&cachep->c_contentslock);
1026 			cachefs_garbage_collect(cachep);
1027 
1028 			/*
1029 			 * Prevent garbage collection from running more
1030 			 * than once every 30 seconds.  This addresses
1031 			 * those cases which do not allow removing
1032 			 * an item from the rl by keeping gc from
1033 			 * being a spin loop.
1034 			 */
1035 			delay(30*hz); /* XXX sam: still do this? */
1036 			mutex_enter(&cachep->c_contentslock);
1037 		}
1038 
1039 		if (cachep->c_flags & CACHE_PACKED_PENDING)
1040 			cachefs_packed_pending(cachep);
1041 		ASSERT(MUTEX_HELD(&cachep->c_contentslock));
1042 	}
1043 
1044 	cachep->c_flags &= ~CACHE_CACHEW_THREADRUN;
1045 	cv_broadcast(&cachep->c_cwhaltcv);
1046 	CALLB_CPR_EXIT(&cprinfo);
1047 	mutex_exit(&cachep->c_contentslock);
1048 	mutex_destroy(&cpr_lock);
1049 
1050 	/* unlock the lock file */
1051 	fl.l_type = F_UNLCK;
1052 	fl.l_whence = 0;
1053 	fl.l_start = (offset_t)0;
1054 	fl.l_len = (offset_t)1024;
1055 	fl.l_sysid = 0;
1056 	fl.l_pid = 0;
1057 	error = VOP_FRLOCK(cachep->c_lockvp, F_SETLK, &fl, FWRITE, (offset_t)0,
1058 	    NULL, kcred, NULL);
1059 	if (error) {
1060 		cmn_err(CE_WARN, "cachefs: Can't unlock lock file\n");
1061 	}
1062 
1063 	thread_exit();
1064 	/*NOTREACHED*/
1065 }
1066 
1067 /* queues up a request to run the garbage collection */
1068 void
cachefs_garbage_collect_queue(cachefscache_t * cachep)1069 cachefs_garbage_collect_queue(cachefscache_t *cachep)
1070 {
1071 	cachefs_rl_listhead_t *lhp;
1072 
1073 	ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0);
1074 	mutex_enter(&cachep->c_contentslock);
1075 
1076 	/* quit if there is no garbage collection thread */
1077 	if ((cachep->c_flags & CACHE_CACHEW_THREADRUN) == 0) {
1078 		mutex_exit(&cachep->c_contentslock);
1079 		return;
1080 	}
1081 
1082 	/* quit if garbage collection is already in progress */
1083 	if (cachep->c_flags & CACHE_GARBAGE_COLLECT) {
1084 		mutex_exit(&cachep->c_contentslock);
1085 		return;
1086 	}
1087 
1088 	/* quit if there is no garbage to collect */
1089 	lhp = RL_HEAD(cachep, CACHEFS_RL_GC);
1090 	if (lhp->rli_front == 0) {
1091 		mutex_exit(&cachep->c_contentslock);
1092 		return;
1093 	}
1094 
1095 	/* indicate garbage collecting is in progress */
1096 	cachep->c_flags |= CACHE_GARBAGE_COLLECT;
1097 
1098 	/* wake up the garbage collection thread */
1099 	cv_signal(&cachep->c_cwcv);
1100 
1101 	mutex_exit(&cachep->c_contentslock);
1102 }
1103 
1104 #ifdef CFSRLDEBUG
1105 time_t cachefs_dbvalid = 123; /* default to non-zero junk */
1106 struct kmem_cache *cachefs_rl_debug_cache = NULL;
1107 static int cachefs_rl_debug_maxcount = CACHEFS_RLDB_DEF_MAXCOUNT;
1108 kmutex_t cachefs_rl_debug_mutex;
1109 static int cachefs_rl_debug_inuse = 0;
1110 
1111 void
cachefs_rl_debug_reclaim(void * cdrarg)1112 cachefs_rl_debug_reclaim(void *cdrarg)
1113 {
1114 	extern cachefscache_t *cachefs_cachelist;
1115 	cachefscache_t *cachep;
1116 	int index;
1117 	int error;
1118 
1119 	for (cachep = cachefs_cachelist; cachep != NULL;
1120 	    cachep = cachep->c_next) {
1121 		mutex_enter(&cachep->c_contentslock);
1122 
1123 		for (index = 0;
1124 		    index <= cachep->c_rlinfo.rl_entries;
1125 		    index++) {
1126 			rl_entry_t *rlent;
1127 
1128 			error = cachefs_rl_entry_get(cachep, index, &rlent);
1129 			if (error)
1130 				break;
1131 			cachefs_rl_debug_destroy(rlent);
1132 		}
1133 
1134 		mutex_exit(&cachep->c_contentslock);
1135 	}
1136 }
1137 
1138 void
cachefs_rl_debug_save(rl_entry_t * rlent)1139 cachefs_rl_debug_save(rl_entry_t *rlent)
1140 {
1141 	rl_debug_t *rldb, *prev, *next;
1142 	int count = 0;
1143 
1144 	mutex_enter(&cachefs_rl_debug_mutex);
1145 	if (cachefs_rl_debug_cache == NULL)
1146 		cachefs_rl_debug_cache =
1147 		    kmem_cache_create("cachefs_rl_debug",
1148 		    sizeof (rl_debug_t), 0,
1149 		    NULL, NULL, cachefs_rl_debug_reclaim, NULL, NULL, 0);
1150 
1151 	rldb = kmem_cache_alloc(cachefs_rl_debug_cache, KM_SLEEP);
1152 	++cachefs_rl_debug_inuse;
1153 
1154 	rldb->db_hrtime = gethrtime();
1155 
1156 	rldb->db_attrc = rlent->rl_attrc;
1157 	rldb->db_fsck = rlent->rl_fsck;
1158 	rldb->db_fsid = rlent->rl_fsid;
1159 	rldb->db_fileno = rlent->rl_fileno;
1160 	rldb->db_current = rlent->rl_current;
1161 
1162 	rldb->db_stackheight = getpcstack(rldb->db_stack,
1163 	    CACHEFS_RLDB_STACKSIZE);
1164 
1165 	if (rlent->rl_dbvalid == cachefs_dbvalid) {
1166 		rldb->db_next = rlent->rl_debug;
1167 	} else {
1168 		rldb->db_next = NULL;
1169 		rlent->rl_dbvalid = cachefs_dbvalid;
1170 	}
1171 	rlent->rl_debug = rldb;
1172 
1173 	prev = rldb;
1174 	for (rldb = rldb->db_next; rldb != NULL; rldb = next) {
1175 		next = rldb->db_next;
1176 		if (++count >= cachefs_rl_debug_maxcount) {
1177 			if (prev != NULL)
1178 				prev->db_next = NULL;
1179 			kmem_cache_free(cachefs_rl_debug_cache, rldb);
1180 			--cachefs_rl_debug_inuse;
1181 			prev = NULL;
1182 		} else {
1183 			prev = rldb;
1184 		}
1185 	}
1186 	mutex_exit(&cachefs_rl_debug_mutex);
1187 }
1188 
1189 void
cachefs_rl_debug_show(rl_entry_t * rlent)1190 cachefs_rl_debug_show(rl_entry_t *rlent)
1191 {
1192 	rl_debug_t *rldb;
1193 	hrtime_t now, elapse;
1194 	timestruc_t tv;
1195 	char *cname = NULL;
1196 	int i;
1197 
1198 	mutex_enter(&cachefs_rl_debug_mutex);
1199 	if (rlent->rl_dbvalid != cachefs_dbvalid) {
1200 		printf("cachefs_rldb: rl entry at %lx -- no info!\n",
1201 		    (uintptr_t)rlent);
1202 		mutex_exit(&cachefs_rl_debug_mutex);
1203 		return;
1204 	}
1205 
1206 	now = gethrtime();
1207 	hrt2ts(now, &tv);
1208 
1209 	printf("===== cachefs_rldb start at %ld =====\n", tv.tv_sec);
1210 	printf("-==== i am thread id %lx   ====-\n", (uintptr_t)curthread);
1211 
1212 	for (rldb = rlent->rl_debug;
1213 	    rldb != NULL;
1214 	    rldb = rldb->db_next) {
1215 		printf("----- cachefs_rldb record start -----\n");
1216 		elapse = now - rldb->db_hrtime;
1217 		hrt2ts(elapse, &tv);
1218 		printf("cachefs_rldb: ago = %lds %ldus\n",
1219 		    tv.tv_sec, tv.tv_nsec / 1000);
1220 
1221 		printf("cachefs_rldb: rl_attrc = %d\n", rldb->db_attrc);
1222 		printf("cachefs_rldb: rl_fsck = %d\n", rldb->db_fsck);
1223 		printf("cachefs_rldb: rl_fsid = %u\n", rldb->db_fsid);
1224 		printf("cachefs_rldb: rl_fileno = %lu\n", rldb->db_fileno);
1225 
1226 		switch (rldb->db_current) {
1227 		case CACHEFS_RL_NONE:
1228 			cname = "CACHEFS_RL_NONE";
1229 			break;
1230 		case CACHEFS_RL_FREE:
1231 			cname = "CACHEFS_RL_FREE";
1232 			break;
1233 		case CACHEFS_RL_GC:
1234 			cname = "CACHEFS_RL_GC";
1235 			break;
1236 		case CACHEFS_RL_ACTIVE:
1237 			cname = "CACHEFS_RL_ACTIVE";
1238 			break;
1239 		case CACHEFS_RL_ATTRFILE:
1240 			cname = "CACHEFS_RL_ATTRFILE";
1241 			break;
1242 		case CACHEFS_RL_MODIFIED:
1243 			cname = "CACHEFS_RL_MODIFIED";
1244 			break;
1245 		case CACHEFS_RL_PACKED:
1246 			cname = "CACHEFS_RL_PACKED";
1247 			break;
1248 		case CACHEFS_RL_PACKED_PENDING:
1249 			cname = "CACHEFS_RL_PACKED_PENDING";
1250 			break;
1251 		case CACHEFS_RL_MF:
1252 			cname = "CACHEFS_MF_GC";
1253 			break;
1254 		}
1255 		if (cname != NULL) {
1256 			printf("cachefs_rldb: state = %s\n", cname);
1257 		} else {
1258 			printf("cachefs_rldb: undefined state %x\n",
1259 			    rldb->db_current);
1260 		}
1261 
1262 		printf("cachefs_rldb: stack trace\n");
1263 		for (i = 0; i < rldb->db_stackheight; i++) {
1264 			char *sym;
1265 			uint_t off;
1266 
1267 			sym = kobj_getsymname(rldb->db_stack[i], &off);
1268 			printf("cachefs_rldb:    %s+%lx\n",
1269 			    sym ? sym : "?", off);
1270 			delay(hz/4);
1271 		}
1272 
1273 		printf("----- cachefs_rldb record end -----\n");
1274 	}
1275 
1276 	mutex_exit(&cachefs_rl_debug_mutex);
1277 }
1278 
1279 void
cachefs_rl_debug_destroy(rl_entry_t * rlent)1280 cachefs_rl_debug_destroy(rl_entry_t *rlent)
1281 {
1282 	rl_debug_t *rldb, *next;
1283 
1284 	mutex_enter(&cachefs_rl_debug_mutex);
1285 	if (rlent->rl_dbvalid != cachefs_dbvalid) {
1286 		rlent->rl_debug = NULL;
1287 		mutex_exit(&cachefs_rl_debug_mutex);
1288 		return;
1289 	}
1290 
1291 	for (rldb = rlent->rl_debug; rldb != NULL; rldb = next) {
1292 		next = rldb->db_next;
1293 		kmem_cache_free(cachefs_rl_debug_cache, rldb);
1294 		--cachefs_rl_debug_inuse;
1295 	}
1296 
1297 	rlent->rl_debug = NULL;
1298 	mutex_exit(&cachefs_rl_debug_mutex);
1299 }
1300 #endif /* CFSRLDEBUG */
1301 
1302 int
cachefs_rl_entry_get(cachefscache_t * cachep,uint_t entno,rl_entry_t ** ent)1303 cachefs_rl_entry_get(cachefscache_t *cachep, uint_t entno, rl_entry_t **ent)
1304 {
1305 	rl_entry_t *rl_ent;
1306 	uint_t whichwindow, winoffset;
1307 	int error = 0;
1308 
1309 	ASSERT(MUTEX_HELD(&cachep->c_contentslock));
1310 	ASSERT(entno <= cachep->c_label.cl_maxinodes); /* strictly less? */
1311 #if 0
1312 	ASSERT((cachep->c_flags & CACHE_NOFILL) == 0);
1313 #endif
1314 
1315 	whichwindow = entno / CACHEFS_RLPMBS;
1316 	winoffset = entno % CACHEFS_RLPMBS;
1317 
1318 	if ((cachep->c_rl_entries == NULL) ||
1319 	    (cachep->c_rl_window != whichwindow)) {
1320 		if (cachep->c_rl_entries != NULL) {
1321 			error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp,
1322 			    (caddr_t)cachep->c_rl_entries, MAXBSIZE,
1323 			    (offset_t)((cachep->c_rl_window + 1) * MAXBSIZE),
1324 			    UIO_SYSSPACE, 0, RLIM_INFINITY, kcred, NULL);
1325 			if (error)
1326 				return (error);
1327 		}
1328 		else
1329 			cachep->c_rl_entries = (rl_entry_t *)
1330 			    cachefs_kmem_alloc(MAXBSIZE, KM_SLEEP);
1331 
1332 		error = vn_rdwr(UIO_READ, cachep->c_resfilevp,
1333 		    (caddr_t)cachep->c_rl_entries, MAXBSIZE,
1334 		    (offset_t)((whichwindow + 1) * MAXBSIZE),
1335 		    UIO_SYSSPACE, 0, RLIM_INFINITY, kcred, NULL);
1336 		if (error) {
1337 			cachefs_kmem_free(cachep->c_rl_entries, MAXBSIZE);
1338 			cachep->c_rl_entries = NULL;
1339 			return (error);
1340 		}
1341 		cachep->c_rl_window = whichwindow;
1342 	}
1343 	rl_ent = &cachep->c_rl_entries[winoffset];
1344 
1345 	*ent = rl_ent;
1346 #ifdef CFSRLDEBUG
1347 	cachefs_rl_debug_save(rl_ent);
1348 #endif /* CFSRLDEBUG */
1349 
1350 	return (error);
1351 }
1352 
1353 static time_t
cachefs_gc_front_atime(cachefscache_t * cachep)1354 cachefs_gc_front_atime(cachefscache_t *cachep)
1355 {
1356 	char namebuf[CFS_FRONTFILE_NAME_SIZE];
1357 
1358 	rl_entry_t rl, *rl_ent;
1359 	uint_t entno, fgsize;
1360 	cfs_cid_t dircid, cid;
1361 	struct fscache *fscp;
1362 	cachefs_rl_listhead_t *lhp;
1363 	int error;
1364 
1365 	struct vnode *dirvp, *filevp;
1366 	struct vattr va;
1367 
1368 	int reledir = 0;
1369 	int gotfile = 0;
1370 	time_t rc = (time_t)0;
1371 
1372 	mutex_enter(&cachep->c_contentslock);
1373 	lhp = RL_HEAD(cachep, CACHEFS_RL_GC);
1374 	entno = lhp->rli_front;
1375 	if (entno == 0) {
1376 		mutex_exit(&cachep->c_contentslock);
1377 		goto out;
1378 	}
1379 
1380 	error = cachefs_rl_entry_get(cachep, entno, &rl_ent);
1381 	if (error) {
1382 		mutex_exit(&cachep->c_contentslock);
1383 		goto out;
1384 	}
1385 	rl = *rl_ent;
1386 	mutex_exit(&cachep->c_contentslock);
1387 	cid.cid_fileno = rl.rl_fileno;
1388 	ASSERT(rl.rl_local == 0);
1389 	cid.cid_flags = 0;
1390 	dircid.cid_flags = 0;
1391 	mutex_enter(&cachep->c_fslistlock);
1392 	if ((fscp = fscache_list_find(cachep, rl.rl_fsid)) == NULL) {
1393 		mutex_exit(&cachep->c_fslistlock);
1394 		goto out;
1395 	}
1396 
1397 	if (rl.rl_attrc) {
1398 		make_ascii_name(&cid, namebuf);
1399 		dirvp = fscp->fs_fsattrdir;
1400 	} else {
1401 		dirvp = NULL;
1402 		fgsize = fscp->fs_info.fi_fgsize;
1403 		dircid.cid_fileno = ((cid.cid_fileno / fgsize) * fgsize);
1404 		make_ascii_name(&dircid, namebuf);
1405 		if (VOP_LOOKUP(fscp->fs_fscdirvp, namebuf,
1406 		    &dirvp, (struct pathname *)NULL, 0,
1407 		    (vnode_t *)NULL, kcred, NULL, NULL, NULL) == 0) {
1408 			make_ascii_name(&cid, namebuf);
1409 			reledir++;
1410 		} else {
1411 			mutex_exit(&cachep->c_fslistlock);
1412 			goto out;
1413 		}
1414 	}
1415 	if (dirvp && VOP_LOOKUP(dirvp, namebuf, &filevp,
1416 	    (struct pathname *)NULL, 0,
1417 	    (vnode_t *)NULL, kcred, NULL, NULL, NULL) == 0) {
1418 		gotfile = 1;
1419 	}
1420 	if (reledir)
1421 		VN_RELE(dirvp);
1422 	mutex_exit(&cachep->c_fslistlock);
1423 
1424 	if (gotfile) {
1425 		va.va_mask = AT_ATIME;
1426 		if (VOP_GETATTR(filevp, &va, 0, kcred, NULL) == 0)
1427 			rc = va.va_atime.tv_sec;
1428 		VN_RELE(filevp);
1429 	}
1430 
1431 out:
1432 	return (rc);
1433 }
1434