xref: /titanic_41/usr/src/uts/common/fs/cachefs/cachefs_filegrp.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
26 
27 #include <sys/param.h>
28 #include <sys/types.h>
29 #include <sys/systm.h>
30 #include <sys/cred.h>
31 #include <sys/proc.h>
32 #include <sys/user.h>
33 #include <sys/vfs.h>
34 #include <sys/vnode.h>
35 #include <sys/pathname.h>
36 #include <sys/uio.h>
37 #include <sys/tiuser.h>
38 #include <sys/sysmacros.h>
39 #include <sys/kmem.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/bootconf.h>
48 #include <sys/modctl.h>
49 #include <sys/file.h>
50 #include <sys/stat.h>
51 
52 #include <vm/hat.h>
53 #include <vm/as.h>
54 #include <vm/page.h>
55 #include <vm/pvn.h>
56 #include <vm/seg.h>
57 #include <vm/seg_map.h>
58 #include <vm/seg_vn.h>
59 #include <vm/rm.h>
60 #include <sys/fs/cachefs_fs.h>
61 #include <sys/fs/cachefs_log.h>
62 
63 struct kmem_cache *cachefs_filegrp_cache = NULL;
64 
65 #if (defined(_SYSCALL32_IMPL) || defined(_LP64))
66 
67 #define	CACHEFS_ALLOC_CFS_METADATA(p, inp)				\
68 	p = cachefs_kmem_zalloc(sizeof (struct cfs_cachefs_metadata), KM_SLEEP)
69 
70 #define	CACHEFS_FREE_CFS_METADATA(p)					\
71 	cachefs_kmem_free(p, sizeof (struct cfs_cachefs_metadata))
72 
73 /* CACHEFS_COPY_COMMON_METADATA_FIELDS - common code for the metadata copy */
74 #define	CACHEFS_COPY_COMMON_METADATA_FIELDS(inmdp, outmdp)		\
75 	(outmdp)->md_aclclass = (inmdp)->md_aclclass;			\
76 	CACHEFS_FID_COPY(&(inmdp)->md_cookie, &(outmdp)->md_cookie);	\
77 	(outmdp)->md_flags = (inmdp)->md_flags;				\
78 	(outmdp)->md_rlno = (inmdp)->md_rlno;				\
79 	(outmdp)->md_rltype = (inmdp)->md_rltype;			\
80 	(outmdp)->md_consttype = (inmdp)->md_consttype;			\
81 	CACHEFS_FID_COPY(&(inmdp)->md_fid, &(outmdp)->md_fid);		\
82 	(outmdp)->md_frontblks = (inmdp)->md_frontblks;			\
83 	(outmdp)->md_gen = (inmdp)->md_gen;				\
84 	(outmdp)->md_parent = (inmdp)->md_parent;			\
85 	(outmdp)->md_resettimes = (inmdp)->md_resettimes;		\
86 	(outmdp)->md_localfileno = (inmdp)->md_localfileno;		\
87 	(outmdp)->md_resetfileno = (inmdp)->md_resetfileno;		\
88 	(outmdp)->md_seq = (inmdp)->md_seq;				\
89 	(outmdp)->md_allocents = (inmdp)->md_allocents;			\
90 	bcopy(&(inmdp)->md_allocinfo, &(outmdp)->md_allocinfo,		\
91 	    MIN(sizeof (inmdp)->md_allocinfo, sizeof (outmdp)->md_allocinfo))
92 
93 #define	CACHEFS_COPY_METADATA_TO_CFS_METADATA(inmdp, outmdp, error)	\
94 	CACHEFS_VATTR_TO_CFS_VATTR_COPY(&(inmdp)->md_vattr,		\
95 		&(outmdp)->md_vattr, error);				\
96 	CACHEFS_TS_TO_CFS_TS_COPY(&(inmdp)->md_timestamp,		\
97 		&(outmdp)->md_timestamp, error);			\
98 	CACHEFS_TS_TO_CFS_TS_COPY(&(inmdp)->md_x_time,			\
99 		&(outmdp)->md_x_time, error);				\
100 	CACHEFS_TS_TO_CFS_TS_COPY(&(inmdp)->md_localmtime,		\
101 		&(outmdp)->md_localmtime, error);			\
102 	CACHEFS_TS_TO_CFS_TS_COPY(&(inmdp)->md_localctime,		\
103 		&(outmdp)->md_localctime, error);			\
104 	CACHEFS_COPY_COMMON_METADATA_FIELDS(inmdp, outmdp)
105 
106 #define	CACHEFS_COPY_CFS_METADATA_TO_METADATA(inmdp, outmdp)		\
107 	CACHEFS_CFS_VATTR_TO_VATTR_COPY(&(inmdp)->md_vattr,		\
108 		&(outmdp)->md_vattr);					\
109 	CACHEFS_CFS_TS_TO_TS_COPY(&(inmdp)->md_timestamp,		\
110 		&(outmdp)->md_timestamp);				\
111 	CACHEFS_CFS_TS_TO_TS_COPY(&(inmdp)->md_x_time,			\
112 		&(outmdp)->md_x_time);					\
113 	CACHEFS_CFS_TS_TO_TS_COPY(&(inmdp)->md_localmtime,		\
114 		&(outmdp)->md_localmtime);				\
115 	CACHEFS_CFS_TS_TO_TS_COPY(&(inmdp)->md_localctime,		\
116 		&(outmdp)->md_localctime);				\
117 	CACHEFS_COPY_COMMON_METADATA_FIELDS(inmdp, outmdp)
118 
119 #else /* not (_SYSCALL32_IMPL || _LP64) */
120 
121 #define	CACHEFS_ALLOC_CFS_METADATA(p, inp)				\
122 	p = (cfs_cachefs_metadata_t *)(inp)
123 
124 #define	CACHEFS_FREE_CFS_METADATA(p)
125 
126 #define	CACHEFS_COPY_METADATA_TO_CFS_METADATA(inmdp, outmdp, error)
127 
128 #define	CACHEFS_COPY_CFS_METADATA_TO_METADATA(inmdp, outmdp)
129 
130 #endif /* _SYSCALL32_IMPL || _LP64 */
131 
132 /* forward references */
133 int filegrp_write_space(vnode_t *vp, offset_t offset, ssize_t cnt);
134 int filegrpattr_find(struct filegrp *fgp);
135 int filegrpattr_create(struct filegrp *fgp);
136 
137 int
138 /*ARGSUSED*/
139 filegrp_cache_create(void *voidp, void *cdrarg, int kmflags)
140 {
141 	filegrp_t *fgp = (filegrp_t *)voidp;
142 
143 	mutex_init(&fgp->fg_mutex, NULL, MUTEX_DEFAULT, NULL);
144 	mutex_init(&fgp->fg_cnodelock, NULL, MUTEX_DEFAULT, NULL);
145 	return (0);
146 }
147 
148 void
149 /*ARGSUSED*/
150 filegrp_cache_destroy(void *voidp, void *cdrarg)
151 {
152 	filegrp_t *fgp = (filegrp_t *)voidp;
153 
154 	mutex_destroy(&fgp->fg_mutex);
155 	mutex_destroy(&fgp->fg_cnodelock);
156 }
157 
158 /*
159  * ------------------------------------------------------------------
160  *
161  *		filegrp_create
162  *
163  * Description:
164  *	Creates a filegrp object for the specified fscache.
165  *	The CFS_FG_ALLOC_{ATTR, FILE} bits will be set in fg_flags
166  *	if the cache is in NOCACHE and NOFILL mode or if
167  *	the directory does not exist yet.
168  *	The filegrp object maintains a reference to the specified
169  *	fscache.
170  * Arguments:
171  *	fscp	fscache to create the file group in
172  *	cidp	start cid for the file group
173  * Returns:
174  *	Returns the created filegrp object.
175  * Preconditions:
176  *	precond(fscp)
177  *	precond(cidp)
178  *	precond(fscp->fs_info.fi_fgsize > 0)
179  */
180 #define	Bugid_1249206_notfixed
181 #ifdef Bugid_1249206_notfixed
182 int bugid_1249206 = 0;
183 #endif
184 filegrp_t *
185 filegrp_create(struct fscache *fscp, cfs_cid_t *cidp)
186 {
187 	filegrp_t *fgp;
188 	int fgsize;
189 	int flags;
190 	ino64_t nfgsize;
191 
192 	fgsize = fscp->fs_info.fi_fgsize;
193 
194 	fgp = (filegrp_t *)
195 	    kmem_cache_alloc(cachefs_filegrp_cache, KM_SLEEP);
196 
197 	fgp->fg_flags = CFS_FG_ALLOC_ATTR | CFS_FG_ALLOC_FILE;
198 	fgp->fg_count = 0;
199 	fgp->fg_id = *cidp;
200 #ifdef Bugid_1249206_notfixed
201 	if (bugid_1249206)
202 		cmn_err(CE_CONT, "fg_id assigned value is %" PRId64 "\n",
203 		    fgp->fg_id.cid_fileno);
204 #endif
205 	nfgsize = (fgp->fg_id.cid_fileno / (ino64_t)fgsize);
206 	fgp->fg_id.cid_fileno = (ino64_t)(nfgsize * (ino64_t)fgsize);
207 #ifdef Bugid_1249206_notfixed
208 	if (bugid_1249206) {
209 		cmn_err(CE_CONT,
210 		    "cid_fileno for fscp %p fgp %p is %" PRId64 "\n",
211 		    (void *)fscp, (void *)fgp,
212 		    fgp->fg_id.cid_fileno);
213 		cmn_err(CE_CONT,
214 		    "sent fileno is %" PRId64 " fgsize %d nfgsize %" PRId64
215 		    "\n", cidp->cid_fileno, fgsize, nfgsize);
216 	}
217 #endif
218 	fgp->fg_fscp = fscp;
219 	fgp->fg_cnodelist = NULL;
220 	fgp->fg_next = NULL;
221 	fgp->fg_dirvp = NULL;
222 	fgp->fg_attrvp = NULL;
223 	fgp->fg_header = NULL;
224 	fgp->fg_offsets = NULL;
225 	fgp->fg_alloclist = NULL;
226 
227 	fgp->fg_headersize = (uint_t)sizeof (struct attrcache_header) +
228 	    (fgsize * (uint_t)sizeof (struct attrcache_index)) +
229 	    ((fgsize + 7) >> 3);
230 
231 	fgp->fg_filesize = fgp->fg_headersize +
232 	    (fgsize * (uint_t)sizeof (struct cfs_cachefs_metadata));
233 
234 	flags = fscp->fs_flags;
235 	if (flags & CFS_FS_READ) {
236 		fgp->fg_flags |= CFS_FG_READ;
237 		if (flags & CFS_FS_WRITE) {
238 			fgp->fg_flags |= CFS_FG_WRITE;
239 		}
240 	}
241 
242 	if (fgp->fg_flags & CFS_FG_READ) {
243 		/* find the attrcache file and frontfile directory */
244 		(void) filegrpattr_find(fgp);
245 
246 		/*
247 		 * XXX: we can tell from the file count in the attrcache
248 		 * whether we can expect to find a front file dir or
249 		 * not.  If not, we can save the lookup here...
250 		 */
251 		(void) filegrpdir_find(fgp);
252 	}
253 
254 	return (fgp);
255 }
256 
257 /*
258  * ------------------------------------------------------------------
259  *
260  *		filegrp_destroy
261  *
262  * Description:
263  *	Destroys the filegrp object and releases any kernel
264  *	resource associated with it.
265  *	Additionally if the on disk file group directory does
266  *	not contain any front files it is removed.
267  * Arguments:
268  *	fgp	filegrp object to destroy
269  * Returns:
270  * Preconditions:
271  *	precond(fgp is a valid filegrp object)
272  *	precond(fgp->fg_count == 0)
273  *	precond(fgp->fg_next == NULL)
274  */
275 
276 void
277 filegrp_destroy(filegrp_t *fgp)
278 {
279 	struct fscache *fscp = fgp->fg_fscp;
280 	char name[CFS_FRONTFILE_NAME_SIZE];
281 	char *fname;
282 	int error;
283 
284 	ASSERT(fgp->fg_count == 0);
285 	ASSERT(fgp->fg_next == NULL);
286 
287 	if (fgp->fg_attrvp) {
288 		if (fgp->fg_flags & CFS_FG_UPDATED) {
289 			error = filegrp_sync(fgp);
290 			if (error)
291 				cmn_err(CE_WARN,
292 				    "cachefs: UFS error on cache, "
293 				    "run fsck %d", error);
294 		}
295 		VN_RELE(fgp->fg_attrvp);
296 	}
297 	if (fgp->fg_header) {
298 		/*
299 		 * If there are no attrcache entries in use and
300 		 * if we can modify the cache.
301 		 */
302 		if ((fgp->fg_header->ach_count == 0) &&
303 		    (fgp->fg_flags & CFS_FG_WRITE)) {
304 			ASSERT(fgp->fg_header->ach_nffs == 0);
305 
306 			/* remove attrcache file from the rl list */
307 			ASSERT(fgp->fg_header->ach_rl_current ==
308 			    CACHEFS_RL_GC);
309 #ifdef CFSDEBUG
310 			cachefs_rlent_verify(fscp->fs_cache, CACHEFS_RL_GC,
311 			    fgp->fg_header->ach_rlno);
312 #endif /* CFSDEBUG */
313 
314 			/*
315 			 * XXX sam: since we're blowing away the
316 			 * attrcache file, i guess i don't need to set
317 			 * ach_rl_current to CACHEFS_RL_NONE and
318 			 * sync the attrcache file, right?
319 			 *
320 			 * fgp->fg_header->ach_rl_current = CACHEFS_RL_NONE;
321 			 * fgp->fg_flags |= CFS_FG_UPDATED;
322 			 */
323 
324 			/* remove the attrcache file */
325 			make_ascii_name(&fgp->fg_id, name);
326 			fname = name;
327 			error = VOP_REMOVE(fscp->fs_fsattrdir, fname, kcred,
328 			    NULL, 0);
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 references 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 references 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 references 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, NULL, 0);
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, NULL);
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, kcred, 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 	uchar_t 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] != (uchar_t)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 	uchar_t 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, NULL, NULL, NULL);
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, NULL, NULL, NULL);
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, kcred, 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 = ((uchar_t *)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, NULL,
1570 	    0, NULL);
1571 	if (error) {
1572 		fgp->fg_flags |= CFS_FG_NOCACHE;
1573 		cachefs_freefile(fscp->fs_cache);
1574 		cachefs_freeblocks(fscp->fs_cache, 1,
1575 		    fgp->fg_header->ach_rl_current);
1576 	} else {
1577 		fgp->fg_dirvp = dirvp;
1578 		fgp->fg_flags &= ~CFS_FG_ALLOC_FILE;
1579 	}
1580 
1581 	if (attrp)
1582 		cachefs_kmem_free(attrp, sizeof (*attrp));
1583 
1584 	return (error);
1585 }
1586 
1587 /*
1588  * ------------------------------------------------------------------
1589  *
1590  *		filegrpattr_create
1591  *
1592  * Description:
1593  *	Creates the attrcache file for the given filegrp.
1594  *	If created CFS_FG_ALLOC_ATTR is turned off.
1595  *	This routine should not be called if CFS_FG_ALLOC_ATTR is
1596  *	already off.
1597  * Arguments:
1598  *	fgp	filegrp object
1599  * Returns:
1600  *	Returns 0 on success, an errno value on failure.
1601  * Preconditions:
1602  *	precond(fgp is a valid filegrp object)
1603  *	precond(filegrp is writable)
1604  */
1605 
1606 int
1607 filegrpattr_create(struct filegrp *fgp)
1608 {
1609 	int error;
1610 	vnode_t *attrvp = NULL;
1611 	struct attrcache_header *ahp = NULL;
1612 	int nblks = 0;
1613 	int gotrlent = 0;
1614 	struct vattr *attrp = NULL;
1615 	char name[CFS_FRONTFILE_NAME_SIZE];
1616 	char *fname;
1617 	struct fscache *fscp = fgp->fg_fscp;
1618 	rl_entry_t rl_ent;
1619 
1620 	ASSERT(fgp->fg_flags & CFS_FG_WRITE);
1621 
1622 	if (fgp->fg_flags & CFS_FG_NOCACHE)
1623 		return (ENOENT);
1624 
1625 	cachefs_cache_dirty(fscp->fs_cache, 1);
1626 
1627 	/* allocate a file for the attrcache */
1628 	error = cachefs_allocfile(fscp->fs_cache);
1629 	if (error) {
1630 		goto out;
1631 	}
1632 
1633 	make_ascii_name(&fgp->fg_id, name);
1634 	fname = name;
1635 	attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP);
1636 	attrp->va_mode = S_IFREG | 0666;
1637 	attrp->va_uid = 0;
1638 	attrp->va_gid = 0;
1639 	attrp->va_type = VREG;
1640 	attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
1641 	error = VOP_CREATE(fscp->fs_fsattrdir, fname, attrp, EXCL, 0666,
1642 			&attrvp, kcred, 0, NULL, NULL);
1643 	if (error) {
1644 		cachefs_freefile(fscp->fs_cache);
1645 		goto out;
1646 	}
1647 
1648 	/* alloc blocks for the attrcache header */
1649 	nblks = (fgp->fg_headersize + MAXBSIZE - 1) / MAXBSIZE;
1650 	error = cachefs_allocblocks(fscp->fs_cache, nblks, CACHEFS_RL_NONE);
1651 	if (error) {
1652 		nblks = 0;
1653 		goto out;
1654 	}
1655 
1656 	/* Construct an attrcache header */
1657 	ahp = cachefs_kmem_zalloc(fgp->fg_headersize, KM_SLEEP);
1658 
1659 	/* write out the header to allocate space on ufs */
1660 	error = vn_rdwr(UIO_WRITE, attrvp, (caddr_t)ahp,
1661 	fgp->fg_headersize, 0LL, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY,
1662 		kcred, NULL);
1663 	if (error)
1664 		goto out;
1665 	error = filegrp_write_space(attrvp, (offset_t)fgp->fg_headersize,
1666 		(nblks * MAXBSIZE) - fgp->fg_headersize);
1667 	if (error)
1668 		goto out;
1669 	error = VOP_FSYNC(attrvp, FSYNC, kcred, NULL);
1670 	if (error)
1671 		goto out;
1672 
1673 	/* allocate an rl entry and mark it as an attrcache entry */
1674 	rl_ent.rl_fileno = fgp->fg_id.cid_fileno;
1675 	rl_ent.rl_local = (fgp->fg_id.cid_flags & CFS_CID_LOCAL) ? 1 : 0;
1676 	rl_ent.rl_fsid = fscp->fs_cfsid;
1677 	rl_ent.rl_attrc = 1;
1678 	error = cachefs_rl_alloc(fscp->fs_cache, &rl_ent, &ahp->ach_rlno);
1679 	if (error)
1680 		goto out;
1681 	gotrlent = 1;
1682 	if (fgp->fg_count == 0) {
1683 		/* put on the gc */
1684 		cachefs_rlent_moveto(fgp->fg_fscp->fs_cache, CACHEFS_RL_GC,
1685 		    ahp->ach_rlno, nblks);
1686 		ahp->ach_rl_current = CACHEFS_RL_GC;
1687 	} else {
1688 		/* put on attrfile list */
1689 		cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
1690 		    CACHEFS_RL_ATTRFILE, ahp->ach_rlno, nblks);
1691 		ahp->ach_rl_current = CACHEFS_RL_ATTRFILE;
1692 	}
1693 
1694 out:
1695 	if (error) {
1696 		fgp->fg_flags |= CFS_FG_NOCACHE;
1697 		if (attrvp) {
1698 			VN_RELE(attrvp);
1699 			(void) VOP_REMOVE(fscp->fs_fsattrdir, fname, kcred,
1700 			    NULL, 0);
1701 			cachefs_freefile(fscp->fs_cache);
1702 		}
1703 		if (nblks)
1704 			cachefs_freeblocks(fscp->fs_cache, nblks,
1705 			    CACHEFS_RL_NONE);
1706 		if (gotrlent)
1707 			cachefs_rlent_moveto(fscp->fs_cache,
1708 			    CACHEFS_RL_FREE, ahp->ach_rlno, 0);
1709 		if (ahp)
1710 			cachefs_kmem_free(ahp, fgp->fg_headersize);
1711 	} else {
1712 		fgp->fg_attrvp = attrvp;
1713 		fgp->fg_header = ahp;
1714 		fgp->fg_offsets = (struct attrcache_index *)(ahp + 1);
1715 		fgp->fg_alloclist = ((uchar_t *)fgp->fg_offsets) +
1716 			(fscp->fs_info.fi_fgsize *
1717 			sizeof (struct attrcache_index));
1718 		ahp->ach_count = 0;
1719 		ahp->ach_nffs = 0;
1720 		ahp->ach_nblks = nblks;
1721 		fgp->fg_flags &= ~CFS_FG_ALLOC_ATTR;
1722 		fgp->fg_flags |= CFS_FG_UPDATED;
1723 	}
1724 
1725 	if (attrp)
1726 		cachefs_kmem_free(attrp, sizeof (*attrp));
1727 
1728 	return (error);
1729 }
1730 
1731 /*
1732  * ------------------------------------------------------------------
1733  *
1734  *		filegrp_cid_to_slot
1735  *
1736  * Description:
1737  *	Takes a file and returns the offset to the metadata
1738  *	slot for the specified filegrp.
1739  * Arguments:
1740  *	fgp	filegrp object
1741  *	cidp	file to map to an offset
1742  * Returns:
1743  *	Returns the offset or 0 if the slot is not allocated yet
1744  *	or it is invalid.
1745  * Preconditions:
1746  *	precond(fgp is a valid filegrp object)
1747  *	precond(fgp is not ALLOC_PENDING or NOCACHE)
1748  */
1749 
1750 int
1751 filegrp_cid_to_slot(filegrp_t *fgp, cfs_cid_t *cidp)
1752 {
1753 	int xx;
1754 	int slot;
1755 	int index;
1756 
1757 	index = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
1758 
1759 	if (index > fgp->fg_fscp->fs_info.fi_fgsize) {
1760 		cmn_err(CE_WARN, "cachefs: attrcache error, run fsck");
1761 		return (0);
1762 	}
1763 
1764 	slot = fgp->fg_offsets[index].ach_offset;
1765 	if (slot == 0)
1766 		return (0);
1767 
1768 	xx = fgp->fg_filesize - (int)sizeof (struct cfs_cachefs_metadata);
1769 	if ((slot < fgp->fg_headersize) || (xx < slot)) {
1770 		cmn_err(CE_WARN, "cachefs: attrcache error, run fsck");
1771 		return (0);
1772 	}
1773 
1774 	return (slot);
1775 }
1776 
1777 /*
1778  *
1779  *		filegrp_write_space
1780  *
1781  * Description:
1782  *	Writes garbage data to the specified file starting
1783  *	at the specified location for the specified number of bytes.
1784  *	slot for the specified filegrp.
1785  * Arguments:
1786  *	vp	vnode to write to
1787  *	offset	offset to write at
1788  *	cnt	number of bytes to write
1789  * Returns:
1790  *	Returns 0 for success or on error the result of the
1791  *	last vn_rdwr call.
1792  * Preconditions:
1793  *	precond(vp)
1794  */
1795 
1796 int
1797 filegrp_write_space(vnode_t *vp, offset_t offset, ssize_t cnt)
1798 {
1799 	char *bufp;
1800 	int xx;
1801 	int error = 0;
1802 
1803 	bufp = (char *)cachefs_kmem_zalloc(MAXBSIZE, KM_SLEEP);
1804 	while (cnt > 0) {
1805 		if (cnt > MAXBSIZE)
1806 			xx = MAXBSIZE;
1807 		else
1808 			xx = (int)cnt;
1809 		error = vn_rdwr(UIO_WRITE, vp, (caddr_t)bufp,
1810 		xx, offset, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY,
1811 			kcred, NULL);
1812 		if (error)
1813 			break;
1814 		offset += xx;
1815 		cnt -= xx;
1816 	}
1817 	cachefs_kmem_free(bufp, MAXBSIZE);
1818 	return (error);
1819 }
1820