cachefs_subr.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/pathname.h>
#include <sys/sysmacros.h>
int segmap_release();
extern struct cnode *cachefs_freeback;
extern struct cnode *cachefs_freefront;
extern cachefscache_t *cachefs_cachelist;
#ifdef CFSDEBUG
int cachefsdebug = 0;
#endif
static int
/*
* Cache routines
*/
/*
* ------------------------------------------------------------------
*
* cachefs_cache_create
*
* Description:
* Creates a cachefscache_t object and initializes it to
* be NOCACHE and NOFILL mode.
* Arguments:
* Returns:
* Returns a pointer to the created object or NULL if
* threads could not be created.
* Preconditions:
*/
cachefs_cache_create(void)
{
struct cachefs_req *rp;
/* allocate zeroed memory for the object */
/* set up the work queue and get the sync thread created */
return (cachep);
}
/*
* ------------------------------------------------------------------
*
* cachefs_cache_destroy
*
* Description:
* Destroys the cachefscache_t object.
* Arguments:
* cachep the cachefscache_t object to destroy
* Returns:
* Preconditions:
* precond(cachep)
*/
void
{
int error = 0;
#ifdef CFSRLDEBUG
#endif /* CFSRLDEBUG */
/* stop async threads */
/* kill off the cachep worker thread */
}
(void) cachefs_cache_rssync(cachep);
}
/* if there is a cache */
#ifdef CFSRLDEBUG
/* blow away dangling rl debugging info */
for (index = 0;
index++) {
rlent);
/*
* Since we are destroying the cache,
* better to ignore and proceed
*/
if (error)
break;
}
#endif /* CFSRLDEBUG */
/* sync the cache */
if (!error)
} else {
/* get rid of any unused fscache objects */
}
}
sizeof (cachefs_log_control_t));
}
/*
* ------------------------------------------------------------------
*
* cachefs_cache_active_ro
*
* Description:
* Activates the cachefscache_t object for a read-only file system.
* Arguments:
* cachep the cachefscache_t object to activate
* cdvp the vnode of the cache directory
* Returns:
* Returns 0 for success, !0 if there is a problem with the cache.
* Preconditions:
* precond(cachep)
* precond(cdvp)
* precond(cachep->c_flags & CACHE_NOCACHE)
*/
int
{
int error;
/* get the mode bits of the cache directory */
if (error)
goto out;
/* ensure the mode bits are 000 to keep out casual users */
goto out;
}
/* Get the lock file */
kcred);
if (error) {
" run fsck.\n");
goto out;
}
/* Get the label file */
kcred);
if (error) {
" run fsck.\n");
goto out;
}
/* read in the label */
if (error) {
" run fsck.\n");
goto out;
}
/* Verify that we can handle the version this cache was created under */
goto out;
}
/* Open the resource file */
if (error) {
" run fsck.\n");
goto out;
}
/* Read the usage struct for this cache */
if (error) {
" run fsck.\n");
goto out;
}
/* ENOSPC is what UFS uses for clean flag check */
goto out;
}
/* Read the rlinfo for this cache */
if (error) {
" run fsck.\n");
goto out;
}
/* Open the lost+found directory */
if (error) {
" run fsck.\n");
goto out;
}
/* get the cachep worker thread created */
/* allocate the `logging control' field */
/* if the LOG_STATUS_NAME file exists, read it in and set up logging */
if (error == 0) {
int vnrw_error;
if (vnrw_error == 0) {
== NULL)
}
} else {
error = 0;
}
out:
if (error == 0) {
}
if (attrp)
if (lockvp)
if (lostfoundvp)
return (error);
}
int
{
int i;
int error = 0;
/* XXX verify lock-ordering for this function */
/*
* no work if we're already in nocache mode. hopefully this
* will be the usual case.
*/
return (0);
}
return (EINVAL);
}
/* We are already not caching if nfsv4 */
if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
return (0);
}
#ifdef CFSDEBUG
printf("cachefs_stop_cache: resetting CACHE_NOCACHE\n");
#endif
/* XXX should i worry about disconnected during boot? */
if (error)
goto out;
/* sigh -- best to keep going if async_halt failed. */
error = 0;
/* XXX current order: cnode, fgp, fscp, cache. okay? */
for (i = 0; i < CFS_FS_FGP_BUCKET_SIZE; i++) {
(CFS_FG_WRITE | CFS_FG_UPDATED)) == 0);
}
}
}
}
if (fscp->fs_fscdirvp) {
}
if (fscp->fs_fsattrdir) {
}
}
/* XXX dlog stuff? */
/*
* release resources grabbed in cachefs_cache_activate_ro
*/
/* kill off the cachep worker thread */
}
if (cachep->c_resfilevp) {
}
}
}
if (cachep->c_lostfoundvp) {
}
sizeof (cachefs_log_control_t));
}
}
/* XXX do what mountroot_init does when ! foundcache */
/* XXX should i release this here? */
out:
return (error);
}
/*
* ------------------------------------------------------------------
*
* cachefs_cache_active_rw
*
* Description:
* Activates the cachefscache_t object for a read-write file system.
* Arguments:
* cachep the cachefscache_t object to activate
* Returns:
* Preconditions:
* precond(cachep)
* precond((cachep->c_flags & CACHE_NOCACHE) == 0)
* precond(cachep->c_flags & CACHE_NOFILL)
*/
void
{
/* move the active list to the rl list */
if (lhp->rli_itemcnt != 0)
}
/*
* ------------------------------------------------------------------
*
* cachefs_cache_dirty
*
* Description:
* Marks the cache as dirty (active).
* Arguments:
* cachep the cachefscache_t to mark as dirty
* lockit 1 means grab contents lock, 0 means caller grabbed it
* Returns:
* Preconditions:
* precond(cachep)
* precond(cache is in rw mode)
*/
void
{
int error;
if (lockit) {
} else {
}
} else {
/*
* turn on the "cache active" (dirty) flag and write it
* synchronously to disk
*/
"cachefs: clean flag write error: %d\n", error);
}
}
if (lockit)
}
/*
* ------------------------------------------------------------------
*
* cachefs_cache_rssync
*
* Description:
* Syncs out the resource file for the cachefscache_t object.
* Arguments:
* cachep the cachefscache_t object to operate on
* Returns:
* Returns 0 for success, !0 on an error writing data.
* Preconditions:
* precond(cachep)
* precond(cache is in rw mode)
*/
int
{
int error;
CACHE_ALLOC_PENDING)) == 0);
if (error)
}
/* write the usage struct for this cache */
if (error) {
}
/* write the rlinfo for this cache */
if (error) {
}
return (error);
}
/*
* ------------------------------------------------------------------
*
* cachefs_cache_sync
*
* Description:
* Sync a cache which includes all of its fscaches.
* Arguments:
* cachep the cachefscache_t object to sync
* Returns:
* Preconditions:
* precond(cachep)
* precond(cache is in rw mode)
*/
void
{
int try;
int done;
return;
done = 0;
nfscs = 0;
/*
* here we turn off the cache-wide DIRTY flag. If it's still
* off when the sync completes we can write the clean flag to
* disk telling fsck it has no work to do.
*/
#ifdef CFSCLEANFLAG
#endif /* CFSCLEANFLAG */
}
}
/* get rid of any unused fscache objects */
/*
* here we check the cache-wide DIRTY flag.
* If it's off,
* we can write the clean flag to disk.
*/
#ifdef CFSCLEANFLAG
if (cachefs_cache_rssync(cachep) == 0) {
done = 1;
} else {
}
} else {
done = 1;
}
}
#else /* CFSCLEANFLAG */
(void) cachefs_cache_rssync(cachep);
done = 1;
#endif /* CFSCLEANFLAG */
}
}
/*
* ------------------------------------------------------------------
*
* cachefs_cache_unique
*
* Description:
* Arguments:
* Returns:
* Returns a unique number.
* Preconditions:
* precond(cachep)
*/
{
int error = 0;
}
if (error == 0)
return (unique);
}
/*
* Called from c_getfrontfile. Shouldn't be called from anywhere else !
*/
static int
{
char name[CFS_FRONTFILE_NAME_SIZE];
int error = 0;
int mode;
int alloc = 0;
int freefile = 0;
int ffrele = 0;
int rlfree = 0;
#ifdef CFSDEBUG
printf("c_createfrontfile: ENTER cp %p fgp %p\n",
#endif
/* quit if we cannot write to the filegrp */
goto out;
}
/* find or create the filegrp attrcache file if necessary */
if (error)
goto out;
}
/* set up attributes for the front file we want to create */
alloc++;
mode = 0666;
/* get a file from the resource counts */
if (error) {
goto out;
}
freefile++;
/* create the metadata slot if necessary */
if (error) {
goto out;
}
}
/* get an rl entry if necessary */
if (error)
goto out;
rlfree++;
/* increment number of front files */
if (error) {
goto out;
}
ffrele++;
}
/* lookup the already created front file */
} else {
/* create the front file */
}
if (error) {
#ifdef CFSDEBUG
printf("c_createfrontfile: Can't create cached object"
" error %u, fileno %llx\n", error,
#endif
goto out;
}
/* get a copy of the fid of the front file */
if (error) {
/*
* If we get back ENOSPC then the fid we passed in was too
* small. For now we don't do anything and map to EINVAL.
*/
}
goto out;
}
out:
if (error) {
}
if (ffrele)
if (freefile)
if (rlfree) {
#ifdef CFSDEBUG
#endif /* CFSDEBUG */
}
}
if (alloc)
#ifdef CFSDEBUG
name);
#endif
return (error);
}
/*
* Releases resources associated with the front file.
* Only call this routine if a ffhold has been done.
* Its okay to call this routine if the front file does not exist.
* Note: this routine is used even if there is no front file.
*/
void
{
enoent = 0;
return;
}
enoent = 1;
}
kcred);
}
}
sizeof (struct cachefs_allocmap));
}
/*
* Clear packed bit, fastsymlinks and special files
* do not have a front file.
*/
/* XXX either rename routine or move this to caller */
if (enoent == 0)
if (mdp->md_frontblks) {
mdp->md_frontblks = 0;
}
}
/*
* This is the interface to the rest of CFS. This takes a cnode, and returns
* the frontvp (stuffs it in the cnode). This creates an attrcache slot and
* and frontfile if necessary.
*/
int
{
int error;
#ifdef CFSDEBUG
#endif
/*
* Now we check to see if there is a front file for this entry.
* If there is, we get the vnode for it and stick it in the cnode.
* Otherwise, we create a front file, get the vnode for it and stick
* it in the cnode.
*/
goto out;
}
/*
* If the cnode is being populated, and we're not the populating
* thread, then block until the pop thread completes. If we are the
* pop thread, then we may come in here, but not to nuke the directory
* cnode at a critical juncture. If we return from a cv_wait and the
* cnode is now stale, don't bother trying to get the front file.
*/
goto out;
}
}
#ifdef CFSDEBUG
"c_getfrontfile: !MD_FILE and frontvp not null cp %p\n",
(void *)cp);
#endif
if (error)
goto out;
} else {
/*
* A front file exists, all we need to do is to grab the fid,
* do a VFS_VGET() on the fid, stuff the vnode in the cnode,
* and return.
*/
" run fsck\n");
goto out;
}
#ifdef CFSDEBUG
printf("cachefs: "
"gff1: front file system error %d\n",
error);
#endif /* CFSDEBUG */
goto out;
}
/* don't need to check timestamps if need_front_sync is set */
error = 0;
goto out;
}
/* don't need to check empty directories */
error = 0;
goto out;
}
/* get modify time of the front file */
if (error) {
" system error %d", error);
goto out;
}
/* compare with modify time stored in metadata */
sizeof (timestruc_t)) != 0) {
#ifdef CFSDEBUG
printf("c_getfrontfile: timestamps don't"
" match fileno %lld va %lx %lx"
" meta %lx %lx\n",
}
#endif
}
}
out:
#ifdef CFSDEBUG
#endif
return (error);
}
void
{
int error;
#if 0
debug_enter("inval object during async pop");
#endif
/* if we cannot modify the cache */
(CACHE_NOFILL | CACHE_NOCACHE)) {
goto out;
}
/* if there is a front file */
goto out;
/* get the front file vp if necessary */
#ifdef CFSDEBUG
printf("cachefs: "
"io: front file error %d\n", error);
#endif /* CFSDEBUG */
goto out;
}
}
/* truncate the file to zero size */
if (error)
goto out;
/* if a directory, v_type is zero if called from initcnode */
}
} else
}
} else {
}
out:
/* unconditionally set CN_UPDATED below */
}
}
/*
* If the object invalidated is a directory, the dnlc should be purged
* to elide all references to this (directory) vnode.
*/
#ifdef CFSDEBUG
printf("c_inval_object: EXIT\n");
#endif
}
void
{
int i = sizeof (uint_t) * 4;
*strp++ = 'L';
do {
name <<= 4;
} while (--i);
*strp = '\0';
}
void
{
#ifdef CFSDEBUG
#endif
#ifdef CFSDEBUG
printf("cachefs_nocache: invalidating %llu\n",
#endif
/*
* Here we are waiting until inactive time to do
* the inval_object. In case we don't get to inactive
* (because of a crash, say) we set up a timestamp mismatch
* such that getfrontfile will blow the front file away
* next time we try to use it.
*/
/*
* It is possible we can nocache while disconnected.
* A directory could be nocached by running out of space.
* A regular file should only be nocached if an I/O error
* occurs to the front fs.
* We count on the item staying on the modified list
* so we do not loose the cid to fid mapping for directories.
*/
/* unconditionally set CN_UPDATED below */
}
}
}
#ifdef CFSDEBUG
#endif
}
/*
* Checks to see if the page is in the disk cache, by checking the allocmap.
*/
int
{
int i;
else
/*LINTED alignment okay*/
struct cachefs_allocmap *allocp =
if ((off + size_to_look) <=
off, size_to_look);
/*
* Found the page in the CFS disk cache.
*/
return (1);
}
} else {
return (0);
}
}
return (0);
}
/*
* Merges adjacent allocmap entries together where possible, e.g.
* offset=0x0, size=0x40000
* offset=0x40000, size=0x20000 becomes just offset=0x0, size-0x90000
* offset=0x60000, size=0x30000
*/
void
{
int i, reduced = 0;
allocp++;
allocp->am_start_off) {
reduced++;
} else {
nallocp++;
}
}
}
/*
* Updates the allocmap to reflect a new chunk of data that has been
* populated.
*/
void
{
int i;
struct cachefs_allocmap *allocp;
/*
* We try to see if we can coalesce the current block into an existing
* allocation and mark it as such.
* If we can't do that then we make a new entry in the allocmap.
* when we run out of allocmaps, put the cnode in NOCACHE mode.
*/
return;
} else {
goto again;
}
} else {
return;
}
return;
}
}
}
if (i == C_MAX_ALLOCINFO_SLOTS) {
#ifdef CFSDEBUG
printf("c_update_alloc_map: "
"Too many allinfo entries cp %p fileno %llu %p\n",
#endif
return;
}
}
/*
* CFS population function
*
* before async population, this function used to turn on the cnode
* flags CN_UPDATED, CN_NEED_FRONT_SYNC, and CN_POPULATION_PENDING.
* now, however, it's the responsibility of the caller to do this if
* this function returns 0 (no error).
*/
int
{
int error = 0;
#ifdef CFSDEBUG
printf("cachefs_populate: ENTER cp %p off %lld\n",
#endif
goto out;
else if (error) {
#ifdef CFSDEBUG
printf("cachefs_populate: fbread error %d\n",
error);
#endif
goto out;
}
goto out;
}
resid = 0;
if (error) {
#ifdef CFSDEBUG
printf("cachefs_populate: "
"Got error = %d from vn_rdwr\n", error);
#endif
goto out;
}
#ifdef CFSDEBUG
if (resid)
printf("cachefs_populate: non-zero resid %ld\n",
resid);
#endif
}
out:
popsize);
#ifdef CFSDEBUG
printf("cachefs_populate: EXIT cp %p error %d\n",
#endif
return (error);
}
/*
* due to compiler error we shifted cnode to the last argument slot.
* occured during large files project - XXX.
*/
void
{
int i;
u_offset_t lastoff = 0;
u_offset_t forward_diff = 0;
u_offset_t backward_diff = 0;
#ifdef CFSDEBUG
printf("cachefs_cluster_allocmap: off %llx, size %llx, "
#endif /* CFSDEBUG */
struct cachefs_allocmap *allocp =
if (backward_diff > off)
backward_diff = off;
} else {
forward_diff = size;
}
return;
} else {
}
}
} else {
}
/*
* 64bit project: popsize is the chunk size used to populate the
* cache (default 64K). As such, 32 bit should suffice.
*/
else
#ifdef CFSDEBUG
printf("cachefs_cluster_allocmap: popoff %llx, popsize %llx\n",
#endif /* CFSDEBUG */
}
/*
* "populate" a symlink in the cache
*/
int
{
int error = 0;
if (CFS_ISFS_BACKFS_NFSV4(fscp))
goto out;
return (ENOENT);
/* if can create a fast sym link */
if (buflen <= C_FSL_SIZE) {
/* give up the front file resources */
}
/* put sym link contents in allocinfo in metadata */
goto out;
}
/* else create a sym link in a front file */
if (error)
goto out;
/* truncate front file */
if (error)
goto out;
/* get space for the sym link */
if (error)
goto out;
/* write the sym link to the front file */
if (error) {
goto out;
}
out:
return (error);
}
/*
* Reads the full contents of the symbolic link from the back file system.
* *bufp is set to a MAXPATHLEN buffer that must be freed when done
* *buflenp is the length of the link
*/
int
{
int error;
/* get back vnode */
if (error)
return (error);
}
/* set up for the readlink */
uio.uio_loffset = 0;
/* get the link data */
("cachefs_readlink (nfsv4): cnode %p, backvp %p\n",
if (error) {
} else {
/*LINTED alignment okay*/
}
return (error);
}
int
{
int error = 0;
int flag;
#ifdef CFSDEBUG
printf("cachefs_getbackvp: ENTER fscp %p cp %p\n",
#endif
/*
* If destroy is set then the last link to a file has been
* removed. Oddly enough NFS will still return a vnode
* for the file if the timeout has not expired.
* This causes headaches for cachefs_push because the
* vnode is really stale.
* So we just short circuit the problem here.
*/
return (ESTALE);
return (ETIMEDOUT);
/*
* XXX bob: really should pass in the correct flag,
* fortunately nobody pays attention to it
*/
flag = 0;
/*
* If NEEDOOPEN is set, then this file was opened VOP_OPEN'd
* but the backvp was not. So, for the sake of the vnode
* open counts used by delegation, we need to OPEN the backvp
* with the same flags that were used for this cnode. That way
* when the file is VOP_CLOSE'd the counts won't go negative.
*/
}
}
}
if (error) {
}
}
#ifdef CFSDEBUG
printf("Stale cookie cp %p fileno %llu type %d \n",
}
}
#endif
#ifdef CFSDEBUG
#endif
return (error);
}
int
{
int error = 0;
#ifdef CFSDEBUG
#endif
/*
* Get the FID only if the caller has indicated it is valid,
* otherwise, zero the cookie.
*/
if (valid_fid) {
/*
* This assumes that the cookie is a full size fid, if we go to
* variable length fids we will need to change this.
*/
} else {
}
if (!error) {
if (attrp) {
}
} else {
/*
* This is an indication that the underlying filesystem
* needs a bigger fid. For now just map to EINVAL.
*/
}
}
#ifdef CFSDEBUG
#endif
return (error);
}
void
{
qp->wq_max_len =
qp->wq_halt_request = 0;
qp->wq_keepone = 0;
}
/*
* return non-zero if it's `okay' to queue more requests (policy)
*/
static int cachefs_async_max = 512;
static int cachefs_async_count = 0;
int
cachefs_async_okay(void)
{
/*
* a value of -1 for max means to ignore freemem
*/
if (cachefs_async_max == -1)
return (1);
return (0);
/*
* a value of 0 for max means no arbitrary limit (only `freemen')
*/
if (cachefs_async_max == 0)
return (1);
ASSERT(cachefs_async_max > 0);
/*
* check the global count against the max.
*
* we don't need to grab cachefs_async_lock -- we're just
* looking, and a little bit of `fuzz' is okay.
*/
if (cachefs_async_count >= cachefs_async_max)
return (0);
return (1);
}
void
{
struct cachefs_req *rp;
int left;
left = 1;
for (;;) {
/* if there are no pending requests */
/* see if thread should exit */
(qp->wq_keepone == 0))
break;
}
/* wake up thread in async_halt if necessary */
if (qp->wq_halt_request)
/* sleep until there is something to do */
&qp->wq_queue_lock);
continue;
}
left = 1;
if (qp->wq_logwork) {
qp->wq_logwork = 0;
continue;
}
/* remove request from the list */
/* do the request */
/* decrement count of requests */
}
qp->wq_thread_count--;
thread_exit();
/*NOTREACHED*/
}
/*
* attempt to halt all the async threads associated with a given workq
*/
int
{
int error = 0;
if (force)
qp->wq_keepone = 0;
if (qp->wq_thread_count > 0) {
qp->wq_halt_request++;
qp->wq_halt_request--;
if (qp->wq_thread_count > 0) {
else
} else {
}
}
return (error);
}
void
{
if (qp->wq_thread_count == 0 ||
qp->wq_thread_count++;
}
}
else
}
void
{
}
}
void
{
int error = 0; /* not returned -- used as a place-holder */
int havelock = 0;
return; /* goto out */
}
if (error) {
#ifdef CFSDEBUG
printf("async_pop: cd_access: err %d con %d\n",
#endif /* CFSDEBUG */
return; /* goto out */
}
/*
* grab the statelock for some minimal things
*/
havelock = 1;
goto out;
/* there can be only one */
goto out;
#ifdef CFSDEBUG
printf("cachefs_async_populate: nocache bit on\n");
#endif /* CFSDEBUG */
goto out;
}
havelock = 0;
/*
* if frontfile doesn't exist, drop the lock
* to do some of the file creation stuff.
*/
if (error != 0)
goto out;
}
else
if (error != 0) {
goto out;
}
}
}
char name[CFS_FRONTFILE_NAME_SIZE];
sizeof (struct vattr));
}
havelock = 1;
}
}
goto out;
goto out;
}
case VREG:
havelock = 0;
break;
case VDIR:
havelock = 0;
break;
default:
#ifdef CFSDEBUG
printf("cachefs_async_populate: warning: vnode type = %d\n",
ASSERT(0);
#endif /* CFSDEBUG */
break;
}
if (error != 0)
goto out;
if (error != 0) {
#ifdef CFSDEBUG
printf("cachefs_async_populate: fsync\n");
#endif /* CFSDEBUG */
goto out;
}
/* grab the lock and finish up */
havelock = 1;
/* if went nocache while lock was dropped, get out */
goto out;
}
if (error) {
#ifdef CFSDEBUG
printf("cachefs_async_populate: getattr\n");
#endif /* CFSDEBUG */
goto out;
}
out:
if (! havelock)
/* see if an error happened behind our backs */
#ifdef CFSDEBUG
printf("cachefs_async_populate: "
"nocache behind our backs\n");
#endif /* CFSDEBUG */
}
if (error != 0)
/* unblock any threads waiting for populate to finish */
}
}
}
/*
* only to be called from cachefs_async_populate
*/
static int
{
int error = 0;
if (popsize == 0) {
#ifdef CFSDEBUG
printf("cachefs_async_populate: popsize == 0\n");
#endif /* CFSDEBUG */
goto out;
}
if (error != 0) {
#ifdef CFSDEBUG
printf("cachefs_async_populate: cachefs_populate\n");
#endif /* CFSDEBUG */
goto out;
}
out:
return (error);
}
void
{
struct cachefscache *cachep;
case CFS_INVALID:
panic("cachefs_do_req: CFS_INVALID operation on queue");
/*NOTREACHED*/
case CFS_CACHE_SYNC:
break;
case CFS_IDLE:
break;
case CFS_PUTPAGE:
break;
case CFS_POPULATE:
break;
case CFS_NOOP:
break;
default:
panic("c_do_req: Invalid CFS async operation");
}
}
ssize_t cachefs_mem_usage = 0;
struct km_wrap {
};
void *
{
#ifdef DEBUG
return (NULL);
}
/*LINTED alignment okay*/
/*LINTED alignment okay*/
/*LINTED alignment okay*/
ASSERT(cachefs_mem_usage >= 0);
cachefs_mem_usage += n;
#else /* DEBUG */
#endif /* DEBUG */
}
void *
{
#ifdef DEBUG
return (NULL);
}
/*LINTED alignment okay*/
/*LINTED alignment okay*/
/*LINTED alignment okay*/
ASSERT(cachefs_mem_usage >= 0);
cachefs_mem_usage += n;
#else /* DEBUG */
#endif /* DEBUG */
}
void
{
#ifdef DEBUG
void *p;
cachefs_mem_usage -= n;
ASSERT(cachefs_mem_usage >= 0);
p = front_kwp;
kmem_free(p, n);
#else /* DEBUG */
#endif /* DEBUG */
}
char *
cachefs_strdup(char *s)
{
char *rc;
return (rc);
}
int
{
int error = 0;
if (rw == KSTAT_WRITE) {
cachep->c_gc_after);
return (error);
}
return (error);
}
#ifdef DEBUG
{
else
if (chain)
KM_SLEEP);
}
}
return (cdb);
}
void
{
int i;
printf("cdb: %p count: %d timelapse: %ld.%9ld\n",
printf("flags: %x int: %d pointer: %p\n",
printf("cnode: %p fscp: %p cachep: %p\n",
printf("frontvp: %p backvp: %p\n",
char *sym;
}
}
}
#endif /* DEBUG */
/*
* Changes the size of the front file.
* Returns 0 for success or error if cannot set file size.
* NOCACHE bit is ignored.
* c_size is ignored.
* statelock must be held, frontvp must be set.
* File must be populated if setting to a size other than zero.
*/
int
{
int error = 0;
int alloc = 0;
struct cachefs_allocmap *allocp;
/* if growing the file, allocate space first, we charge for holes */
if (length) {
if (error)
goto out;
alloc = 1;
}
}
/* change the size of the front file */
if (error)
goto out;
/* zero out the alloc map */
if (length == 0) {
/* free up blocks */
}
} else {
/* update number of blocks if shrinking file */
}
/* fix up alloc map to reflect new size */
allocp->am_start_off = 0;
}
out:
return (error);
}
/*ARGSUSED*/
int
{
/*
* XXX don't do this! if you need this, you can't use this
* constructor.
*/
return (0);
}
/*ARGSUSED*/
void
{
}