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