xref: /titanic_41/usr/src/uts/common/fs/cachefs/cachefs_filegrp.c (revision d58fda4376e4bf67072ce2e69f6f47036f9dbb68)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/systm.h>
31 #include <sys/cred.h>
32 #include <sys/proc.h>
33 #include <sys/user.h>
34 #include <sys/vfs.h>
35 #include <sys/vnode.h>
36 #include <sys/pathname.h>
37 #include <sys/uio.h>
38 #include <sys/tiuser.h>
39 #include <sys/sysmacros.h>
40 #include <sys/kmem.h>
41 #include <sys/mount.h>
42 #include <sys/ioctl.h>
43 #include <sys/statvfs.h>
44 #include <sys/errno.h>
45 #include <sys/debug.h>
46 #include <sys/cmn_err.h>
47 #include <sys/utsname.h>
48 #include <sys/bootconf.h>
49 #include <sys/modctl.h>
50 #include <sys/file.h>
51 #include <sys/stat.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 #include <sys/fs/cachefs_log.h>
63 
64 struct kmem_cache *cachefs_filegrp_cache = NULL;
65 
66 #if (defined(_SYSCALL32_IMPL) || defined(_LP64))
67 
68 #define	CACHEFS_ALLOC_CFS_METADATA(p, inp)				\
69 	p = cachefs_kmem_zalloc(sizeof (struct cfs_cachefs_metadata), KM_SLEEP)
70 
71 #define	CACHEFS_FREE_CFS_METADATA(p)					\
72 	cachefs_kmem_free(p, sizeof (struct cfs_cachefs_metadata))
73 
74 /* CACHEFS_COPY_COMMON_METADATA_FIELDS - common code for the metadata copy */
75 #define	CACHEFS_COPY_COMMON_METADATA_FIELDS(inmdp, outmdp)		\
76 	(outmdp)->md_aclclass = (inmdp)->md_aclclass;			\
77 	CACHEFS_FID_COPY(&(inmdp)->md_cookie, &(outmdp)->md_cookie);	\
78 	(outmdp)->md_flags = (inmdp)->md_flags;				\
79 	(outmdp)->md_rlno = (inmdp)->md_rlno;				\
80 	(outmdp)->md_rltype = (inmdp)->md_rltype;			\
81 	(outmdp)->md_consttype = (inmdp)->md_consttype;			\
82 	CACHEFS_FID_COPY(&(inmdp)->md_fid, &(outmdp)->md_fid);		\
83 	(outmdp)->md_frontblks = (inmdp)->md_frontblks;			\
84 	(outmdp)->md_gen = (inmdp)->md_gen;				\
85 	(outmdp)->md_parent = (inmdp)->md_parent;			\
86 	(outmdp)->md_resettimes = (inmdp)->md_resettimes;		\
87 	(outmdp)->md_localfileno = (inmdp)->md_localfileno;		\
88 	(outmdp)->md_resetfileno = (inmdp)->md_resetfileno;		\
89 	(outmdp)->md_seq = (inmdp)->md_seq;				\
90 	(outmdp)->md_allocents = (inmdp)->md_allocents;			\
91 	bcopy(&(inmdp)->md_allocinfo, &(outmdp)->md_allocinfo,		\
92 	    MIN(sizeof (inmdp)->md_allocinfo, sizeof (outmdp)->md_allocinfo))
93 
94 #define	CACHEFS_COPY_METADATA_TO_CFS_METADATA(inmdp, outmdp, error)	\
95 	CACHEFS_VATTR_TO_CFS_VATTR_COPY(&(inmdp)->md_vattr,		\
96 		&(outmdp)->md_vattr, error);				\
97 	CACHEFS_TS_TO_CFS_TS_COPY(&(inmdp)->md_timestamp,		\
98 		&(outmdp)->md_timestamp, error);			\
99 	CACHEFS_TS_TO_CFS_TS_COPY(&(inmdp)->md_x_time,			\
100 		&(outmdp)->md_x_time, error);				\
101 	CACHEFS_TS_TO_CFS_TS_COPY(&(inmdp)->md_localmtime,		\
102 		&(outmdp)->md_localmtime, error);			\
103 	CACHEFS_TS_TO_CFS_TS_COPY(&(inmdp)->md_localctime,		\
104 		&(outmdp)->md_localctime, error);			\
105 	CACHEFS_COPY_COMMON_METADATA_FIELDS(inmdp, outmdp)
106 
107 #define	CACHEFS_COPY_CFS_METADATA_TO_METADATA(inmdp, outmdp)		\
108 	CACHEFS_CFS_VATTR_TO_VATTR_COPY(&(inmdp)->md_vattr,		\
109 		&(outmdp)->md_vattr);					\
110 	CACHEFS_CFS_TS_TO_TS_COPY(&(inmdp)->md_timestamp,		\
111 		&(outmdp)->md_timestamp);				\
112 	CACHEFS_CFS_TS_TO_TS_COPY(&(inmdp)->md_x_time,			\
113 		&(outmdp)->md_x_time);					\
114 	CACHEFS_CFS_TS_TO_TS_COPY(&(inmdp)->md_localmtime,		\
115 		&(outmdp)->md_localmtime);				\
116 	CACHEFS_CFS_TS_TO_TS_COPY(&(inmdp)->md_localctime,		\
117 		&(outmdp)->md_localctime);				\
118 	CACHEFS_COPY_COMMON_METADATA_FIELDS(inmdp, outmdp)
119 
120 #else /* not (_SYSCALL32_IMPL || _LP64) */
121 
122 #define	CACHEFS_ALLOC_CFS_METADATA(p, inp)				\
123 	p = (cfs_cachefs_metadata_t *)(inp)
124 
125 #define	CACHEFS_FREE_CFS_METADATA(p)
126 
127 #define	CACHEFS_COPY_METADATA_TO_CFS_METADATA(inmdp, outmdp, error)
128 
129 #define	CACHEFS_COPY_CFS_METADATA_TO_METADATA(inmdp, outmdp)
130 
131 #endif /* _SYSCALL32_IMPL || _LP64 */
132 
133 /* forward references */
134 int filegrp_write_space(vnode_t *vp, offset_t offset, ssize_t cnt);
135 int filegrpattr_find(struct filegrp *fgp);
136 int filegrpattr_create(struct filegrp *fgp);
137 
138 int
139 /*ARGSUSED*/
140 filegrp_cache_create(void *voidp, void *cdrarg, int kmflags)
141 {
142 	filegrp_t *fgp = (filegrp_t *)voidp;
143 
144 	mutex_init(&fgp->fg_mutex, NULL, MUTEX_DEFAULT, NULL);
145 	mutex_init(&fgp->fg_cnodelock, NULL, MUTEX_DEFAULT, NULL);
146 	return (0);
147 }
148 
149 void
150 /*ARGSUSED*/
151 filegrp_cache_destroy(void *voidp, void *cdrarg)
152 {
153 	filegrp_t *fgp = (filegrp_t *)voidp;
154 
155 	mutex_destroy(&fgp->fg_mutex);
156 	mutex_destroy(&fgp->fg_cnodelock);
157 }
158 
159 /*
160  * ------------------------------------------------------------------
161  *
162  *		filegrp_create
163  *
164  * Description:
165  *	Creates a filegrp object for the specified fscache.
166  *	The CFS_FG_ALLOC_{ATTR, FILE} bits will be set in fg_flags
167  *	if the cache is in NOCACHE and NOFILL mode or if
168  *	the directory does not exist yet.
169  *	The filegrp object maintains a reference to the specified
170  *	fscache.
171  * Arguments:
172  *	fscp	fscache to create the file group in
173  *	cidp	start cid for the file group
174  * Returns:
175  *	Returns the created filegrp object.
176  * Preconditions:
177  *	precond(fscp)
178  *	precond(cidp)
179  *	precond(fscp->fs_info.fi_fgsize > 0)
180  */
181 #define	Bugid_1249206_notfixed
182 #ifdef Bugid_1249206_notfixed
183 int bugid_1249206 = 0;
184 #endif
185 filegrp_t *
186 filegrp_create(struct fscache *fscp, cfs_cid_t *cidp)
187 {
188 	filegrp_t *fgp;
189 	int fgsize;
190 	int flags;
191 	ino64_t nfgsize;
192 
193 	fgsize = fscp->fs_info.fi_fgsize;
194 
195 	fgp = (filegrp_t *)
196 	    kmem_cache_alloc(cachefs_filegrp_cache, KM_SLEEP);
197 
198 	fgp->fg_flags = CFS_FG_ALLOC_ATTR | CFS_FG_ALLOC_FILE;
199 	fgp->fg_count = 0;
200 	fgp->fg_id = *cidp;
201 #ifdef Bugid_1249206_notfixed
202 	if (bugid_1249206)
203 		cmn_err(CE_CONT, "fg_id assigned value is %" PRId64 "\n",
204 		    fgp->fg_id.cid_fileno);
205 #endif
206 	nfgsize = (fgp->fg_id.cid_fileno / (ino64_t)fgsize);
207 	fgp->fg_id.cid_fileno = (ino64_t)(nfgsize * (ino64_t)fgsize);
208 #ifdef Bugid_1249206_notfixed
209 	if (bugid_1249206) {
210 		cmn_err(CE_CONT,
211 		    "cid_fileno for fscp %p fgp %p is %" PRId64 "\n",
212 		    (void *)fscp, (void *)fgp,
213 		    fgp->fg_id.cid_fileno);
214 		cmn_err(CE_CONT,
215 		    "sent fileno is %" PRId64 " fgsize %d nfgsize %" PRId64
216 		    "\n", cidp->cid_fileno, fgsize, nfgsize);
217 	}
218 #endif
219 	fgp->fg_fscp = fscp;
220 	fgp->fg_cnodelist = NULL;
221 	fgp->fg_next = NULL;
222 	fgp->fg_dirvp = NULL;
223 	fgp->fg_attrvp = NULL;
224 	fgp->fg_header = NULL;
225 	fgp->fg_offsets = NULL;
226 	fgp->fg_alloclist = NULL;
227 
228 	fgp->fg_headersize = (u_int)sizeof (struct attrcache_header) +
229 	    (fgsize * (u_int)sizeof (struct attrcache_index)) +
230 	    ((fgsize + 7) >> 3);
231 
232 	fgp->fg_filesize = fgp->fg_headersize +
233 	    (fgsize * (u_int)sizeof (struct cfs_cachefs_metadata));
234 
235 	flags = fscp->fs_flags;
236 	if (flags & CFS_FS_READ) {
237 		fgp->fg_flags |= CFS_FG_READ;
238 		if (flags & CFS_FS_WRITE) {
239 			fgp->fg_flags |= CFS_FG_WRITE;
240 		}
241 	}
242 
243 	if (fgp->fg_flags & CFS_FG_READ) {
244 		/* find the attrcache file and frontfile directory */
245 		(void) filegrpattr_find(fgp);
246 
247 		/*
248 		 * XXX: we can tell from the file count in the attrcache
249 		 * whether we can expect to find a front file dir or
250 		 * not.  If not, we can save the lookup here...
251 		 */
252 		(void) filegrpdir_find(fgp);
253 	}
254 
255 	return (fgp);
256 }
257 
258 /*
259  * ------------------------------------------------------------------
260  *
261  *		filegrp_destroy
262  *
263  * Description:
264  *	Destroys the filegrp object and releases any kernel
265  *	resource associated with it.
266  *	Additionally if the on disk file group directory does
267  *	not contain any front files it is removed.
268  * Arguments:
269  *	fgp	filegrp object to destroy
270  * Returns:
271  * Preconditions:
272  *	precond(fgp is a valid filegrp object)
273  *	precond(fgp->fg_count == 0)
274  *	precond(fgp->fg_next == NULL)
275  */
276 
277 void
278 filegrp_destroy(filegrp_t *fgp)
279 {
280 	struct fscache *fscp = fgp->fg_fscp;
281 	char name[CFS_FRONTFILE_NAME_SIZE];
282 	char *fname;
283 	int error;
284 
285 	ASSERT(fgp->fg_count == 0);
286 	ASSERT(fgp->fg_next == NULL);
287 
288 	if (fgp->fg_attrvp) {
289 		if (fgp->fg_flags & CFS_FG_UPDATED) {
290 			error = filegrp_sync(fgp);
291 			if (error)
292 				cmn_err(CE_WARN,
293 				    "cachefs: UFS error on cache, "
294 				    "run fsck %d", error);
295 		}
296 		VN_RELE(fgp->fg_attrvp);
297 	}
298 	if (fgp->fg_header) {
299 		/*
300 		 * If there are no attrcache entries in use and
301 		 * if we can modify the cache.
302 		 */
303 		if ((fgp->fg_header->ach_count == 0) &&
304 		    (fgp->fg_flags & CFS_FG_WRITE)) {
305 			ASSERT(fgp->fg_header->ach_nffs == 0);
306 
307 			/* remove attrcache file from the rl list */
308 			ASSERT(fgp->fg_header->ach_rl_current ==
309 			    CACHEFS_RL_GC);
310 #ifdef CFSDEBUG
311 			cachefs_rlent_verify(fscp->fs_cache, CACHEFS_RL_GC,
312 			    fgp->fg_header->ach_rlno);
313 #endif /* CFSDEBUG */
314 
315 			/*
316 			 * XXX sam: since we're blowing away the
317 			 * attrcache file, i guess i don't need to set
318 			 * ach_rl_current to CACHEFS_RL_NONE and
319 			 * sync the attrcache file, right?
320 			 *
321 			 * fgp->fg_header->ach_rl_current = CACHEFS_RL_NONE;
322 			 * fgp->fg_flags |= CFS_FG_UPDATED;
323 			 */
324 
325 			/* remove the attrcache file */
326 			make_ascii_name(&fgp->fg_id, name);
327 			fname = name;
328 			error = VOP_REMOVE(fscp->fs_fsattrdir, fname, kcred);
329 			if (error) {
330 				cmn_err(CE_WARN,
331 				    "cachefs: error in cache, run fsck");
332 			} else {
333 				cachefs_freefile(fscp->fs_cache);
334 				cachefs_freeblocks(fscp->fs_cache,
335 				    fgp->fg_header->ach_nblks, CACHEFS_RL_GC);
336 				cachefs_rlent_moveto(fscp->fs_cache,
337 				    CACHEFS_RL_FREE, fgp->fg_header->ach_rlno,
338 				    0);
339 			}
340 		}
341 		cachefs_kmem_free(fgp->fg_header, fgp->fg_headersize);
342 	}
343 	if (fgp->fg_dirvp) {
344 		VN_RELE(fgp->fg_dirvp);
345 	}
346 	kmem_cache_free(cachefs_filegrp_cache, fgp);
347 }
348 
349 /*
350  * ------------------------------------------------------------------
351  *
352  *		filegrp_allocattr
353  *
354  * Description:
355  *	Tries to find the attrcache file for the given filegroup.
356  *	If the file does not yet exist it is created.
357  * Arguments:
358  *	fgp	filegrp object
359  * Returns:
360  *	Returns 0 on success, an errno value on failure.
361  * Preconditions:
362  *	precond(fgp is a valid filegrp object)
363  */
364 
365 int
366 filegrp_allocattr(filegrp_t *fgp)
367 {
368 	int error = 0;
369 
370 	mutex_enter(&fgp->fg_mutex);
371 
372 	/* if we do not yet have the attrcache file */
373 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
374 		/* fail if we tried to create it but failed previously */
375 		if (fgp->fg_flags & CFS_FG_NOCACHE) {
376 			error = ENOENT;
377 			goto out;
378 		}
379 
380 		/* fail if we cannot read from the cache */
381 		if ((fgp->fg_flags & CFS_FG_READ) == 0) {
382 			error = ENOENT;
383 			goto out;
384 		}
385 
386 		/* try to find the attrcache file in the cache */
387 		error = filegrpattr_find(fgp);
388 		if (error == ENOENT) {
389 			/* fail if we cannot create the attrcache file */
390 			if ((fgp->fg_flags & CFS_FG_WRITE) == 0) {
391 				error = ENOENT;
392 				goto out;
393 			}
394 
395 			/* try to create the attrcache file */
396 			error = filegrpattr_create(fgp);
397 		}
398 	}
399 out:
400 	mutex_exit(&fgp->fg_mutex);
401 
402 	return (error);
403 }
404 
405 /*
406  * ------------------------------------------------------------------
407  *
408  *		filegrp_hold
409  *
410  * Description:
411  *	Increments the number of references to this filegrp object.
412  * Arguments:
413  *	fgp	filegrp object to reference
414  * Returns:
415  * Preconditions:
416  *	precond(fgp is a valid filegrp object)
417  */
418 
419 void
420 filegrp_hold(filegrp_t *fgp)
421 {
422 	mutex_enter(&fgp->fg_mutex);
423 
424 	fgp->fg_count++;
425 
426 	/* remove attrcache file from the rl list if necessary */
427 	if ((fgp->fg_flags & CFS_FG_WRITE) &&
428 	    (fgp->fg_header != NULL) &&
429 	    (fgp->fg_header->ach_rl_current == CACHEFS_RL_GC)) {
430 #ifdef CFSDEBUG
431 		cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
432 		    CACHEFS_RL_GC, fgp->fg_header->ach_rlno);
433 #endif /* CFSDEBUG */
434 		cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
435 		    CACHEFS_RL_ATTRFILE, fgp->fg_header->ach_rlno,
436 		    fgp->fg_header->ach_nblks);
437 		fgp->fg_header->ach_rl_current = CACHEFS_RL_ATTRFILE;
438 		fgp->fg_flags |= CFS_FG_UPDATED;
439 	}
440 
441 	mutex_exit(&fgp->fg_mutex);
442 }
443 
444 /*
445  * ------------------------------------------------------------------
446  *
447  *		filegrp_rele
448  *
449  * Description:
450  *	Decrements the number of references to this filegrp object.
451  * Arguments:
452  *	fgp	filegrp object to dereference
453  * Returns:
454  * Preconditions:
455  *	precond(fgp is a valid filegrp object)
456  *	precond(number of refrences to filegrp is > 0)
457  */
458 
459 void
460 filegrp_rele(filegrp_t *fgp)
461 {
462 	mutex_enter(&fgp->fg_mutex);
463 	ASSERT(fgp->fg_count > 0);
464 
465 	/* move attrcache file to the rl list if necessary */
466 	if (((fgp->fg_flags & CFS_FG_ALLOC_ATTR) == 0) &&
467 	    (fgp->fg_flags & CFS_FG_WRITE) &&
468 	    (fgp->fg_header->ach_rl_current != CACHEFS_RL_GC) &&
469 	    (fgp->fg_count == 1) &&
470 	    (fgp->fg_header->ach_nffs == 0)) {
471 #ifdef CFSDEBUG
472 		cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
473 		    CACHEFS_RL_ATTRFILE, fgp->fg_header->ach_rlno);
474 #endif /* CFSDEBUG */
475 		cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
476 		    CACHEFS_RL_GC, fgp->fg_header->ach_rlno,
477 		    fgp->fg_header->ach_nblks);
478 		fgp->fg_header->ach_rl_current = CACHEFS_RL_GC;
479 		fgp->fg_flags |= CFS_FG_UPDATED;
480 	}
481 
482 	fgp->fg_count--;
483 
484 	mutex_exit(&fgp->fg_mutex);
485 
486 }
487 
488 /*
489  * ------------------------------------------------------------------
490  *
491  *		filegrp_ffhold
492  *
493  * Description:
494  *	Increments the count of the number of front files for
495  *	this filegrp by one.
496  * Arguments:
497  *	fgp	filegrp object to reference
498  * Returns:
499  *	Returns 0 for success or a non-zero errno.
500  * Preconditions:
501  *	precond(fgp is a valid filegrp object)
502  *	precond(number of refrences to filegrp is > 0)
503  *	precond(filegrp is writable)
504  */
505 
506 int
507 filegrp_ffhold(filegrp_t *fgp)
508 {
509 	int error = 0;
510 
511 	cachefs_cache_dirty(fgp->fg_fscp->fs_cache, 1);
512 
513 	mutex_enter(&fgp->fg_mutex);
514 	ASSERT(fgp->fg_flags & CFS_FG_WRITE);
515 	ASSERT(fgp->fg_count > 0);
516 
517 	/* if the filegrp is no good, bail out with warning */
518 	if (fgp->fg_flags & CFS_FG_NOCACHE) {
519 		error = EINVAL;
520 		goto out;
521 	}
522 
523 	/* if we do not have the directory vp yet */
524 	if (fgp->fg_flags & CFS_FG_ALLOC_FILE) {
525 
526 		/* create the directory if necessary */
527 		if (fgp->fg_header->ach_nffs == 0) {
528 			error = filegrpdir_create(fgp);
529 			if (error)
530 				goto out;
531 		}
532 
533 		/* else find the directory */
534 		else {
535 			error = filegrpdir_find(fgp);
536 			if (error) {
537 #ifdef CFSDEBUG
538 				CFS_DEBUG(CFSDEBUG_FILEGRP)
539 					printf("ffhold: no dir, errno %d, "
540 					    "fileno %llx\n",
541 				error, (u_longlong_t)fgp->fg_id.cid_fileno);
542 #endif
543 				goto out;
544 			}
545 		}
546 	}
547 	ASSERT(fgp->fg_dirvp);
548 
549 #ifdef CFSDEBUG
550 	if (fgp->fg_header->ach_nffs == 0) {
551 		ASSERT(fgp->fg_header->ach_rl_current == CACHEFS_RL_ATTRFILE);
552 		cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
553 		    CACHEFS_RL_ATTRFILE, fgp->fg_header->ach_rlno);
554 
555 		/*
556 		 * XXX sam: this used to remove from the active list,
557 		 * and put on `NONE'.  now, we're on
558 		 * CACHEFS_RL_ATTRFILE if either count or nffs is
559 		 * nonzero; CACHEFS_RL_GC otherwise.  since we just
560 		 * asserted that we're not on CACHEFS_RL_GC, there's
561 		 * nothing more to do.  right?
562 		 */
563 	}
564 #endif /* CFSDEBUG */
565 
566 	fgp->fg_header->ach_nffs++;
567 	fgp->fg_flags |= CFS_FG_UPDATED;
568 	ASSERT(fgp->fg_header->ach_nffs <= fgp->fg_header->ach_count);
569 
570 out:
571 	mutex_exit(&fgp->fg_mutex);
572 
573 	return (error);
574 }
575 
576 /*
577  * ------------------------------------------------------------------
578  *
579  *		filegrp_ffrele
580  *
581  * Description:
582  *	Decrements the count of the number of front files for
583  *	this filegrp by one.
584  * Arguments:
585  *	fgp	filegrp object to dereference
586  * Returns:
587  * Preconditions:
588  *	precond(fgp is a valid filegrp object)
589  *	precond(filegrp is writable)
590  *	precond(number of refrences to filegrp is > 0)
591  *	precond(number of front file references is > 0)
592  */
593 
594 void
595 filegrp_ffrele(filegrp_t *fgp)
596 {
597 	char name[CFS_FRONTFILE_NAME_SIZE];
598 	char *fname;
599 	struct fscache *fscp = fgp->fg_fscp;
600 	int error = 0;
601 
602 	/* if the filegrp is corrupt, bail out with warning */
603 	if (fgp->fg_flags & CFS_FG_NOCACHE) {
604 		return;
605 	}
606 
607 	cachefs_cache_dirty(fgp->fg_fscp->fs_cache, 1);
608 
609 	mutex_enter(&fgp->fg_mutex);
610 	ASSERT(fgp->fg_flags & CFS_FG_WRITE);
611 	ASSERT((fgp->fg_flags & CFS_FG_ALLOC_FILE) == 0);
612 	ASSERT(fgp->fg_dirvp != NULL);
613 	ASSERT(fgp->fg_count > 0);
614 	ASSERT(fgp->fg_header->ach_nffs > 0);
615 	ASSERT(fgp->fg_header->ach_nffs <= fgp->fg_header->ach_count);
616 
617 	fgp->fg_header->ach_nffs--;
618 	fgp->fg_flags |= CFS_FG_UPDATED;
619 
620 	if (fgp->fg_header->ach_nffs == 0) {
621 		make_ascii_name(&fgp->fg_id, name);
622 		fname = name;
623 		error = VOP_RMDIR(fscp->fs_fscdirvp, fname,
624 		    fscp->fs_fscdirvp, kcred);
625 		if (error == 0) {
626 			cachefs_freefile(fscp->fs_cache);
627 			cachefs_freeblocks(fscp->fs_cache, 1,
628 			    fgp->fg_header->ach_rl_current);
629 			VN_RELE(fgp->fg_dirvp);
630 			fgp->fg_dirvp = NULL;
631 			fgp->fg_flags |= CFS_FG_ALLOC_FILE;
632 		} else {
633 			fgp->fg_flags |= CFS_FG_NOCACHE;
634 			cmn_err(CE_WARN, "cachefs_ffrele:"
635 			    " frontfs cache error %d, run fsck", error);
636 		}
637 
638 		/*
639 		 * XXX sam: this used to move from `NONE' to
640 		 * `CACHEFS_RL_ACTIVE'.  now, we're on
641 		 * CACHEFS_RL_ATTRFILE if count and/or nffs is
642 		 * nonzero, and CACHEFS_RL_GC otherwise.  since we
643 		 * just asserted that count > 0, there's nothing to
644 		 * do.  right?
645 		 */
646 #ifdef CFSDEBUG
647 		cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
648 		    CACHEFS_RL_ATTRFILE, fgp->fg_header->ach_rlno);
649 #endif /* CFSDEBUG */
650 	}
651 	mutex_exit(&fgp->fg_mutex);
652 }
653 
654 /*
655  * ------------------------------------------------------------------
656  *
657  *		filegrp_sync
658  *
659  * Description:
660  *	Writes the file group's attrcache header to the attrcache
661  *	file if necessary and syncs it.
662  * Arguments:
663  *	fgp	filegrp object
664  * Returns:
665  *	Returns 0 on success, an errno value on failure.
666  * Preconditions:
667  *	precond(fgp is a valid filegrp object)
668  */
669 
670 int
671 filegrp_sync(filegrp_t *fgp)
672 {
673 	int error = 0;
674 
675 	mutex_enter(&fgp->fg_mutex);
676 
677 	if (((fgp->fg_flags & CFS_FG_UPDATED) == 0) ||
678 	    (fgp->fg_flags & CFS_FG_ALLOC_ATTR) ||
679 		CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp)) {
680 		mutex_exit(&fgp->fg_mutex);
681 		return (0);
682 	}
683 
684 	ASSERT(fgp->fg_header->ach_nffs <= fgp->fg_header->ach_count);
685 
686 	error = vn_rdwr(UIO_WRITE, fgp->fg_attrvp, (caddr_t)fgp->fg_header,
687 	    fgp->fg_headersize, 0LL, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY,
688 	    kcred, NULL);
689 
690 	if (error == 0)
691 		error = VOP_FSYNC(fgp->fg_attrvp, FSYNC, kcred);
692 
693 	if (error == 0)
694 		fgp->fg_flags &= ~CFS_FG_UPDATED;
695 
696 	mutex_exit(&fgp->fg_mutex);
697 
698 	return (error);
699 }
700 
701 /*
702  * ------------------------------------------------------------------
703  *
704  *		filegrp_read_metadata
705  *
706  * Description:
707  *	Reads the metadata for the specified file from the attrcache
708  *	file belonging to the filegrp object.  Note that the md_rltype
709  *	field may be incorrect if (cachep->c_flags & CACHE_CHECK_RLTYPE);
710  *	in this case, if you care about md_rltype, you should double-check
711  *	if rl_type is CACHEFS_RL_ACTIVE; cachefs_move_active_to_rl may have
712  *	moved it without telling us.
713  * Arguments:
714  *	fgp	filegrp object
715  *	cidp	the file to search for
716  *	mdp	set to the metadata for the fileno
717  * Returns:
718  *	Returns 0 on success, an errno value on failure.
719  * Preconditions:
720  *	precond(fgp is a valid filegrp object)
721  *	precond(mdp)
722  *	precond(slotp)
723  */
724 
725 int
726 filegrp_read_metadata(filegrp_t *fgp, cfs_cid_t *cidp,
727     struct cachefs_metadata *mdp)
728 {
729 	int slot;
730 	int error;
731 	int index;
732 	struct cfs_cachefs_metadata	*tmpmdp;
733 
734 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
735 
736 	mutex_enter(&fgp->fg_mutex);
737 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
738 		mutex_exit(&fgp->fg_mutex);
739 		return (ENOENT);
740 	}
741 
742 	slot = filegrp_cid_to_slot(fgp, cidp);
743 	if (slot == 0) {
744 		mutex_exit(&fgp->fg_mutex);
745 		return (ENOENT);
746 	}
747 
748 
749 	/* see if metadata was ever written */
750 	index = (int) (cidp->cid_fileno - fgp->fg_id.cid_fileno);
751 	if (fgp->fg_offsets[index].ach_written == 0) {
752 		mutex_exit(&fgp->fg_mutex);
753 		return (ENOENT);
754 	}
755 
756 	CACHEFS_ALLOC_CFS_METADATA(tmpmdp, mdp);
757 
758 	error = vn_rdwr(UIO_READ, fgp->fg_attrvp,
759 	    (caddr_t)tmpmdp, sizeof (struct cfs_cachefs_metadata),
760 	    (offset_t)slot,
761 	    UIO_SYSSPACE, 0, (long long)0, (cred_t *)NULL, NULL);
762 	if (error) {
763 		cmn_err(CE_WARN,
764 		    "cachefs_read_metadata:"
765 		    " frontfs cache error %d, run fsck", error);
766 	}
767 	CACHEFS_COPY_CFS_METADATA_TO_METADATA(tmpmdp, mdp);
768 	CACHEFS_FREE_CFS_METADATA(tmpmdp);
769 
770 	mutex_exit(&fgp->fg_mutex);
771 	return (error);
772 }
773 
774 /*
775  * ------------------------------------------------------------------
776  *
777  *		filegrp_create_metadata
778  *
779  * Description:
780  *	Allocates a slot for the specified fileno.
781  * Arguments:
782  *	fgp	filegrp object
783  *	cidp	the file to allocate a slot for
784  * Returns:
785  *	Returns 0 on success, an errno value on failure.
786  * Preconditions:
787  *	precond(fgp is a valid filegrp object)
788  */
789 
790 int
791 filegrp_create_metadata(filegrp_t *fgp, struct cachefs_metadata *md,
792     cfs_cid_t *cidp)
793 {
794 	struct fscache *fscp = fgp->fg_fscp;
795 	cachefscache_t *cachep = fscp->fs_cache;
796 	int slot;
797 	int bitno;
798 	u_char mask;
799 	int last;
800 	int xx;
801 	int index;
802 
803 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
804 
805 	cachefs_cache_dirty(cachep, 1);
806 
807 	mutex_enter(&fgp->fg_mutex);
808 
809 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
810 		mutex_exit(&fgp->fg_mutex);
811 		return (ENOENT);
812 	}
813 
814 	slot = filegrp_cid_to_slot(fgp, cidp);
815 	if (slot) {
816 		mutex_exit(&fgp->fg_mutex);
817 		return (0);
818 	}
819 
820 	index = (int) (cidp->cid_fileno - fgp->fg_id.cid_fileno);
821 
822 	ASSERT(index < fgp->fg_fscp->fs_info.fi_fgsize);
823 
824 	last = (((fgp->fg_fscp->fs_info.fi_fgsize + 7) & ~(7)) / 8);
825 	for (xx = 0; xx < last; xx++) {
826 		if (fgp->fg_alloclist[xx] != (u_char)0xff) {
827 			for (mask = 1, bitno = 0; bitno < 8; bitno++) {
828 				if ((mask & fgp->fg_alloclist[xx]) == 0) {
829 					slot = (xx * 8) + bitno;
830 					goto found;
831 				}
832 				mask <<= 1;
833 			}
834 		}
835 	}
836 found:
837 	if (xx == last) {
838 		cmn_err(CE_WARN, "cachefs: attrcache error, run fsck");
839 		mutex_exit(&fgp->fg_mutex);
840 		return (ENOMEM);
841 	}
842 
843 	slot = (slot * (int)sizeof (struct cfs_cachefs_metadata)) +
844 		fgp->fg_headersize;
845 
846 	ASSERT(fgp->fg_header->ach_nffs <= fgp->fg_header->ach_count);
847 	fgp->fg_header->ach_count++;
848 	fgp->fg_offsets[index].ach_offset = slot;
849 	fgp->fg_offsets[index].ach_written = 0;
850 	fgp->fg_alloclist[xx] |= mask;
851 	fgp->fg_flags |= CFS_FG_UPDATED;
852 
853 	mutex_exit(&fgp->fg_mutex);
854 
855 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_MDCREATE))
856 		cachefs_log_mdcreate(cachep, 0,
857 		    fscp->fs_cfsvfsp, &md->md_cookie, cidp->cid_fileno,
858 		    fgp->fg_header->ach_count);
859 
860 	return (0);
861 }
862 
863 /*
864  * ------------------------------------------------------------------
865  *
866  *		filegrp_write_metadata
867  *
868  * Description:
869  *	Writes metadata to the slot held by file.
870  * Arguments:
871  *	fgp	filegrp object
872  *	cidp	the file to write the metadata for
873  *	mdp	the metadata to write
874  * Returns:
875  *	Returns 0 on success, an errno value on failure.
876  * Preconditions:
877  *	precond(fgp is a valid filegrp object)
878  *	precond(mdp)
879  */
880 int
881 filegrp_write_metadata(filegrp_t *fgp, cfs_cid_t *cidp,
882     struct cachefs_metadata *mdp)
883 {
884 	int error = 0;
885 	int slot;
886 	blkcnt64_t nblks;
887 	int index;
888 	struct fscache *fscp = fgp->fg_fscp;
889 	struct cfs_cachefs_metadata	*tmpmdp;
890 
891 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
892 
893 	cachefs_cache_dirty(fscp->fs_cache, 1);
894 	mutex_enter(&fgp->fg_mutex);
895 
896 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
897 		error = ENOENT;
898 		goto out;
899 	}
900 
901 	slot = filegrp_cid_to_slot(fgp, cidp);
902 	if (slot == 0) {
903 		error = ENOENT;
904 		goto out;
905 	}
906 
907 	/* allocate blocks for the data if necessary */
908 	nblks = slot + sizeof (struct cfs_cachefs_metadata);
909 	nblks = (nblks + MAXBSIZE - 1) / MAXBSIZE;
910 	nblks -= fgp->fg_header->ach_nblks;
911 	if (nblks > 0) {
912 		error = cachefs_allocblocks(fscp->fs_cache, nblks,
913 		    fgp->fg_header->ach_rl_current);
914 		if (error)
915 			goto out;
916 		error = filegrp_write_space(fgp->fg_attrvp,
917 			(offset_t)fgp->fg_header->ach_nblks * MAXBSIZE,
918 			nblks * MAXBSIZE);
919 		if (error) {
920 			cachefs_freeblocks(fscp->fs_cache, nblks,
921 			    fgp->fg_header->ach_rl_current);
922 			goto out;
923 		}
924 	} else
925 		nblks = 0;
926 
927 	CACHEFS_ALLOC_CFS_METADATA(tmpmdp, mdp);
928 	CACHEFS_COPY_METADATA_TO_CFS_METADATA(mdp, tmpmdp, error);
929 	/* write the metadata */
930 	if (!error)
931 		error = vn_rdwr(UIO_WRITE, fgp->fg_attrvp, (caddr_t)tmpmdp,
932 			sizeof (struct cfs_cachefs_metadata), (offset_t)slot,
933 			UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY, kcred, NULL);
934 
935 	CACHEFS_FREE_CFS_METADATA(tmpmdp);
936 
937 	if (error) {
938 		if (error == EOVERFLOW) {
939 			cmn_err(CE_WARN, "cachefs_write_metadata:"
940 			    " time/dev overflow error %d", error);
941 		} else if (error != ENOSPC) {
942 			cmn_err(CE_WARN,
943 			    "cachefs: UFS write error %d, run fsck",
944 			    error);
945 		}
946 		cachefs_freeblocks(fscp->fs_cache, nblks,
947 		    fgp->fg_header->ach_rl_current);
948 		goto out;
949 	}
950 
951 	/* mark metadata as having been written */
952 	index = (int) (cidp->cid_fileno - fgp->fg_id.cid_fileno);
953 	fgp->fg_offsets[index].ach_written = 1;
954 
955 	/* update number of blocks used by the attrcache file */
956 	fgp->fg_header->ach_nblks += nblks;
957 
958 	/* force sync to be done eventually */
959 	fgp->fg_flags |= CFS_FG_UPDATED;
960 
961 out:
962 	mutex_exit(&fgp->fg_mutex);
963 	return (error);
964 }
965 
966 /*
967  * ------------------------------------------------------------------
968  *
969  *		filegrp_destroy_metadata
970  *
971  * Description:
972  *	Destroys the metadata associated with the specified file.
973  * Arguments:
974  *	fgp	filegrp object
975  *	cidp	the file to destroy the metadata for
976  * Returns:
977  *	Returns 0 on success, an errno value on failure.
978  * Preconditions:
979  *	precond(fgp is a valid filegrp object)
980  */
981 
982 int
983 filegrp_destroy_metadata(filegrp_t *fgp, cfs_cid_t *cidp)
984 {
985 	int i;
986 	int bitno;
987 	u_char mask = 1;
988 
989 	int slot;
990 
991 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
992 
993 	cachefs_cache_dirty(fgp->fg_fscp->fs_cache, 1);
994 	mutex_enter(&fgp->fg_mutex);
995 
996 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
997 		mutex_exit(&fgp->fg_mutex);
998 		return (ENOENT);
999 	}
1000 
1001 	slot = filegrp_cid_to_slot(fgp, cidp);
1002 	if (slot == 0) {
1003 		mutex_exit(&fgp->fg_mutex);
1004 		return (ENOENT);
1005 	}
1006 
1007 	i = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
1008 	fgp->fg_offsets[i].ach_offset = 0;
1009 	fgp->fg_offsets[i].ach_written = 0;
1010 	i = (slot - fgp->fg_headersize) /
1011 		(int)sizeof (struct cfs_cachefs_metadata);
1012 	bitno = i & 7;
1013 	i = i >> 3;
1014 	mask <<= bitno;
1015 	if (fgp->fg_alloclist[i] & mask)
1016 		fgp->fg_alloclist[i] &= ~mask;
1017 	else
1018 		cmn_err(CE_WARN,
1019 		    "filegrp_destroy_metadata:"
1020 		    " fileno %" PRId64 " slot %d-%d fgp %p not allocated",
1021 		    cidp->cid_fileno, i, bitno, (void *)fgp);
1022 
1023 	fgp->fg_header->ach_count--;
1024 	ASSERT(fgp->fg_header->ach_nffs <= fgp->fg_header->ach_count);
1025 	fgp->fg_flags |= CFS_FG_UPDATED;
1026 	mutex_exit(&fgp->fg_mutex);
1027 
1028 	return (0);
1029 }
1030 
1031 /*
1032  * ------------------------------------------------------------------
1033  *
1034  *		filegrp_list_find
1035  *
1036  * Description:
1037  *	Looks for the filegrp that owns the specified file
1038  *	on the fscp filegrp lists.
1039  *	The fscp->fs_fslock must be held while this routine is called.
1040  *	By convention the filegrp object returned may be used as
1041  *	long as the fs_fslock is held.  To use the filegrp after
1042  *	dropping fs_fslock, call filegrp_hold.
1043  * Arguments:
1044  *	fscp	fscache object
1045  *	cidp	the file to search on
1046  * Returns:
1047  *	Returns the filegrp object if found, NULL if not.
1048  * Preconditions:
1049  *	precond(fscp is a valid fscache object)
1050  */
1051 
1052 filegrp_t *
1053 filegrp_list_find(struct fscache *fscp, cfs_cid_t *cidp)
1054 {
1055 	int fgsize = fscp->fs_info.fi_fgsize;
1056 	struct filegrp *fgp;
1057 	ino64_t fxx;
1058 	int findex;
1059 	ino64_t fileno;
1060 
1061 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
1062 
1063 	/* get fileno of filegrp */
1064 	fxx = (ino64_t)(cidp->cid_fileno / fgsize);
1065 	fileno = fxx * fgsize;
1066 
1067 	/* hash into array of file groups */
1068 	findex = (int) (fxx & (CFS_FS_FGP_BUCKET_SIZE - 1));
1069 
1070 	/* search set of file groups for this hash bucket */
1071 	for (fgp = fscp->fs_filegrp[findex];
1072 	    fgp != NULL;
1073 	    fgp = fgp->fg_next) {
1074 		if ((fgp->fg_id.cid_fileno == fileno) &&
1075 		    (fgp->fg_id.cid_flags == cidp->cid_flags))
1076 			break;
1077 	}
1078 
1079 	return (fgp);
1080 }
1081 
1082 /*
1083  * ------------------------------------------------------------------
1084  *
1085  *		filegrp_list_add
1086  *
1087  * Description:
1088  *	Adds the filegrp to the list of filegrps in the fscp.
1089  *	The fscp->fs_fslock must be held while this routine is called.
1090  * Arguments:
1091  *	fscp	fscache object
1092  *	fgp	filegrp object
1093  * Returns:
1094  * Preconditions:
1095  *	precond(fscp is a valid fscache object)
1096  *	precond(fgp is a valid filegrp object)
1097  *	precond(fgp is not already on a list of filegrps)
1098  */
1099 
1100 void
1101 filegrp_list_add(struct fscache *fscp, filegrp_t *fgp)
1102 {
1103 	int findex;
1104 	int fgsize = fscp->fs_info.fi_fgsize;
1105 
1106 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
1107 	ASSERT(fgp->fg_next == NULL);
1108 
1109 	/* hash into array of file groups */
1110 	findex = (int) ((fgp->fg_id.cid_fileno / fgsize) &
1111 	    (CFS_FS_FGP_BUCKET_SIZE - 1));
1112 
1113 	fgp->fg_next = fscp->fs_filegrp[findex];
1114 	fscp->fs_filegrp[findex] = fgp;
1115 	fscp->fs_ref++;
1116 }
1117 
1118 /*
1119  * ------------------------------------------------------------------
1120  *
1121  *		filegrp_list_remove
1122  *
1123  * Description:
1124  *	Removes the filegrp from the list of filegrps in the fscp.
1125  *	The fscp->fs_fslock must be held while this routine is called.
1126  * Arguments:
1127  *	fscp	fscache object
1128  *	fgp	filegrp object
1129  * Returns:
1130  * Preconditions:
1131  *	precond(fscp is a valid fscache object)
1132  *	precond(fgp is a valid filegrp object)
1133  *	precond(fgp is on the list of filegrps in fscp)
1134  */
1135 
1136 void
1137 filegrp_list_remove(struct fscache *fscp, filegrp_t *fgp)
1138 {
1139 	struct filegrp *fp;
1140 	struct filegrp **pfgp;
1141 	int found = 0;
1142 	int findex;
1143 	int fgsize = fscp->fs_info.fi_fgsize;
1144 
1145 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
1146 
1147 	/* hash into array of file groups */
1148 	findex = (int) ((fgp->fg_id.cid_fileno / fgsize) &
1149 	    (CFS_FS_FGP_BUCKET_SIZE - 1));
1150 	fp = fscp->fs_filegrp[findex];
1151 	pfgp = &fscp->fs_filegrp[findex];
1152 
1153 	while (fp != NULL) {
1154 		if (fp == fgp) {
1155 			*pfgp = fp->fg_next;
1156 			fp->fg_next = NULL;
1157 			found++;
1158 			break;
1159 		}
1160 		pfgp = &fp->fg_next;
1161 		fp = fp->fg_next;
1162 	}
1163 	ASSERT(found);
1164 	fscp->fs_ref--;
1165 }
1166 
1167 /*
1168  * ------------------------------------------------------------------
1169  *
1170  *		filegrp_list_gc
1171  *
1172  * Description:
1173  *	Traverses the filegrp lists and throws away any filegrps that are
1174  *	not in use.
1175  *	The fscp->fs_fslock must be held while this routine is called.
1176  * Arguments:
1177  *	fscp	fscache object
1178  * Returns:
1179  * Preconditions:
1180  *	precond(fscp is a valid fscache object)
1181  */
1182 
1183 void
1184 filegrp_list_gc(struct fscache *fscp)
1185 {
1186 	struct filegrp *next, *fgp;
1187 	int xx;
1188 
1189 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
1190 
1191 	for (xx = 0; xx < CFS_FS_FGP_BUCKET_SIZE; xx++) {
1192 		for (fgp = fscp->fs_filegrp[xx]; fgp != NULL; fgp = next) {
1193 			next = fgp->fg_next;
1194 			mutex_enter(&fgp->fg_mutex);
1195 			if (fgp->fg_count > 0) {
1196 				mutex_exit(&fgp->fg_mutex);
1197 				continue;
1198 			}
1199 			mutex_exit(&fgp->fg_mutex);
1200 			filegrp_list_remove(fscp, fgp);
1201 			filegrp_destroy(fgp);
1202 		}
1203 	}
1204 }
1205 
1206 /*
1207  * ------------------------------------------------------------------
1208  *
1209  *		filegrp_setup
1210  *
1211  * Description:
1212  *	Perform initialization actions on the given filegrp.
1213  *	The fgp->fg_mutex must be held while this routine is called.
1214  * Arguments:
1215  *	fgp	filegrp object
1216  *	flags	flags to be OR'ed into the fgp flags field
1217  *	dorl	indicates whether filegrp should be removed from rl or not
1218  * Returns:
1219  * Preconditions:
1220  *	precond(fgp is a valid filegrp object)
1221  */
1222 static void
1223 filegrp_setup(struct filegrp *fgp, int flags, int dorl)
1224 {
1225 	ASSERT(MUTEX_HELD(&fgp->fg_mutex));
1226 
1227 	/* turn on the specified flags */
1228 	if (flags)
1229 		fgp->fg_flags |= flags;
1230 
1231 	/* if the attrcache file exists, find it */
1232 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR)
1233 		(void) filegrpattr_find(fgp);
1234 
1235 	/* if the attrcache directory exists, find it */
1236 	if (((fgp->fg_flags & CFS_FG_ALLOC_ATTR) == 0) &&
1237 	    (fgp->fg_flags & CFS_FG_ALLOC_FILE) &&
1238 	    (fgp->fg_header->ach_nffs > 0)) {
1239 		(void) filegrpdir_find(fgp);
1240 	}
1241 
1242 	/* move from gc list to attrfile list if necessary */
1243 	if ((dorl != 0) &&
1244 	    ((fgp->fg_flags & CFS_FG_ALLOC_ATTR) == 0) &&
1245 	    (fgp->fg_header->ach_rl_current == CACHEFS_RL_GC)) {
1246 		ASSERT(fgp->fg_header->ach_nffs == 0);
1247 		if (fgp->fg_count > 0) {
1248 #ifdef CFSDEBUG
1249 			cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
1250 			    CACHEFS_RL_GC, fgp->fg_header->ach_rlno);
1251 #endif /* CFSDEBUG */
1252 			cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
1253 			    CACHEFS_RL_ATTRFILE, fgp->fg_header->ach_rlno,
1254 			    fgp->fg_header->ach_nblks);
1255 			fgp->fg_header->ach_rl_current = CACHEFS_RL_ATTRFILE;
1256 			fgp->fg_flags |= CFS_FG_UPDATED;
1257 		}
1258 	}
1259 }
1260 
1261 /*
1262  * ------------------------------------------------------------------
1263  *
1264  *		filegrp_list_enable_caching_ro
1265  *
1266  * Description:
1267  *	Traverses the filegrp lists and enables the
1268  *	use of the cache read-only.
1269  *	The fscp->fs_fslock must be held while this routine is called.
1270  * Arguments:
1271  *	fscp	fscache object
1272  * Returns:
1273  * Preconditions:
1274  *	precond(fscp is a valid fscache object)
1275  */
1276 
1277 void
1278 filegrp_list_enable_caching_ro(struct fscache *fscp)
1279 {
1280 	struct filegrp *fgp;
1281 	int xx;
1282 
1283 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
1284 
1285 	for (xx = 0; xx < CFS_FS_FGP_BUCKET_SIZE; xx++) {
1286 		for (fgp = fscp->fs_filegrp[xx]; fgp != NULL;
1287 		    fgp = fgp->fg_next) {
1288 			mutex_enter(&fgp->fg_mutex);
1289 			filegrp_setup(fgp, 0, 0);
1290 			mutex_exit(&fgp->fg_mutex);
1291 		}
1292 	}
1293 }
1294 
1295 /*
1296  * ------------------------------------------------------------------
1297  *
1298  *		filegrp_list_enable_caching_rw
1299  *
1300  * Description:
1301  *	Traverses the filegrp lists and enables the
1302  *	use of the cache read-write.
1303  *	The fscp->fs_fslock must be held while this routine is called.
1304  * Arguments:
1305  *	fscp	fscache object
1306  * Returns:
1307  * Preconditions:
1308  *	precond(fscp is a valid fscache object)
1309  *	precond(all filegrps must be in the read-only state)
1310  */
1311 
1312 void
1313 filegrp_list_enable_caching_rw(struct fscache *fscp)
1314 {
1315 	struct filegrp *fgp;
1316 	int xx;
1317 
1318 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
1319 
1320 	for (xx = 0; xx < CFS_FS_FGP_BUCKET_SIZE; xx++) {
1321 		for (fgp = fscp->fs_filegrp[xx]; fgp != NULL;
1322 		    fgp = fgp->fg_next) {
1323 			mutex_enter(&fgp->fg_mutex);
1324 			filegrp_setup(fgp, CFS_FG_READ|CFS_FG_WRITE, 1);
1325 			mutex_exit(&fgp->fg_mutex);
1326 		}
1327 	}
1328 }
1329 
1330 /*
1331  * ------------------------------------------------------------------
1332  *
1333  *		filegrpdir_find
1334  *
1335  * Description:
1336  *	Tries to find the filegrp frontfile directory in the cache.
1337  *	If found CFS_FG_ALLOC_FILE is turned off.
1338  *	This routine should not be called if CFS_FG_ALLOC_FILE is
1339  *	already off.
1340  * Arguments:
1341  *	fgp	filegrp object
1342  * Returns:
1343  *	Returns 0 on success, an errno value on failure.
1344  * Preconditions:
1345  *	precond(fgp is a valid filegrp object)
1346  */
1347 
1348 int
1349 filegrpdir_find(filegrp_t *fgp)
1350 {
1351 	int error;
1352 	vnode_t *dirvp;
1353 	char name[CFS_FRONTFILE_NAME_SIZE];
1354 	char *fname;
1355 	struct fscache *fscp = fgp->fg_fscp;
1356 
1357 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR)
1358 		return (ENOENT);
1359 	ASSERT(fgp->fg_flags & CFS_FG_ALLOC_FILE);
1360 
1361 	make_ascii_name(&fgp->fg_id, name);
1362 	fname = name;
1363 	error = VOP_LOOKUP(fscp->fs_fscdirvp, fname, &dirvp, NULL,
1364 			0, NULL, kcred);
1365 	if (error == 0) {
1366 		fgp->fg_dirvp = dirvp;
1367 		fgp->fg_flags &= ~CFS_FG_ALLOC_FILE;
1368 #ifdef CFSDEBUG
1369 		if (fgp->fg_header->ach_nffs == 0) {
1370 			CFS_DEBUG(CFSDEBUG_FILEGRP)
1371 				printf("filegrpdir_find: "
1372 				    "%s found but no front files\n", fname);
1373 		}
1374 #endif
1375 	}
1376 #ifdef CFSDEBUG
1377 	else if (fgp->fg_header->ach_nffs != 0) {
1378 		CFS_DEBUG(CFSDEBUG_FILEGRP)
1379 			printf("filegrpdir_find: "
1380 				"%s NOT found but %d front files\n",
1381 				fname, fgp->fg_header->ach_nffs);
1382 	}
1383 #endif
1384 	return (error);
1385 }
1386 
1387 /*
1388  * ------------------------------------------------------------------
1389  *
1390  *		filegrparttr_find
1391  *
1392  * Description:
1393  *	Tries to find the attrcache file for the given filegrp.
1394  *	If found the header information is read in and
1395  *	CFS_FG_ALLOC_ATTR is turned off.
1396  *	This routine should not be called if CFS_FG_ALLOC_ATTR is
1397  *	already off.
1398  * Arguments:
1399  *	fgp	filegrp object
1400  * Returns:
1401  *	Returns 0 on success, an errno value on failure.
1402  * Preconditions:
1403  *	precond(fgp is a valid filegrp object)
1404  *	precond(fgp is readable)
1405  */
1406 
1407 int
1408 filegrpattr_find(struct filegrp *fgp)
1409 {
1410 	int error = 0;
1411 	struct fscache *fscp = fgp->fg_fscp;
1412 	cachefscache_t *cachep = fscp->fs_cache;
1413 	vnode_t *attrvp;
1414 	struct attrcache_header *ahp;
1415 	char name[CFS_FRONTFILE_NAME_SIZE];
1416 	char *fname;
1417 
1418 	if (fgp->fg_flags & CFS_FG_NOCACHE)
1419 		return (ENOENT);
1420 
1421 	ASSERT(fgp->fg_flags & CFS_FG_ALLOC_ATTR);
1422 	make_ascii_name(&fgp->fg_id, name);
1423 	fname = name;
1424 	error = VOP_LOOKUP(fscp->fs_fsattrdir, fname,
1425 	    &attrvp, NULL, 0, NULL, kcred);
1426 	if (error) {
1427 		return (error);
1428 	}
1429 	ahp = (struct attrcache_header *)cachefs_kmem_zalloc(
1430 	    fgp->fg_headersize, KM_SLEEP);
1431 
1432 	error = vn_rdwr(UIO_READ, attrvp, (caddr_t)ahp,
1433 				fgp->fg_headersize, 0LL, UIO_SYSSPACE,
1434 			0, (rlim64_t)RLIM_INFINITY, (cred_t *)NULL, NULL);
1435 	if (error) {
1436 		cmn_err(CE_WARN, "cachefs: Read attrcache error %d, run fsck",
1437 		    error);
1438 		cachefs_kmem_free(ahp, fgp->fg_headersize);
1439 		fgp->fg_flags |= CFS_FG_NOCACHE;
1440 		VN_RELE(attrvp);
1441 	} else {
1442 		ASSERT(ahp->ach_nffs <= ahp->ach_count);
1443 		fgp->fg_attrvp = attrvp;
1444 		fgp->fg_header = ahp;
1445 		fgp->fg_offsets = (struct attrcache_index *)(ahp + 1);
1446 		fgp->fg_alloclist = ((u_char *)fgp->fg_offsets) +
1447 			(fscp->fs_info.fi_fgsize *
1448 			sizeof (struct attrcache_index));
1449 		fgp->fg_flags &= ~CFS_FG_ALLOC_ATTR;
1450 
1451 		if ((cachep->c_flags & CACHE_CHECK_RLTYPE) &&
1452 		    (ahp->ach_rl_current == CACHEFS_RL_ATTRFILE)) {
1453 			rl_entry_t *rlp, rl;
1454 
1455 			mutex_enter(&cachep->c_contentslock);
1456 			error = cachefs_rl_entry_get(cachep, ahp->ach_rlno,
1457 									&rlp);
1458 			if (error) {
1459 				mutex_exit(&cachep->c_contentslock);
1460 				cachefs_kmem_free(ahp, fgp->fg_headersize);
1461 				fgp->fg_flags |= CFS_FG_NOCACHE;
1462 				VN_RELE(attrvp);
1463 				return (error);
1464 			}
1465 
1466 			rl = *rlp;
1467 			mutex_exit(&cachep->c_contentslock);
1468 
1469 			if (rl.rl_current != ahp->ach_rl_current) {
1470 				ahp->ach_rl_current = rl.rl_current;
1471 				fgp->fg_flags |= CFS_FG_UPDATED;
1472 			}
1473 		}
1474 
1475 		/* if the attr file is on the rl */
1476 		if (fgp->fg_header->ach_rl_current == CACHEFS_RL_GC) {
1477 #ifdef CFSDEBUG
1478 			if (fgp->fg_flags & CFS_FG_WRITE)
1479 				cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
1480 				    CACHEFS_RL_GC,
1481 				    fgp->fg_header->ach_rlno);
1482 #endif /* CFSDEBUG */
1483 			if ((fgp->fg_count > 0) &&
1484 			    (fgp->fg_flags & CFS_FG_WRITE)) {
1485 				/* remove from rl, put on active */
1486 				cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
1487 				    CACHEFS_RL_ATTRFILE,
1488 				    fgp->fg_header->ach_rlno,
1489 				    fgp->fg_header->ach_nblks);
1490 				fgp->fg_header->ach_rl_current =
1491 				    CACHEFS_RL_ATTRFILE;
1492 				fgp->fg_flags |= CFS_FG_UPDATED;
1493 			}
1494 		} else {
1495 			ASSERT(fgp->fg_header->ach_rl_current ==
1496 			    CACHEFS_RL_ATTRFILE);
1497 #ifdef CFSDEBUG
1498 			if (fgp->fg_flags & CFS_FG_WRITE)
1499 				cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
1500 				    CACHEFS_RL_ATTRFILE,
1501 				    fgp->fg_header->ach_rlno);
1502 #endif /* CFSDEBUG */
1503 		}
1504 	}
1505 
1506 	return (error);
1507 }
1508 
1509 /*
1510  * ------------------------------------------------------------------
1511  *
1512  *		filegrpdir_create
1513  *
1514  * Description:
1515  *	Creates the filegrp directory in the cache.
1516  *	If created CFS_FG_ALLOC_FILE is turned off.
1517  *	This routine should not be called if CFS_FG_ALLOC_FILE is
1518  *	already off.
1519  * Arguments:
1520  *	fgp	filegrp object
1521  * Returns:
1522  *	Returns 0 on success, an errno value on failure.
1523  * Preconditions:
1524  *	precond(fgp is a valid filegrp object)
1525  *	precond(filegrp is writeable)
1526  */
1527 
1528 int
1529 filegrpdir_create(filegrp_t *fgp)
1530 {
1531 	int error;
1532 	vnode_t *dirvp = NULL;
1533 	struct vattr *attrp = NULL;
1534 	char name[CFS_FRONTFILE_NAME_SIZE];
1535 	char *fname;
1536 	struct fscache *fscp = fgp->fg_fscp;
1537 
1538 	ASSERT(fgp->fg_flags & CFS_FG_WRITE);
1539 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1540 	ASSERT(MUTEX_HELD(&fgp->fg_mutex));
1541 
1542 	if (fgp->fg_flags & (CFS_FG_ALLOC_ATTR | CFS_FG_NOCACHE))
1543 		return (ENOENT);
1544 
1545 	/* allocate a 1 block file for the directory */
1546 	error = cachefs_allocfile(fscp->fs_cache);
1547 	if (error) {
1548 		return (error);
1549 	}
1550 	error = cachefs_allocblocks(fscp->fs_cache, 1,
1551 	    fgp->fg_header->ach_rl_current);
1552 	if (error) {
1553 		cachefs_freefile(fscp->fs_cache);
1554 		return (error);
1555 	}
1556 
1557 	/*
1558 	 * Construct a name for this file group directory and then do a mkdir
1559 	 */
1560 	make_ascii_name(&fgp->fg_id, name);
1561 	fname = name;
1562 	attrp = (struct vattr *)cachefs_kmem_alloc(sizeof (struct vattr),
1563 			KM_SLEEP);
1564 	attrp->va_mode = S_IFDIR | 0777;
1565 	attrp->va_uid = 0;
1566 	attrp->va_gid = 0;
1567 	attrp->va_type = VDIR;
1568 	attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
1569 	error = VOP_MKDIR(fscp->fs_fscdirvp, fname, attrp, &dirvp, kcred);
1570 	if (error) {
1571 		fgp->fg_flags |= CFS_FG_NOCACHE;
1572 		cachefs_freefile(fscp->fs_cache);
1573 		cachefs_freeblocks(fscp->fs_cache, 1,
1574 		    fgp->fg_header->ach_rl_current);
1575 	} else {
1576 		fgp->fg_dirvp = dirvp;
1577 		fgp->fg_flags &= ~CFS_FG_ALLOC_FILE;
1578 	}
1579 
1580 	if (attrp)
1581 		cachefs_kmem_free(attrp, sizeof (*attrp));
1582 
1583 	return (error);
1584 }
1585 
1586 /*
1587  * ------------------------------------------------------------------
1588  *
1589  *		filegrpattr_create
1590  *
1591  * Description:
1592  *	Creates the attrcache file for the given filegrp.
1593  *	If created CFS_FG_ALLOC_ATTR is turned off.
1594  *	This routine should not be called if CFS_FG_ALLOC_ATTR is
1595  *	already off.
1596  * Arguments:
1597  *	fgp	filegrp object
1598  * Returns:
1599  *	Returns 0 on success, an errno value on failure.
1600  * Preconditions:
1601  *	precond(fgp is a valid filegrp object)
1602  *	precond(filegrp is writable)
1603  */
1604 
1605 int
1606 filegrpattr_create(struct filegrp *fgp)
1607 {
1608 	int error;
1609 	vnode_t *attrvp = NULL;
1610 	struct attrcache_header *ahp = NULL;
1611 	int nblks = 0;
1612 	int gotrlent = 0;
1613 	struct vattr *attrp = NULL;
1614 	char name[CFS_FRONTFILE_NAME_SIZE];
1615 	char *fname;
1616 	struct fscache *fscp = fgp->fg_fscp;
1617 	rl_entry_t rl_ent;
1618 
1619 	ASSERT(fgp->fg_flags & CFS_FG_WRITE);
1620 
1621 	if (fgp->fg_flags & CFS_FG_NOCACHE)
1622 		return (ENOENT);
1623 
1624 	cachefs_cache_dirty(fscp->fs_cache, 1);
1625 
1626 	/* allocate a file for the attrcache */
1627 	error = cachefs_allocfile(fscp->fs_cache);
1628 	if (error) {
1629 		goto out;
1630 	}
1631 
1632 	make_ascii_name(&fgp->fg_id, name);
1633 	fname = name;
1634 	attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP);
1635 	attrp->va_mode = S_IFREG | 0666;
1636 	attrp->va_uid = 0;
1637 	attrp->va_gid = 0;
1638 	attrp->va_type = VREG;
1639 	attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
1640 	error = VOP_CREATE(fscp->fs_fsattrdir, fname, attrp, EXCL, 0666,
1641 			&attrvp, kcred, 0);
1642 	if (error) {
1643 		cachefs_freefile(fscp->fs_cache);
1644 		goto out;
1645 	}
1646 
1647 	/* alloc blocks for the attrcache header */
1648 	nblks = (fgp->fg_headersize + MAXBSIZE - 1) / MAXBSIZE;
1649 	error = cachefs_allocblocks(fscp->fs_cache, nblks, CACHEFS_RL_NONE);
1650 	if (error) {
1651 		nblks = 0;
1652 		goto out;
1653 	}
1654 
1655 	/* Construct an attrcache header */
1656 	ahp = cachefs_kmem_zalloc(fgp->fg_headersize, KM_SLEEP);
1657 
1658 	/* write out the header to allocate space on ufs */
1659 	error = vn_rdwr(UIO_WRITE, attrvp, (caddr_t)ahp,
1660 	fgp->fg_headersize, 0LL, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY,
1661 		kcred, NULL);
1662 	if (error)
1663 		goto out;
1664 	error = filegrp_write_space(attrvp, (offset_t)fgp->fg_headersize,
1665 		(nblks * MAXBSIZE) - fgp->fg_headersize);
1666 	if (error)
1667 		goto out;
1668 	error = VOP_FSYNC(attrvp, FSYNC, kcred);
1669 	if (error)
1670 		goto out;
1671 
1672 	/* allocate an rl entry and mark it as an attrcache entry */
1673 	rl_ent.rl_fileno = fgp->fg_id.cid_fileno;
1674 	rl_ent.rl_local = (fgp->fg_id.cid_flags & CFS_CID_LOCAL) ? 1 : 0;
1675 	rl_ent.rl_fsid = fscp->fs_cfsid;
1676 	rl_ent.rl_attrc = 1;
1677 	error = cachefs_rl_alloc(fscp->fs_cache, &rl_ent, &ahp->ach_rlno);
1678 	if (error)
1679 		goto out;
1680 	gotrlent = 1;
1681 	if (fgp->fg_count == 0) {
1682 		/* put on the gc */
1683 		cachefs_rlent_moveto(fgp->fg_fscp->fs_cache, CACHEFS_RL_GC,
1684 		    ahp->ach_rlno, nblks);
1685 		ahp->ach_rl_current = CACHEFS_RL_GC;
1686 	} else {
1687 		/* put on attrfile list */
1688 		cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
1689 		    CACHEFS_RL_ATTRFILE, ahp->ach_rlno, nblks);
1690 		ahp->ach_rl_current = CACHEFS_RL_ATTRFILE;
1691 	}
1692 
1693 out:
1694 	if (error) {
1695 		fgp->fg_flags |= CFS_FG_NOCACHE;
1696 		if (attrvp) {
1697 			VN_RELE(attrvp);
1698 			(void) VOP_REMOVE(fscp->fs_fsattrdir, fname, kcred);
1699 			cachefs_freefile(fscp->fs_cache);
1700 		}
1701 		if (nblks)
1702 			cachefs_freeblocks(fscp->fs_cache, nblks,
1703 			    CACHEFS_RL_NONE);
1704 		if (gotrlent)
1705 			cachefs_rlent_moveto(fscp->fs_cache,
1706 			    CACHEFS_RL_FREE, ahp->ach_rlno, 0);
1707 		if (ahp)
1708 			cachefs_kmem_free(ahp, fgp->fg_headersize);
1709 	} else {
1710 		fgp->fg_attrvp = attrvp;
1711 		fgp->fg_header = ahp;
1712 		fgp->fg_offsets = (struct attrcache_index *)(ahp + 1);
1713 		fgp->fg_alloclist = ((u_char *)fgp->fg_offsets) +
1714 			(fscp->fs_info.fi_fgsize *
1715 			sizeof (struct attrcache_index));
1716 		ahp->ach_count = 0;
1717 		ahp->ach_nffs = 0;
1718 		ahp->ach_nblks = nblks;
1719 		fgp->fg_flags &= ~CFS_FG_ALLOC_ATTR;
1720 		fgp->fg_flags |= CFS_FG_UPDATED;
1721 	}
1722 
1723 	if (attrp)
1724 		cachefs_kmem_free(attrp, sizeof (*attrp));
1725 
1726 	return (error);
1727 }
1728 
1729 /*
1730  * ------------------------------------------------------------------
1731  *
1732  *		filegrp_cid_to_slot
1733  *
1734  * Description:
1735  *	Takes a file and returns the offset to the metadata
1736  *	slot for the specified filegrp.
1737  * Arguments:
1738  *	fgp	filegrp object
1739  *	cidp	file to map to an offset
1740  * Returns:
1741  *	Returns the offset or 0 if the slot is not allocated yet
1742  *	or it is invalid.
1743  * Preconditions:
1744  *	precond(fgp is a valid filegrp object)
1745  *	precond(fgp is not ALLOC_PENDING or NOCACHE)
1746  */
1747 
1748 int
1749 filegrp_cid_to_slot(filegrp_t *fgp, cfs_cid_t *cidp)
1750 {
1751 	int xx;
1752 	int slot;
1753 	int index;
1754 
1755 	index = (int) (cidp->cid_fileno - fgp->fg_id.cid_fileno);
1756 
1757 	if (index > fgp->fg_fscp->fs_info.fi_fgsize) {
1758 		cmn_err(CE_WARN, "cachefs: attrcache error, run fsck");
1759 		return (0);
1760 	}
1761 
1762 	slot = fgp->fg_offsets[index].ach_offset;
1763 	if (slot == 0)
1764 		return (0);
1765 
1766 	xx = fgp->fg_filesize - (int)sizeof (struct cfs_cachefs_metadata);
1767 	if ((slot < fgp->fg_headersize) || (xx < slot)) {
1768 		cmn_err(CE_WARN, "cachefs: attrcache error, run fsck");
1769 		return (0);
1770 	}
1771 
1772 	return (slot);
1773 }
1774 
1775 /*
1776  *
1777  *		filegrp_write_space
1778  *
1779  * Description:
1780  *	Writes garbage data to the specified file starting
1781  *	at the specified location for the specified number of bytes.
1782  *	slot for the specified filegrp.
1783  * Arguments:
1784  *	vp	vnode to write to
1785  *	offset	offset to write at
1786  *	cnt	number of bytes to write
1787  * Returns:
1788  *	Returns 0 for success or on error the result of the
1789  *	last vn_rdwr call.
1790  * Preconditions:
1791  *	precond(vp)
1792  */
1793 
1794 int
1795 filegrp_write_space(vnode_t *vp, offset_t offset, ssize_t cnt)
1796 {
1797 	char *bufp;
1798 	int xx;
1799 	int error = 0;
1800 
1801 	bufp = (char *)cachefs_kmem_zalloc(MAXBSIZE, KM_SLEEP);
1802 	while (cnt > 0) {
1803 		if (cnt > MAXBSIZE)
1804 			xx = MAXBSIZE;
1805 		else
1806 			xx = (int)cnt;
1807 		error = vn_rdwr(UIO_WRITE, vp, (caddr_t)bufp,
1808 		xx, offset, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY,
1809 			kcred, NULL);
1810 		if (error)
1811 			break;
1812 		offset += xx;
1813 		cnt -= xx;
1814 	}
1815 	cachefs_kmem_free(bufp, MAXBSIZE);
1816 	return (error);
1817 }
1818