Home | History | Annotate | Download | only in cachefs
      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