10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
55331Samw * Common Development and Distribution License (the "License").
65331Samw * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*11066Srafael.vanoni@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <sys/param.h>
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/systm.h>
290Sstevel@tonic-gate #include <sys/cred.h>
300Sstevel@tonic-gate #include <sys/proc.h>
310Sstevel@tonic-gate #include <sys/user.h>
320Sstevel@tonic-gate #include <sys/vfs.h>
330Sstevel@tonic-gate #include <sys/vnode.h>
340Sstevel@tonic-gate #include <sys/pathname.h>
350Sstevel@tonic-gate #include <sys/uio.h>
360Sstevel@tonic-gate #include <sys/tiuser.h>
370Sstevel@tonic-gate #include <sys/sysmacros.h>
380Sstevel@tonic-gate #include <sys/kmem.h>
390Sstevel@tonic-gate #include <sys/mount.h>
400Sstevel@tonic-gate #include <sys/ioctl.h>
410Sstevel@tonic-gate #include <sys/statvfs.h>
420Sstevel@tonic-gate #include <sys/errno.h>
430Sstevel@tonic-gate #include <sys/debug.h>
440Sstevel@tonic-gate #include <sys/cmn_err.h>
450Sstevel@tonic-gate #include <sys/utsname.h>
460Sstevel@tonic-gate #include <sys/modctl.h>
470Sstevel@tonic-gate #include <sys/file.h>
480Sstevel@tonic-gate #include <sys/stat.h>
490Sstevel@tonic-gate #include <sys/fcntl.h>
500Sstevel@tonic-gate #include <sys/fbuf.h>
510Sstevel@tonic-gate #include <sys/dnlc.h>
520Sstevel@tonic-gate #include <sys/callb.h>
530Sstevel@tonic-gate #include <sys/kobj.h>
540Sstevel@tonic-gate #include <sys/rwlock.h>
550Sstevel@tonic-gate
560Sstevel@tonic-gate #include <sys/vmsystm.h>
570Sstevel@tonic-gate #include <vm/hat.h>
580Sstevel@tonic-gate #include <vm/as.h>
590Sstevel@tonic-gate #include <vm/page.h>
600Sstevel@tonic-gate #include <vm/pvn.h>
610Sstevel@tonic-gate #include <vm/seg.h>
620Sstevel@tonic-gate #include <vm/seg_map.h>
630Sstevel@tonic-gate #include <vm/seg_vn.h>
640Sstevel@tonic-gate #include <vm/rm.h>
650Sstevel@tonic-gate #include <sys/fs/cachefs_fs.h>
660Sstevel@tonic-gate #include <sys/fs/cachefs_log.h>
670Sstevel@tonic-gate #include <sys/fs/cachefs_dir.h>
680Sstevel@tonic-gate
690Sstevel@tonic-gate extern struct seg *segkmap;
700Sstevel@tonic-gate caddr_t segmap_getmap();
710Sstevel@tonic-gate int segmap_release();
720Sstevel@tonic-gate
730Sstevel@tonic-gate extern struct cnode *cachefs_freeback;
740Sstevel@tonic-gate extern struct cnode *cachefs_freefront;
750Sstevel@tonic-gate extern cachefscache_t *cachefs_cachelist;
760Sstevel@tonic-gate
770Sstevel@tonic-gate #ifdef CFSDEBUG
780Sstevel@tonic-gate int cachefsdebug = 0;
790Sstevel@tonic-gate #endif
800Sstevel@tonic-gate
810Sstevel@tonic-gate int cachefs_max_threads = CFS_MAX_THREADS;
820Sstevel@tonic-gate ino64_t cachefs_check_fileno = 0;
830Sstevel@tonic-gate struct kmem_cache *cachefs_cache_kmcache = NULL;
840Sstevel@tonic-gate struct kmem_cache *cachefs_req_cache = NULL;
850Sstevel@tonic-gate
860Sstevel@tonic-gate static int
870Sstevel@tonic-gate cachefs_async_populate_reg(struct cachefs_populate_req *, cred_t *,
880Sstevel@tonic-gate vnode_t *, vnode_t *);
890Sstevel@tonic-gate
900Sstevel@tonic-gate /*
910Sstevel@tonic-gate * Cache routines
920Sstevel@tonic-gate */
930Sstevel@tonic-gate
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate * ------------------------------------------------------------------
960Sstevel@tonic-gate *
970Sstevel@tonic-gate * cachefs_cache_create
980Sstevel@tonic-gate *
990Sstevel@tonic-gate * Description:
1000Sstevel@tonic-gate * Creates a cachefscache_t object and initializes it to
1010Sstevel@tonic-gate * be NOCACHE and NOFILL mode.
1020Sstevel@tonic-gate * Arguments:
1030Sstevel@tonic-gate * Returns:
1040Sstevel@tonic-gate * Returns a pointer to the created object or NULL if
1050Sstevel@tonic-gate * threads could not be created.
1060Sstevel@tonic-gate * Preconditions:
1070Sstevel@tonic-gate */
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate cachefscache_t *
cachefs_cache_create(void)1100Sstevel@tonic-gate cachefs_cache_create(void)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate cachefscache_t *cachep;
1130Sstevel@tonic-gate struct cachefs_req *rp;
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate /* allocate zeroed memory for the object */
1160Sstevel@tonic-gate cachep = kmem_cache_alloc(cachefs_cache_kmcache, KM_SLEEP);
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate bzero(cachep, sizeof (*cachep));
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate cv_init(&cachep->c_cwcv, NULL, CV_DEFAULT, NULL);
1210Sstevel@tonic-gate cv_init(&cachep->c_cwhaltcv, NULL, CV_DEFAULT, NULL);
1220Sstevel@tonic-gate mutex_init(&cachep->c_contentslock, NULL, MUTEX_DEFAULT, NULL);
1230Sstevel@tonic-gate mutex_init(&cachep->c_fslistlock, NULL, MUTEX_DEFAULT, NULL);
1240Sstevel@tonic-gate mutex_init(&cachep->c_log_mutex, NULL, MUTEX_DEFAULT, NULL);
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate /* set up the work queue and get the sync thread created */
1270Sstevel@tonic-gate cachefs_workq_init(&cachep->c_workq);
1280Sstevel@tonic-gate cachep->c_workq.wq_keepone = 1;
1290Sstevel@tonic-gate cachep->c_workq.wq_cachep = cachep;
1300Sstevel@tonic-gate rp = kmem_cache_alloc(cachefs_req_cache, KM_SLEEP);
1310Sstevel@tonic-gate rp->cfs_cmd = CFS_NOOP;
1320Sstevel@tonic-gate rp->cfs_cr = kcred;
1330Sstevel@tonic-gate rp->cfs_req_u.cu_fs_sync.cf_cachep = cachep;
1340Sstevel@tonic-gate crhold(rp->cfs_cr);
1350Sstevel@tonic-gate cachefs_addqueue(rp, &cachep->c_workq);
1360Sstevel@tonic-gate cachep->c_flags |= CACHE_NOCACHE | CACHE_NOFILL | CACHE_ALLOC_PENDING;
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate return (cachep);
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate /*
1420Sstevel@tonic-gate * ------------------------------------------------------------------
1430Sstevel@tonic-gate *
1440Sstevel@tonic-gate * cachefs_cache_destroy
1450Sstevel@tonic-gate *
1460Sstevel@tonic-gate * Description:
1470Sstevel@tonic-gate * Destroys the cachefscache_t object.
1480Sstevel@tonic-gate * Arguments:
1490Sstevel@tonic-gate * cachep the cachefscache_t object to destroy
1500Sstevel@tonic-gate * Returns:
1510Sstevel@tonic-gate * Preconditions:
1520Sstevel@tonic-gate * precond(cachep)
1530Sstevel@tonic-gate */
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate void
cachefs_cache_destroy(cachefscache_t * cachep)1560Sstevel@tonic-gate cachefs_cache_destroy(cachefscache_t *cachep)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate int error = 0;
1590Sstevel@tonic-gate #ifdef CFSRLDEBUG
1600Sstevel@tonic-gate uint_t index;
1610Sstevel@tonic-gate #endif /* CFSRLDEBUG */
162*11066Srafael.vanoni@sun.com clock_t wakeup = (60 * hz);
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate /* stop async threads */
1650Sstevel@tonic-gate while (cachep->c_workq.wq_thread_count > 0)
1660Sstevel@tonic-gate (void) cachefs_async_halt(&cachep->c_workq, 1);
1670Sstevel@tonic-gate
1680Sstevel@tonic-gate /* kill off the cachep worker thread */
1690Sstevel@tonic-gate mutex_enter(&cachep->c_contentslock);
1700Sstevel@tonic-gate while (cachep->c_flags & CACHE_CACHEW_THREADRUN) {
1710Sstevel@tonic-gate cachep->c_flags |= CACHE_CACHEW_THREADEXIT;
1720Sstevel@tonic-gate cv_signal(&cachep->c_cwcv);
173*11066Srafael.vanoni@sun.com (void) cv_reltimedwait(&cachep->c_cwhaltcv,
174*11066Srafael.vanoni@sun.com &cachep->c_contentslock, wakeup, TR_CLOCK_TICK);
1750Sstevel@tonic-gate }
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate if ((cachep->c_flags & CACHE_ALLOC_PENDING) == 0) {
1780Sstevel@tonic-gate cachep->c_usage.cu_flags &= ~CUSAGE_ACTIVE;
1790Sstevel@tonic-gate (void) cachefs_cache_rssync(cachep);
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate mutex_exit(&cachep->c_contentslock);
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate /* if there is a cache */
1840Sstevel@tonic-gate if ((cachep->c_flags & CACHE_NOCACHE) == 0) {
1850Sstevel@tonic-gate if ((cachep->c_flags & CACHE_NOFILL) == 0) {
1860Sstevel@tonic-gate #ifdef CFSRLDEBUG
1870Sstevel@tonic-gate /* blow away dangling rl debugging info */
1880Sstevel@tonic-gate mutex_enter(&cachep->c_contentslock);
1890Sstevel@tonic-gate for (index = 0;
1900Sstevel@tonic-gate index <= cachep->c_rlinfo.rl_entries;
1910Sstevel@tonic-gate index++) {
1920Sstevel@tonic-gate rl_entry_t *rlent;
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate error = cachefs_rl_entry_get(cachep, index,
195*11066Srafael.vanoni@sun.com rlent);
1960Sstevel@tonic-gate /*
1970Sstevel@tonic-gate * Since we are destroying the cache,
1980Sstevel@tonic-gate * better to ignore and proceed
1990Sstevel@tonic-gate */
2000Sstevel@tonic-gate if (error)
2010Sstevel@tonic-gate break;
2020Sstevel@tonic-gate cachefs_rl_debug_destroy(rlent);
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate mutex_exit(&cachep->c_contentslock);
2050Sstevel@tonic-gate #endif /* CFSRLDEBUG */
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate /* sync the cache */
2080Sstevel@tonic-gate if (!error)
2090Sstevel@tonic-gate cachefs_cache_sync(cachep);
2100Sstevel@tonic-gate } else {
2110Sstevel@tonic-gate /* get rid of any unused fscache objects */
2120Sstevel@tonic-gate mutex_enter(&cachep->c_fslistlock);
2130Sstevel@tonic-gate fscache_list_gc(cachep);
2140Sstevel@tonic-gate mutex_exit(&cachep->c_fslistlock);
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate ASSERT(cachep->c_fslist == NULL);
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate VN_RELE(cachep->c_resfilevp);
2190Sstevel@tonic-gate VN_RELE(cachep->c_dirvp);
2200Sstevel@tonic-gate VN_RELE(cachep->c_lockvp);
2210Sstevel@tonic-gate VN_RELE(cachep->c_lostfoundvp);
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate if (cachep->c_log_ctl != NULL)
2250Sstevel@tonic-gate cachefs_kmem_free(cachep->c_log_ctl,
2260Sstevel@tonic-gate sizeof (cachefs_log_control_t));
2270Sstevel@tonic-gate if (cachep->c_log != NULL)
2280Sstevel@tonic-gate cachefs_log_destroy_cookie(cachep->c_log);
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate cv_destroy(&cachep->c_cwcv);
2310Sstevel@tonic-gate cv_destroy(&cachep->c_cwhaltcv);
2320Sstevel@tonic-gate mutex_destroy(&cachep->c_contentslock);
2330Sstevel@tonic-gate mutex_destroy(&cachep->c_fslistlock);
2340Sstevel@tonic-gate mutex_destroy(&cachep->c_log_mutex);
2350Sstevel@tonic-gate
2360Sstevel@tonic-gate kmem_cache_free(cachefs_cache_kmcache, cachep);
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate /*
2400Sstevel@tonic-gate * ------------------------------------------------------------------
2410Sstevel@tonic-gate *
2420Sstevel@tonic-gate * cachefs_cache_active_ro
2430Sstevel@tonic-gate *
2440Sstevel@tonic-gate * Description:
2450Sstevel@tonic-gate * Activates the cachefscache_t object for a read-only file system.
2460Sstevel@tonic-gate * Arguments:
2470Sstevel@tonic-gate * cachep the cachefscache_t object to activate
2480Sstevel@tonic-gate * cdvp the vnode of the cache directory
2490Sstevel@tonic-gate * Returns:
2500Sstevel@tonic-gate * Returns 0 for success, !0 if there is a problem with the cache.
2510Sstevel@tonic-gate * Preconditions:
2520Sstevel@tonic-gate * precond(cachep)
2530Sstevel@tonic-gate * precond(cdvp)
2540Sstevel@tonic-gate * precond(cachep->c_flags & CACHE_NOCACHE)
2550Sstevel@tonic-gate */
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate int
cachefs_cache_activate_ro(cachefscache_t * cachep,vnode_t * cdvp)2580Sstevel@tonic-gate cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
2590Sstevel@tonic-gate {
2600Sstevel@tonic-gate cachefs_log_control_t *lc;
2610Sstevel@tonic-gate vnode_t *labelvp = NULL;
2620Sstevel@tonic-gate vnode_t *rifvp = NULL;
2630Sstevel@tonic-gate vnode_t *lockvp = NULL;
2640Sstevel@tonic-gate vnode_t *statevp = NULL;
2650Sstevel@tonic-gate vnode_t *lostfoundvp = NULL;
2660Sstevel@tonic-gate struct vattr *attrp = NULL;
2670Sstevel@tonic-gate int error;
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate ASSERT(cachep->c_flags & CACHE_NOCACHE);
2700Sstevel@tonic-gate mutex_enter(&cachep->c_contentslock);
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP);
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate /* get the mode bits of the cache directory */
2750Sstevel@tonic-gate attrp->va_mask = AT_ALL;
2765331Samw error = VOP_GETATTR(cdvp, attrp, 0, kcred, NULL);
2770Sstevel@tonic-gate if (error)
2780Sstevel@tonic-gate goto out;
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate /* ensure the mode bits are 000 to keep out casual users */
2810Sstevel@tonic-gate if (attrp->va_mode & S_IAMB) {
2820Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: Cache Directory Mode must be 000\n");
2830Sstevel@tonic-gate error = EPERM;
2840Sstevel@tonic-gate goto out;
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate
2870Sstevel@tonic-gate /* Get the lock file */
2880Sstevel@tonic-gate error = VOP_LOOKUP(cdvp, CACHEFS_LOCK_FILE, &lockvp, NULL, 0, NULL,
289*11066Srafael.vanoni@sun.com kcred, NULL, NULL, NULL);
2900Sstevel@tonic-gate if (error) {
2910Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: activate_a: cache corruption"
292*11066Srafael.vanoni@sun.com " run fsck.\n");
2930Sstevel@tonic-gate goto out;
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate /* Get the label file */
2970Sstevel@tonic-gate error = VOP_LOOKUP(cdvp, CACHELABEL_NAME, &labelvp, NULL, 0, NULL,
298*11066Srafael.vanoni@sun.com kcred, NULL, NULL, NULL);
2990Sstevel@tonic-gate if (error) {
3000Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: activate_b: cache corruption"
301*11066Srafael.vanoni@sun.com " run fsck.\n");
3020Sstevel@tonic-gate goto out;
3030Sstevel@tonic-gate }
3040Sstevel@tonic-gate
3050Sstevel@tonic-gate /* read in the label */
3060Sstevel@tonic-gate error = vn_rdwr(UIO_READ, labelvp, (caddr_t)&cachep->c_label,
307*11066Srafael.vanoni@sun.com sizeof (struct cache_label), 0LL, UIO_SYSSPACE,
308*11066Srafael.vanoni@sun.com 0, (rlim64_t)0, kcred, NULL);
3090Sstevel@tonic-gate if (error) {
3100Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: activate_c: cache corruption"
311*11066Srafael.vanoni@sun.com " run fsck.\n");
3120Sstevel@tonic-gate goto out;
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate /* Verify that we can handle the version this cache was created under */
3160Sstevel@tonic-gate if (cachep->c_label.cl_cfsversion != CFSVERSION) {
3170Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: Invalid Cache Version, run fsck\n");
3180Sstevel@tonic-gate error = EINVAL;
3190Sstevel@tonic-gate goto out;
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate /* Open the resource file */
3235331Samw error = VOP_LOOKUP(cdvp, RESOURCE_NAME, &rifvp, NULL, 0, NULL, kcred,
3245331Samw NULL, NULL, NULL);
3250Sstevel@tonic-gate if (error) {
3260Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: activate_d: cache corruption"
327*11066Srafael.vanoni@sun.com " run fsck.\n");
3280Sstevel@tonic-gate goto out;
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate /* Read the usage struct for this cache */
3320Sstevel@tonic-gate error = vn_rdwr(UIO_READ, rifvp, (caddr_t)&cachep->c_usage,
333*11066Srafael.vanoni@sun.com sizeof (struct cache_usage), 0LL, UIO_SYSSPACE, 0,
334*11066Srafael.vanoni@sun.com (rlim64_t)0, kcred, NULL);
3350Sstevel@tonic-gate if (error) {
3360Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: activate_e: cache corruption"
337*11066Srafael.vanoni@sun.com " run fsck.\n");
3380Sstevel@tonic-gate goto out;
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate if (cachep->c_usage.cu_flags & CUSAGE_ACTIVE) {
3420Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: cache not clean. Run fsck\n");
3430Sstevel@tonic-gate /* ENOSPC is what UFS uses for clean flag check */
3440Sstevel@tonic-gate error = ENOSPC;
3450Sstevel@tonic-gate goto out;
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate /* Read the rlinfo for this cache */
3490Sstevel@tonic-gate error = vn_rdwr(UIO_READ, rifvp, (caddr_t)&cachep->c_rlinfo,
350*11066Srafael.vanoni@sun.com sizeof (cachefs_rl_info_t), (offset_t)sizeof (struct cache_usage),
351*11066Srafael.vanoni@sun.com UIO_SYSSPACE, 0, 0, kcred, NULL);
3520Sstevel@tonic-gate if (error) {
3530Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: activate_f: cache corruption"
354*11066Srafael.vanoni@sun.com " run fsck.\n");
3550Sstevel@tonic-gate goto out;
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate /* Open the lost+found directory */
3590Sstevel@tonic-gate error = VOP_LOOKUP(cdvp, CACHEFS_LOSTFOUND_NAME, &lostfoundvp,
3605331Samw NULL, 0, NULL, kcred, NULL, NULL, NULL);
3610Sstevel@tonic-gate if (error) {
3620Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: activate_g: cache corruption"
363*11066Srafael.vanoni@sun.com " run fsck.\n");
3640Sstevel@tonic-gate goto out;
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate VN_HOLD(rifvp);
3680Sstevel@tonic-gate VN_HOLD(cdvp);
3690Sstevel@tonic-gate VN_HOLD(lockvp);
3700Sstevel@tonic-gate VN_HOLD(lostfoundvp);
3710Sstevel@tonic-gate cachep->c_resfilevp = rifvp;
3720Sstevel@tonic-gate cachep->c_dirvp = cdvp;
3730Sstevel@tonic-gate cachep->c_lockvp = lockvp;
3740Sstevel@tonic-gate cachep->c_lostfoundvp = lostfoundvp;
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate /* get the cachep worker thread created */
3770Sstevel@tonic-gate cachep->c_flags |= CACHE_CACHEW_THREADRUN;
3780Sstevel@tonic-gate (void) thread_create(NULL, 0, cachefs_cachep_worker_thread,
3790Sstevel@tonic-gate cachep, 0, &p0, TS_RUN, minclsyspri);
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate /* allocate the `logging control' field */
3820Sstevel@tonic-gate mutex_enter(&cachep->c_log_mutex);
3830Sstevel@tonic-gate cachep->c_log_ctl =
3840Sstevel@tonic-gate cachefs_kmem_zalloc(sizeof (cachefs_log_control_t), KM_SLEEP);
3850Sstevel@tonic-gate lc = (cachefs_log_control_t *)cachep->c_log_ctl;
3860Sstevel@tonic-gate
3870Sstevel@tonic-gate /* if the LOG_STATUS_NAME file exists, read it in and set up logging */
3880Sstevel@tonic-gate error = VOP_LOOKUP(cachep->c_dirvp, LOG_STATUS_NAME, &statevp,
3895331Samw NULL, 0, NULL, kcred, NULL, NULL, NULL);
3900Sstevel@tonic-gate if (error == 0) {
3910Sstevel@tonic-gate int vnrw_error;
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate vnrw_error = vn_rdwr(UIO_READ, statevp, (caddr_t)lc,
3940Sstevel@tonic-gate sizeof (*lc), 0LL, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY,
3950Sstevel@tonic-gate kcred, NULL);
3960Sstevel@tonic-gate VN_RELE(statevp);
3970Sstevel@tonic-gate
3980Sstevel@tonic-gate if (vnrw_error == 0) {
3990Sstevel@tonic-gate if ((cachep->c_log = cachefs_log_create_cookie(lc))
4000Sstevel@tonic-gate == NULL)
4010Sstevel@tonic-gate cachefs_log_error(cachep, ENOMEM, 0);
4020Sstevel@tonic-gate else if ((lc->lc_magic != CACHEFS_LOG_MAGIC) ||
4030Sstevel@tonic-gate (lc->lc_path[0] != '/') ||
4040Sstevel@tonic-gate (cachefs_log_logfile_open(cachep,
4050Sstevel@tonic-gate lc->lc_path) != 0))
4060Sstevel@tonic-gate cachefs_log_error(cachep, EINVAL, 0);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate } else {
4090Sstevel@tonic-gate error = 0;
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate lc->lc_magic = CACHEFS_LOG_MAGIC;
4120Sstevel@tonic-gate lc->lc_cachep = (uint64_t)(uintptr_t)cachep;
4130Sstevel@tonic-gate mutex_exit(&cachep->c_log_mutex);
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate out:
4160Sstevel@tonic-gate if (error == 0) {
4170Sstevel@tonic-gate cachep->c_flags &= ~(CACHE_NOCACHE | CACHE_ALLOC_PENDING);
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate if (attrp)
4200Sstevel@tonic-gate cachefs_kmem_free(attrp, sizeof (struct vattr));
4210Sstevel@tonic-gate if (labelvp != NULL)
4220Sstevel@tonic-gate VN_RELE(labelvp);
4230Sstevel@tonic-gate if (rifvp != NULL)
4240Sstevel@tonic-gate VN_RELE(rifvp);
4250Sstevel@tonic-gate if (lockvp)
4260Sstevel@tonic-gate VN_RELE(lockvp);
4270Sstevel@tonic-gate if (lostfoundvp)
4280Sstevel@tonic-gate VN_RELE(lostfoundvp);
4290Sstevel@tonic-gate
4300Sstevel@tonic-gate mutex_exit(&cachep->c_contentslock);
4310Sstevel@tonic-gate return (error);
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate int
cachefs_stop_cache(cnode_t * cp)4350Sstevel@tonic-gate cachefs_stop_cache(cnode_t *cp)
4360Sstevel@tonic-gate {
4370Sstevel@tonic-gate fscache_t *fscp = C_TO_FSCACHE(cp);
4380Sstevel@tonic-gate cachefscache_t *cachep = fscp->fs_cache;
4390Sstevel@tonic-gate filegrp_t *fgp;
4400Sstevel@tonic-gate int i;
4410Sstevel@tonic-gate int error = 0;
442*11066Srafael.vanoni@sun.com clock_t wakeup = (60 * hz);
4430Sstevel@tonic-gate
4440Sstevel@tonic-gate /* XXX verify lock-ordering for this function */
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate mutex_enter(&cachep->c_contentslock);
4470Sstevel@tonic-gate
4480Sstevel@tonic-gate /*
4490Sstevel@tonic-gate * no work if we're already in nocache mode. hopefully this
4500Sstevel@tonic-gate * will be the usual case.
4510Sstevel@tonic-gate */
4520Sstevel@tonic-gate
4530Sstevel@tonic-gate if (cachep->c_flags & CACHE_NOCACHE) {
4540Sstevel@tonic-gate mutex_exit(&cachep->c_contentslock);
4550Sstevel@tonic-gate return (0);
4560Sstevel@tonic-gate }
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate if ((cachep->c_flags & CACHE_NOFILL) == 0) {
4590Sstevel@tonic-gate mutex_exit(&cachep->c_contentslock);
4600Sstevel@tonic-gate return (EINVAL);
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate mutex_exit(&cachep->c_contentslock);
4640Sstevel@tonic-gate
4650Sstevel@tonic-gate /* We are already not caching if nfsv4 */
4660Sstevel@tonic-gate if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
4670Sstevel@tonic-gate return (0);
4680Sstevel@tonic-gate }
4690Sstevel@tonic-gate
4700Sstevel@tonic-gate #ifdef CFSDEBUG
4710Sstevel@tonic-gate mutex_enter(&cachep->c_fslistlock);
4720Sstevel@tonic-gate ASSERT(fscp == cachep->c_fslist);
4730Sstevel@tonic-gate ASSERT(fscp->fs_next == NULL);
4740Sstevel@tonic-gate mutex_exit(&cachep->c_fslistlock);
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate printf("cachefs_stop_cache: resetting CACHE_NOCACHE\n");
4770Sstevel@tonic-gate #endif
4780Sstevel@tonic-gate
4790Sstevel@tonic-gate /* XXX should i worry about disconnected during boot? */
4800Sstevel@tonic-gate error = cachefs_cd_access(fscp, 1, 1);
4810Sstevel@tonic-gate if (error)
4820Sstevel@tonic-gate goto out;
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate error = cachefs_async_halt(&fscp->fs_workq, 1);
4850Sstevel@tonic-gate ASSERT(error == 0);
4860Sstevel@tonic-gate error = cachefs_async_halt(&cachep->c_workq, 1);
4870Sstevel@tonic-gate ASSERT(error == 0);
4880Sstevel@tonic-gate /* sigh -- best to keep going if async_halt failed. */
4890Sstevel@tonic-gate error = 0;
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate /* XXX current order: cnode, fgp, fscp, cache. okay? */
4920Sstevel@tonic-gate
4930Sstevel@tonic-gate cachefs_cnode_traverse(fscp, cachefs_cnode_disable_caching);
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate for (i = 0; i < CFS_FS_FGP_BUCKET_SIZE; i++) {
4960Sstevel@tonic-gate for (fgp = fscp->fs_filegrp[i]; fgp != NULL;
497*11066Srafael.vanoni@sun.com fgp = fgp->fg_next) {
4980Sstevel@tonic-gate mutex_enter(&fgp->fg_mutex);
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate ASSERT((fgp->fg_flags &
5010Sstevel@tonic-gate (CFS_FG_WRITE | CFS_FG_UPDATED)) == 0);
5020Sstevel@tonic-gate fgp->fg_flags |=
5030Sstevel@tonic-gate CFS_FG_ALLOC_FILE |
5040Sstevel@tonic-gate CFS_FG_ALLOC_ATTR;
5050Sstevel@tonic-gate fgp->fg_flags &= ~CFS_FG_READ;
5060Sstevel@tonic-gate
5070Sstevel@tonic-gate if (fgp->fg_dirvp) {
5080Sstevel@tonic-gate fgp->fg_flags |= CFS_FG_ALLOC_FILE;
5090Sstevel@tonic-gate VN_RELE(fgp->fg_dirvp);
5100Sstevel@tonic-gate fgp->fg_dirvp = NULL;
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate if (fgp->fg_attrvp) {
5130Sstevel@tonic-gate fgp->fg_flags |= CFS_FG_ALLOC_ATTR;
5140Sstevel@tonic-gate VN_RELE(fgp->fg_attrvp);
5150Sstevel@tonic-gate fgp->fg_attrvp = NULL;
5160Sstevel@tonic-gate }
5170Sstevel@tonic-gate
5180Sstevel@tonic-gate mutex_exit(&fgp->fg_mutex);
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate
5220Sstevel@tonic-gate mutex_enter(&fscp->fs_fslock);
5230Sstevel@tonic-gate ASSERT((fscp->fs_flags & (CFS_FS_WRITE)) == 0);
5240Sstevel@tonic-gate fscp->fs_flags &= ~(CFS_FS_READ | CFS_FS_DIRTYINFO);
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate if (fscp->fs_fscdirvp) {
5270Sstevel@tonic-gate VN_RELE(fscp->fs_fscdirvp);
5280Sstevel@tonic-gate fscp->fs_fscdirvp = NULL;
5290Sstevel@tonic-gate }
5300Sstevel@tonic-gate if (fscp->fs_fsattrdir) {
5310Sstevel@tonic-gate VN_RELE(fscp->fs_fsattrdir);
5320Sstevel@tonic-gate fscp->fs_fsattrdir = NULL;
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate if (fscp->fs_infovp) {
5350Sstevel@tonic-gate VN_RELE(fscp->fs_infovp);
5360Sstevel@tonic-gate fscp->fs_infovp = NULL;
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate /* XXX dlog stuff? */
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate mutex_exit(&fscp->fs_fslock);
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate /*
5430Sstevel@tonic-gate * release resources grabbed in cachefs_cache_activate_ro
5440Sstevel@tonic-gate */
5450Sstevel@tonic-gate
5460Sstevel@tonic-gate mutex_enter(&cachep->c_contentslock);
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate /* kill off the cachep worker thread */
5490Sstevel@tonic-gate while (cachep->c_flags & CACHE_CACHEW_THREADRUN) {
5500Sstevel@tonic-gate cachep->c_flags |= CACHE_CACHEW_THREADEXIT;
5510Sstevel@tonic-gate cv_signal(&cachep->c_cwcv);
552*11066Srafael.vanoni@sun.com (void) cv_reltimedwait(&cachep->c_cwhaltcv,
553*11066Srafael.vanoni@sun.com &cachep->c_contentslock, wakeup, TR_CLOCK_TICK);
5540Sstevel@tonic-gate }
5550Sstevel@tonic-gate
5560Sstevel@tonic-gate if (cachep->c_resfilevp) {
5570Sstevel@tonic-gate VN_RELE(cachep->c_resfilevp);
5580Sstevel@tonic-gate cachep->c_resfilevp = NULL;
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate if (cachep->c_dirvp) {
5610Sstevel@tonic-gate VN_RELE(cachep->c_dirvp);
5620Sstevel@tonic-gate cachep->c_dirvp = NULL;
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate if (cachep->c_lockvp) {
5650Sstevel@tonic-gate VN_RELE(cachep->c_lockvp);
5660Sstevel@tonic-gate cachep->c_lockvp = NULL;
5670Sstevel@tonic-gate }
5680Sstevel@tonic-gate if (cachep->c_lostfoundvp) {
5690Sstevel@tonic-gate VN_RELE(cachep->c_lostfoundvp);
5700Sstevel@tonic-gate cachep->c_lostfoundvp = NULL;
5710Sstevel@tonic-gate }
5720Sstevel@tonic-gate
5730Sstevel@tonic-gate mutex_enter(&cachep->c_log_mutex);
5740Sstevel@tonic-gate if (cachep->c_log_ctl) {
5750Sstevel@tonic-gate cachefs_kmem_free(cachep->c_log_ctl,
5760Sstevel@tonic-gate sizeof (cachefs_log_control_t));
5770Sstevel@tonic-gate cachep->c_log_ctl = NULL;
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate if (cachep->c_log) {
5800Sstevel@tonic-gate cachefs_log_destroy_cookie(cachep->c_log);
5810Sstevel@tonic-gate cachep->c_log = NULL;
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate mutex_exit(&cachep->c_log_mutex);
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate /* XXX do what mountroot_init does when ! foundcache */
5860Sstevel@tonic-gate
5870Sstevel@tonic-gate cachep->c_flags |= CACHE_NOCACHE;
5880Sstevel@tonic-gate mutex_exit(&cachep->c_contentslock);
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate /* XXX should i release this here? */
5910Sstevel@tonic-gate cachefs_cd_release(fscp);
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate out:
5940Sstevel@tonic-gate
5950Sstevel@tonic-gate return (error);
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate
5980Sstevel@tonic-gate /*
5990Sstevel@tonic-gate * ------------------------------------------------------------------
6000Sstevel@tonic-gate *
6010Sstevel@tonic-gate * cachefs_cache_active_rw
6020Sstevel@tonic-gate *
6030Sstevel@tonic-gate * Description:
6040Sstevel@tonic-gate * Activates the cachefscache_t object for a read-write file system.
6050Sstevel@tonic-gate * Arguments:
6060Sstevel@tonic-gate * cachep the cachefscache_t object to activate
6070Sstevel@tonic-gate * Returns:
6080Sstevel@tonic-gate * Preconditions:
6090Sstevel@tonic-gate * precond(cachep)
6100Sstevel@tonic-gate * precond((cachep->c_flags & CACHE_NOCACHE) == 0)
6110Sstevel@tonic-gate * precond(cachep->c_flags & CACHE_NOFILL)
6120Sstevel@tonic-gate */
6130Sstevel@tonic-gate
6140Sstevel@tonic-gate void
cachefs_cache_activate_rw(cachefscache_t * cachep)6150Sstevel@tonic-gate cachefs_cache_activate_rw(cachefscache_t *cachep)
6160Sstevel@tonic-gate {
6170Sstevel@tonic-gate cachefs_rl_listhead_t *lhp;
6180Sstevel@tonic-gate
6190Sstevel@tonic-gate ASSERT((cachep->c_flags & CACHE_NOCACHE) == 0);
6200Sstevel@tonic-gate ASSERT(cachep->c_flags & CACHE_NOFILL);
6210Sstevel@tonic-gate
6220Sstevel@tonic-gate mutex_enter(&cachep->c_contentslock);
6230Sstevel@tonic-gate cachep->c_flags &= ~CACHE_NOFILL;
6240Sstevel@tonic-gate
6250Sstevel@tonic-gate /* move the active list to the rl list */
6260Sstevel@tonic-gate cachefs_rl_cleanup(cachep);
6270Sstevel@tonic-gate
6280Sstevel@tonic-gate lhp = &cachep->c_rlinfo.rl_items[
6290Sstevel@tonic-gate CACHEFS_RL_INDEX(CACHEFS_RL_PACKED_PENDING)];
6300Sstevel@tonic-gate if (lhp->rli_itemcnt != 0)
6310Sstevel@tonic-gate cachep->c_flags |= CACHE_PACKED_PENDING;
6320Sstevel@tonic-gate cachefs_cache_dirty(cachep, 0);
6330Sstevel@tonic-gate mutex_exit(&cachep->c_contentslock);
6340Sstevel@tonic-gate }
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate /*
6370Sstevel@tonic-gate * ------------------------------------------------------------------
6380Sstevel@tonic-gate *
6390Sstevel@tonic-gate * cachefs_cache_dirty
6400Sstevel@tonic-gate *
6410Sstevel@tonic-gate * Description:
6420Sstevel@tonic-gate * Marks the cache as dirty (active).
6430Sstevel@tonic-gate * Arguments:
6440Sstevel@tonic-gate * cachep the cachefscache_t to mark as dirty
6450Sstevel@tonic-gate * lockit 1 means grab contents lock, 0 means caller grabbed it
6460Sstevel@tonic-gate * Returns:
6470Sstevel@tonic-gate * Preconditions:
6480Sstevel@tonic-gate * precond(cachep)
6490Sstevel@tonic-gate * precond(cache is in rw mode)
6500Sstevel@tonic-gate */
6510Sstevel@tonic-gate
6520Sstevel@tonic-gate void
cachefs_cache_dirty(struct cachefscache * cachep,int lockit)6530Sstevel@tonic-gate cachefs_cache_dirty(struct cachefscache *cachep, int lockit)
6540Sstevel@tonic-gate {
6550Sstevel@tonic-gate int error;
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate ASSERT((cachep->c_flags & (CACHE_NOCACHE | CACHE_NOFILL)) == 0);
6580Sstevel@tonic-gate
6590Sstevel@tonic-gate if (lockit) {
6600Sstevel@tonic-gate mutex_enter(&cachep->c_contentslock);
6610Sstevel@tonic-gate } else {
6620Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cachep->c_contentslock));
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate if (cachep->c_flags & CACHE_DIRTY) {
6650Sstevel@tonic-gate ASSERT(cachep->c_usage.cu_flags & CUSAGE_ACTIVE);
6660Sstevel@tonic-gate } else {
6670Sstevel@tonic-gate /*
6680Sstevel@tonic-gate * turn on the "cache active" (dirty) flag and write it
6690Sstevel@tonic-gate * synchronously to disk
6700Sstevel@tonic-gate */
6710Sstevel@tonic-gate cachep->c_flags |= CACHE_DIRTY;
6720Sstevel@tonic-gate cachep->c_usage.cu_flags |= CUSAGE_ACTIVE;
6730Sstevel@tonic-gate if (error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp,
6740Sstevel@tonic-gate (caddr_t)&cachep->c_usage, sizeof (struct cache_usage),
6750Sstevel@tonic-gate 0LL, UIO_SYSSPACE, FSYNC, (rlim64_t)RLIM_INFINITY,
676*11066Srafael.vanoni@sun.com kcred, NULL)) {
6770Sstevel@tonic-gate cmn_err(CE_WARN,
6780Sstevel@tonic-gate "cachefs: clean flag write error: %d\n", error);
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate if (lockit)
6830Sstevel@tonic-gate mutex_exit(&cachep->c_contentslock);
6840Sstevel@tonic-gate }
6850Sstevel@tonic-gate
6860Sstevel@tonic-gate /*
6870Sstevel@tonic-gate * ------------------------------------------------------------------
6880Sstevel@tonic-gate *
6890Sstevel@tonic-gate * cachefs_cache_rssync
6900Sstevel@tonic-gate *
6910Sstevel@tonic-gate * Description:
6920Sstevel@tonic-gate * Syncs out the resource file for the cachefscache_t object.
6930Sstevel@tonic-gate * Arguments:
6940Sstevel@tonic-gate * cachep the cachefscache_t object to operate on
6950Sstevel@tonic-gate * Returns:
6960Sstevel@tonic-gate * Returns 0 for success, !0 on an error writing data.
6970Sstevel@tonic-gate * Preconditions:
6980Sstevel@tonic-gate * precond(cachep)
6990Sstevel@tonic-gate * precond(cache is in rw mode)
7000Sstevel@tonic-gate */
7010Sstevel@tonic-gate
7020Sstevel@tonic-gate int
cachefs_cache_rssync(struct cachefscache * cachep)7030Sstevel@tonic-gate cachefs_cache_rssync(struct cachefscache *cachep)
7040Sstevel@tonic-gate {
7050Sstevel@tonic-gate int error;
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate ASSERT((cachep->c_flags & (CACHE_NOCACHE | CACHE_NOFILL |
7080Sstevel@tonic-gate CACHE_ALLOC_PENDING)) == 0);
7090Sstevel@tonic-gate
7100Sstevel@tonic-gate if (cachep->c_rl_entries != NULL) {
7110Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp,
7120Sstevel@tonic-gate (caddr_t)cachep->c_rl_entries, MAXBSIZE,
7130Sstevel@tonic-gate (offset_t)((cachep->c_rl_window + 1) * MAXBSIZE),
7140Sstevel@tonic-gate UIO_SYSSPACE, FSYNC, RLIM_INFINITY, kcred, NULL);
7150Sstevel@tonic-gate if (error)
716*11066Srafael.vanoni@sun.com cmn_err(CE_WARN,
717*11066Srafael.vanoni@sun.com "cachefs: Can't Write rl entries Info\n");
7180Sstevel@tonic-gate cachefs_kmem_free(cachep->c_rl_entries, MAXBSIZE);
7190Sstevel@tonic-gate cachep->c_rl_entries = NULL;
7200Sstevel@tonic-gate }
7210Sstevel@tonic-gate
7220Sstevel@tonic-gate /* write the usage struct for this cache */
7230Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp,
724*11066Srafael.vanoni@sun.com (caddr_t)&cachep->c_usage, sizeof (struct cache_usage),
725*11066Srafael.vanoni@sun.com 0LL, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY, kcred, NULL);
7260Sstevel@tonic-gate if (error) {
7270Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: Can't Write Cache Usage Info\n");
7280Sstevel@tonic-gate }
7290Sstevel@tonic-gate
7300Sstevel@tonic-gate /* write the rlinfo for this cache */
7310Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp,
732*11066Srafael.vanoni@sun.com (caddr_t)&cachep->c_rlinfo, sizeof (cachefs_rl_info_t),
733*11066Srafael.vanoni@sun.com (offset_t)sizeof (struct cache_usage), UIO_SYSSPACE,
734*11066Srafael.vanoni@sun.com 0, (rlim64_t)RLIM_INFINITY, kcred, NULL);
7350Sstevel@tonic-gate if (error) {
7360Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: Can't Write Cache RL Info\n");
7370Sstevel@tonic-gate }
7385331Samw error = VOP_FSYNC(cachep->c_resfilevp, FSYNC, kcred, NULL);
7390Sstevel@tonic-gate return (error);
7400Sstevel@tonic-gate }
7410Sstevel@tonic-gate
7420Sstevel@tonic-gate /*
7430Sstevel@tonic-gate * ------------------------------------------------------------------
7440Sstevel@tonic-gate *
7450Sstevel@tonic-gate * cachefs_cache_sync
7460Sstevel@tonic-gate *
7470Sstevel@tonic-gate * Description:
7480Sstevel@tonic-gate * Sync a cache which includes all of its fscaches.
7490Sstevel@tonic-gate * Arguments:
7500Sstevel@tonic-gate * cachep the cachefscache_t object to sync
7510Sstevel@tonic-gate * Returns:
7520Sstevel@tonic-gate * Preconditions:
7530Sstevel@tonic-gate * precond(cachep)
7540Sstevel@tonic-gate * precond(cache is in rw mode)
7550Sstevel@tonic-gate */
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate void
cachefs_cache_sync(struct cachefscache * cachep)7580Sstevel@tonic-gate cachefs_cache_sync(struct cachefscache *cachep)
7590Sstevel@tonic-gate {
7600Sstevel@tonic-gate struct fscache *fscp;
7610Sstevel@tonic-gate struct fscache **syncfsc;
7620Sstevel@tonic-gate int nfscs, fscidx;
7630Sstevel@tonic-gate int try;
7640Sstevel@tonic-gate int done;
7650Sstevel@tonic-gate
7660Sstevel@tonic-gate if (cachep->c_flags & (CACHE_NOCACHE | CACHE_NOFILL))
7670Sstevel@tonic-gate return;
7680Sstevel@tonic-gate
7690Sstevel@tonic-gate done = 0;
7700Sstevel@tonic-gate for (try = 0; (try < 2) && !done; try++) {
7710Sstevel@tonic-gate
7720Sstevel@tonic-gate nfscs = 0;
7730Sstevel@tonic-gate
7740Sstevel@tonic-gate /*
7750Sstevel@tonic-gate * here we turn off the cache-wide DIRTY flag. If it's still
7760Sstevel@tonic-gate * off when the sync completes we can write the clean flag to
7770Sstevel@tonic-gate * disk telling fsck it has no work to do.
7780Sstevel@tonic-gate */
7790Sstevel@tonic-gate #ifdef CFSCLEANFLAG
7800Sstevel@tonic-gate mutex_enter(&cachep->c_contentslock);
7810Sstevel@tonic-gate cachep->c_flags &= ~CACHE_DIRTY;
7820Sstevel@tonic-gate mutex_exit(&cachep->c_contentslock);
7830Sstevel@tonic-gate #endif /* CFSCLEANFLAG */
7840Sstevel@tonic-gate
7850Sstevel@tonic-gate cachefs_log_process_queue(cachep, 1);
7860Sstevel@tonic-gate
7870Sstevel@tonic-gate mutex_enter(&cachep->c_fslistlock);
7880Sstevel@tonic-gate syncfsc = cachefs_kmem_alloc(
7890Sstevel@tonic-gate cachep->c_refcnt * sizeof (struct fscache *), KM_SLEEP);
7900Sstevel@tonic-gate for (fscp = cachep->c_fslist; fscp; fscp = fscp->fs_next) {
7910Sstevel@tonic-gate fscache_hold(fscp);
7920Sstevel@tonic-gate ASSERT(nfscs < cachep->c_refcnt);
7930Sstevel@tonic-gate syncfsc[nfscs++] = fscp;
7940Sstevel@tonic-gate }
7950Sstevel@tonic-gate ASSERT(nfscs == cachep->c_refcnt);
7960Sstevel@tonic-gate mutex_exit(&cachep->c_fslistlock);
7970Sstevel@tonic-gate for (fscidx = 0; fscidx < nfscs; fscidx++) {
7980Sstevel@tonic-gate fscp = syncfsc[fscidx];
7990Sstevel@tonic-gate fscache_sync(fscp);
8000Sstevel@tonic-gate fscache_rele(fscp);
8010Sstevel@tonic-gate }
8020Sstevel@tonic-gate
8030Sstevel@tonic-gate /* get rid of any unused fscache objects */
8040Sstevel@tonic-gate mutex_enter(&cachep->c_fslistlock);
8050Sstevel@tonic-gate fscache_list_gc(cachep);
8060Sstevel@tonic-gate mutex_exit(&cachep->c_fslistlock);
8070Sstevel@tonic-gate
8080Sstevel@tonic-gate /*
8090Sstevel@tonic-gate * here we check the cache-wide DIRTY flag.
8100Sstevel@tonic-gate * If it's off,
8110Sstevel@tonic-gate * we can write the clean flag to disk.
8120Sstevel@tonic-gate */
8130Sstevel@tonic-gate #ifdef CFSCLEANFLAG
8140Sstevel@tonic-gate mutex_enter(&cachep->c_contentslock);
8150Sstevel@tonic-gate if ((cachep->c_flags & CACHE_DIRTY) == 0) {
8160Sstevel@tonic-gate if (cachep->c_usage.cu_flags & CUSAGE_ACTIVE) {
8170Sstevel@tonic-gate cachep->c_usage.cu_flags &= ~CUSAGE_ACTIVE;
8180Sstevel@tonic-gate if (cachefs_cache_rssync(cachep) == 0) {
8190Sstevel@tonic-gate done = 1;
8200Sstevel@tonic-gate } else {
8210Sstevel@tonic-gate cachep->c_usage.cu_flags |=
822*11066Srafael.vanoni@sun.com CUSAGE_ACTIVE;
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate } else {
8250Sstevel@tonic-gate done = 1;
8260Sstevel@tonic-gate }
8270Sstevel@tonic-gate }
8280Sstevel@tonic-gate mutex_exit(&cachep->c_contentslock);
8290Sstevel@tonic-gate #else /* CFSCLEANFLAG */
8300Sstevel@tonic-gate mutex_enter(&cachep->c_contentslock);
8310Sstevel@tonic-gate (void) cachefs_cache_rssync(cachep);
8320Sstevel@tonic-gate mutex_exit(&cachep->c_contentslock);
8330Sstevel@tonic-gate done = 1;
8340Sstevel@tonic-gate #endif /* CFSCLEANFLAG */
8350Sstevel@tonic-gate cachefs_kmem_free(syncfsc, nfscs * sizeof (struct fscache *));
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate }
8380Sstevel@tonic-gate
8390Sstevel@tonic-gate /*
8400Sstevel@tonic-gate * ------------------------------------------------------------------
8410Sstevel@tonic-gate *
8420Sstevel@tonic-gate * cachefs_cache_unique
8430Sstevel@tonic-gate *
8440Sstevel@tonic-gate * Description:
8450Sstevel@tonic-gate * Arguments:
8460Sstevel@tonic-gate * Returns:
8470Sstevel@tonic-gate * Returns a unique number.
8480Sstevel@tonic-gate * Preconditions:
8490Sstevel@tonic-gate * precond(cachep)
8500Sstevel@tonic-gate */
8510Sstevel@tonic-gate
8520Sstevel@tonic-gate uint_t
cachefs_cache_unique(cachefscache_t * cachep)8530Sstevel@tonic-gate cachefs_cache_unique(cachefscache_t *cachep)
8540Sstevel@tonic-gate {
8550Sstevel@tonic-gate uint_t unique = 0;
8560Sstevel@tonic-gate int error = 0;
8570Sstevel@tonic-gate
8580Sstevel@tonic-gate mutex_enter(&cachep->c_contentslock);
8590Sstevel@tonic-gate if (cachep->c_usage.cu_flags & CUSAGE_NEED_ADJUST ||
860*11066Srafael.vanoni@sun.com ++(cachep->c_unique) == 0) {
8610Sstevel@tonic-gate cachep->c_usage.cu_unique++;
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate if (cachep->c_unique == 0)
8640Sstevel@tonic-gate cachep->c_unique = 1;
8650Sstevel@tonic-gate cachep->c_flags &= ~CUSAGE_NEED_ADJUST;
8660Sstevel@tonic-gate error = cachefs_cache_rssync(cachep);
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate if (error == 0)
8690Sstevel@tonic-gate unique = (cachep->c_usage.cu_unique << 16) + cachep->c_unique;
8700Sstevel@tonic-gate mutex_exit(&cachep->c_contentslock);
8710Sstevel@tonic-gate return (unique);
8720Sstevel@tonic-gate }
8730Sstevel@tonic-gate
8740Sstevel@tonic-gate /*
8750Sstevel@tonic-gate * Called from c_getfrontfile. Shouldn't be called from anywhere else !
8760Sstevel@tonic-gate */
8770Sstevel@tonic-gate static int
cachefs_createfrontfile(cnode_t * cp,struct filegrp * fgp)8780Sstevel@tonic-gate cachefs_createfrontfile(cnode_t *cp, struct filegrp *fgp)
8790Sstevel@tonic-gate {
8800Sstevel@tonic-gate char name[CFS_FRONTFILE_NAME_SIZE];
8810Sstevel@tonic-gate struct vattr *attrp = NULL;
8820Sstevel@tonic-gate int error = 0;
8830Sstevel@tonic-gate int mode;
8840Sstevel@tonic-gate int alloc = 0;
8850Sstevel@tonic-gate int freefile = 0;
8860Sstevel@tonic-gate int ffrele = 0;
8870Sstevel@tonic-gate int rlfree = 0;
8880Sstevel@tonic-gate rl_entry_t rl_ent;
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate #ifdef CFSDEBUG
8910Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_FRONT)
8920Sstevel@tonic-gate printf("c_createfrontfile: ENTER cp %p fgp %p\n",
893*11066Srafael.vanoni@sun.com (void *)cp, (void *)fgp);
8940Sstevel@tonic-gate #endif
8950Sstevel@tonic-gate
8960Sstevel@tonic-gate ASSERT(cp->c_frontvp == NULL);
8970Sstevel@tonic-gate ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
8980Sstevel@tonic-gate
8990Sstevel@tonic-gate /* quit if we cannot write to the filegrp */
9000Sstevel@tonic-gate if ((fgp->fg_flags & CFS_FG_WRITE) == 0) {
9010Sstevel@tonic-gate error = ENOENT;
9020Sstevel@tonic-gate goto out;
9030Sstevel@tonic-gate }
9040Sstevel@tonic-gate
9050Sstevel@tonic-gate /* find or create the filegrp attrcache file if necessary */
9060Sstevel@tonic-gate if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
9070Sstevel@tonic-gate error = filegrp_allocattr(fgp);
9080Sstevel@tonic-gate if (error)
9090Sstevel@tonic-gate goto out;
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate
9120Sstevel@tonic-gate make_ascii_name(&cp->c_id, name);
9130Sstevel@tonic-gate
9140Sstevel@tonic-gate /* set up attributes for the front file we want to create */
9150Sstevel@tonic-gate attrp = cachefs_kmem_zalloc(sizeof (struct vattr), KM_SLEEP);
9160Sstevel@tonic-gate alloc++;
9170Sstevel@tonic-gate attrp->va_mode = S_IFREG | 0666;
9180Sstevel@tonic-gate mode = 0666;
9190Sstevel@tonic-gate attrp->va_uid = 0;
9200Sstevel@tonic-gate attrp->va_gid = 0;
9210Sstevel@tonic-gate attrp->va_type = VREG;
9220Sstevel@tonic-gate attrp->va_size = 0;
9230Sstevel@tonic-gate attrp->va_mask = AT_SIZE | AT_TYPE | AT_MODE | AT_UID | AT_GID;
9240Sstevel@tonic-gate
9250Sstevel@tonic-gate /* get a file from the resource counts */
9260Sstevel@tonic-gate error = cachefs_allocfile(fgp->fg_fscp->fs_cache);
9270Sstevel@tonic-gate if (error) {
9280Sstevel@tonic-gate error = EINVAL;
9290Sstevel@tonic-gate goto out;
9300Sstevel@tonic-gate }
9310Sstevel@tonic-gate freefile++;
9320Sstevel@tonic-gate
9330Sstevel@tonic-gate /* create the metadata slot if necessary */
9340Sstevel@tonic-gate if (cp->c_flags & CN_ALLOC_PENDING) {
9350Sstevel@tonic-gate error = filegrp_create_metadata(fgp, &cp->c_metadata,
9360Sstevel@tonic-gate &cp->c_id);
9370Sstevel@tonic-gate if (error) {
9380Sstevel@tonic-gate error = EINVAL;
9390Sstevel@tonic-gate goto out;
9400Sstevel@tonic-gate }
9410Sstevel@tonic-gate cp->c_flags &= ~CN_ALLOC_PENDING;
9420Sstevel@tonic-gate cp->c_flags |= CN_UPDATED;
9430Sstevel@tonic-gate }
9440Sstevel@tonic-gate
9450Sstevel@tonic-gate /* get an rl entry if necessary */
9460Sstevel@tonic-gate if (cp->c_metadata.md_rlno == 0) {
9470Sstevel@tonic-gate rl_ent.rl_fileno = cp->c_id.cid_fileno;
9480Sstevel@tonic-gate rl_ent.rl_local = (cp->c_id.cid_flags & CFS_CID_LOCAL) ? 1 : 0;
9490Sstevel@tonic-gate rl_ent.rl_fsid = fgp->fg_fscp->fs_cfsid;
9500Sstevel@tonic-gate rl_ent.rl_attrc = 0;
9510Sstevel@tonic-gate error = cachefs_rl_alloc(fgp->fg_fscp->fs_cache, &rl_ent,
9520Sstevel@tonic-gate &cp->c_metadata.md_rlno);
9530Sstevel@tonic-gate if (error)
9540Sstevel@tonic-gate goto out;
9550Sstevel@tonic-gate cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
9560Sstevel@tonic-gate CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno,
9570Sstevel@tonic-gate cp->c_metadata.md_frontblks);
9580Sstevel@tonic-gate cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE;
9590Sstevel@tonic-gate rlfree++;
9600Sstevel@tonic-gate cp->c_flags |= CN_UPDATED; /* XXX sam: do we need this? */
9610Sstevel@tonic-gate
9620Sstevel@tonic-gate /* increment number of front files */
9630Sstevel@tonic-gate error = filegrp_ffhold(fgp);
9640Sstevel@tonic-gate if (error) {
9650Sstevel@tonic-gate error = EINVAL;
9660Sstevel@tonic-gate goto out;
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate ffrele++;
9690Sstevel@tonic-gate }
9700Sstevel@tonic-gate
9710Sstevel@tonic-gate if (cp->c_flags & CN_ASYNC_POP_WORKING) {
9720Sstevel@tonic-gate /* lookup the already created front file */
9730Sstevel@tonic-gate error = VOP_LOOKUP(fgp->fg_dirvp, name, &cp->c_frontvp,
9745331Samw NULL, 0, NULL, kcred, NULL, NULL, NULL);
9750Sstevel@tonic-gate } else {
9760Sstevel@tonic-gate /* create the front file */
9770Sstevel@tonic-gate error = VOP_CREATE(fgp->fg_dirvp, name, attrp, EXCL, mode,
9785331Samw &cp->c_frontvp, kcred, 0, NULL, NULL);
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate if (error) {
9810Sstevel@tonic-gate #ifdef CFSDEBUG
9820Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_FRONT)
9830Sstevel@tonic-gate printf("c_createfrontfile: Can't create cached object"
9840Sstevel@tonic-gate " error %u, fileno %llx\n", error,
9850Sstevel@tonic-gate (u_longlong_t)cp->c_id.cid_fileno);
9860Sstevel@tonic-gate #endif
9870Sstevel@tonic-gate goto out;
9880Sstevel@tonic-gate }
9890Sstevel@tonic-gate
9900Sstevel@tonic-gate /* get a copy of the fid of the front file */
9910Sstevel@tonic-gate cp->c_metadata.md_fid.fid_len = MAXFIDSZ;
9925331Samw error = VOP_FID(cp->c_frontvp, &cp->c_metadata.md_fid, NULL);
9930Sstevel@tonic-gate if (error) {
9940Sstevel@tonic-gate /*
9950Sstevel@tonic-gate * If we get back ENOSPC then the fid we passed in was too
9960Sstevel@tonic-gate * small. For now we don't do anything and map to EINVAL.
9970Sstevel@tonic-gate */
9980Sstevel@tonic-gate if (error == ENOSPC) {
9990Sstevel@tonic-gate error = EINVAL;
10000Sstevel@tonic-gate }
10010Sstevel@tonic-gate goto out;
10020Sstevel@tonic-gate }
10030Sstevel@tonic-gate
10040Sstevel@tonic-gate dnlc_purge_vp(cp->c_frontvp);
10050Sstevel@tonic-gate
10060Sstevel@tonic-gate cp->c_metadata.md_flags |= MD_FILE;
10070Sstevel@tonic-gate cp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
10080Sstevel@tonic-gate
10090Sstevel@tonic-gate out:
10100Sstevel@tonic-gate if (error) {
10110Sstevel@tonic-gate if (cp->c_frontvp) {
10120Sstevel@tonic-gate VN_RELE(cp->c_frontvp);
10135331Samw (void) VOP_REMOVE(fgp->fg_dirvp, name, kcred, NULL, 0);
10140Sstevel@tonic-gate cp->c_frontvp = NULL;
10150Sstevel@tonic-gate }
10160Sstevel@tonic-gate if (ffrele)
10170Sstevel@tonic-gate filegrp_ffrele(fgp);
10180Sstevel@tonic-gate if (freefile)
10190Sstevel@tonic-gate cachefs_freefile(fgp->fg_fscp->fs_cache);
10200Sstevel@tonic-gate if (rlfree) {
10210Sstevel@tonic-gate #ifdef CFSDEBUG
10220Sstevel@tonic-gate cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
10230Sstevel@tonic-gate CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno);
10240Sstevel@tonic-gate #endif /* CFSDEBUG */
10250Sstevel@tonic-gate cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
10260Sstevel@tonic-gate CACHEFS_RL_FREE, cp->c_metadata.md_rlno, 0);
10270Sstevel@tonic-gate cp->c_metadata.md_rlno = 0;
10280Sstevel@tonic-gate cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
10290Sstevel@tonic-gate }
10300Sstevel@tonic-gate cachefs_nocache(cp);
10310Sstevel@tonic-gate }
10320Sstevel@tonic-gate if (alloc)
10330Sstevel@tonic-gate cachefs_kmem_free(attrp, sizeof (struct vattr));
10340Sstevel@tonic-gate #ifdef CFSDEBUG
10350Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_FRONT)
10360Sstevel@tonic-gate printf("c_createfrontfile: EXIT error = %d name %s\n", error,
1037*11066Srafael.vanoni@sun.com name);
10380Sstevel@tonic-gate #endif
10390Sstevel@tonic-gate return (error);
10400Sstevel@tonic-gate }
10410Sstevel@tonic-gate
10420Sstevel@tonic-gate /*
10430Sstevel@tonic-gate * Releases resources associated with the front file.
10440Sstevel@tonic-gate * Only call this routine if a ffhold has been done.
10450Sstevel@tonic-gate * Its okay to call this routine if the front file does not exist.
10460Sstevel@tonic-gate * Note: this routine is used even if there is no front file.
10470Sstevel@tonic-gate */
10480Sstevel@tonic-gate void
cachefs_removefrontfile(cachefs_metadata_t * mdp,cfs_cid_t * cidp,filegrp_t * fgp)10490Sstevel@tonic-gate cachefs_removefrontfile(cachefs_metadata_t *mdp, cfs_cid_t *cidp,
10500Sstevel@tonic-gate filegrp_t *fgp)
10510Sstevel@tonic-gate {
10520Sstevel@tonic-gate int error, enoent;
10530Sstevel@tonic-gate char name[CFS_FRONTFILE_NAME_SIZE + 2];
10540Sstevel@tonic-gate
10550Sstevel@tonic-gate ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
10560Sstevel@tonic-gate
10570Sstevel@tonic-gate enoent = 0;
10580Sstevel@tonic-gate if (mdp->md_flags & MD_FILE) {
10590Sstevel@tonic-gate if (fgp->fg_dirvp == NULL) {
10600Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: remove error, run fsck\n");
10610Sstevel@tonic-gate return;
10620Sstevel@tonic-gate }
10630Sstevel@tonic-gate make_ascii_name(cidp, name);
10645331Samw error = VOP_REMOVE(fgp->fg_dirvp, name, kcred, NULL, 0);
10650Sstevel@tonic-gate if (error == ENOENT)
10660Sstevel@tonic-gate enoent = 1;
10670Sstevel@tonic-gate if ((error) && (error != ENOENT)) {
10680Sstevel@tonic-gate cmn_err(CE_WARN, "UFS remove error %s %d, run fsck\n",
10690Sstevel@tonic-gate name, error);
10700Sstevel@tonic-gate }
10710Sstevel@tonic-gate if (mdp->md_flags & MD_ACLDIR) {
10720Sstevel@tonic-gate (void) strcat(name, ".d");
10730Sstevel@tonic-gate error = VOP_RMDIR(fgp->fg_dirvp, name, fgp->fg_dirvp,
10745331Samw kcred, NULL, 0);
10750Sstevel@tonic-gate if ((error) && (error != ENOENT)) {
10760Sstevel@tonic-gate cmn_err(CE_WARN, "frontfs rmdir error %s %d"
10770Sstevel@tonic-gate "; run fsck\n", name, error);
10780Sstevel@tonic-gate }
10790Sstevel@tonic-gate }
10800Sstevel@tonic-gate mdp->md_flags &= ~(MD_FILE | MD_POPULATED | MD_ACL | MD_ACLDIR);
10810Sstevel@tonic-gate bzero(&mdp->md_allocinfo, mdp->md_allocents *
1082*11066Srafael.vanoni@sun.com sizeof (struct cachefs_allocmap));
10830Sstevel@tonic-gate cachefs_freefile(fgp->fg_fscp->fs_cache);
10840Sstevel@tonic-gate }
10850Sstevel@tonic-gate
10860Sstevel@tonic-gate /*
10870Sstevel@tonic-gate * Clear packed bit, fastsymlinks and special files
10880Sstevel@tonic-gate * do not have a front file.
10890Sstevel@tonic-gate */
10900Sstevel@tonic-gate mdp->md_flags &= ~MD_PACKED;
10910Sstevel@tonic-gate
10920Sstevel@tonic-gate /* XXX either rename routine or move this to caller */
10930Sstevel@tonic-gate if (enoent == 0)
10940Sstevel@tonic-gate filegrp_ffrele(fgp);
10950Sstevel@tonic-gate
10960Sstevel@tonic-gate if (mdp->md_frontblks) {
10970Sstevel@tonic-gate cachefs_freeblocks(fgp->fg_fscp->fs_cache, mdp->md_frontblks,
10980Sstevel@tonic-gate mdp->md_rltype);
10990Sstevel@tonic-gate mdp->md_frontblks = 0;
11000Sstevel@tonic-gate }
11010Sstevel@tonic-gate }
11020Sstevel@tonic-gate
11030Sstevel@tonic-gate /*
11040Sstevel@tonic-gate * This is the interface to the rest of CFS. This takes a cnode, and returns
11050Sstevel@tonic-gate * the frontvp (stuffs it in the cnode). This creates an attrcache slot and
11060Sstevel@tonic-gate * and frontfile if necessary.
11070Sstevel@tonic-gate */
11080Sstevel@tonic-gate
11090Sstevel@tonic-gate int
cachefs_getfrontfile(cnode_t * cp)11100Sstevel@tonic-gate cachefs_getfrontfile(cnode_t *cp)
11110Sstevel@tonic-gate {
11120Sstevel@tonic-gate struct filegrp *fgp = cp->c_filegrp;
11130Sstevel@tonic-gate int error;
11140Sstevel@tonic-gate struct vattr va;
11150Sstevel@tonic-gate
11160Sstevel@tonic-gate #ifdef CFSDEBUG
11170Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_SUBR)
11180Sstevel@tonic-gate printf("c_getfrontfile: ENTER cp %p\n", (void *)cp);
11190Sstevel@tonic-gate #endif
11200Sstevel@tonic-gate
11210Sstevel@tonic-gate ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
11220Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cp->c_statelock));
11230Sstevel@tonic-gate
11240Sstevel@tonic-gate /*
11250Sstevel@tonic-gate * Now we check to see if there is a front file for this entry.
11260Sstevel@tonic-gate * If there is, we get the vnode for it and stick it in the cnode.
11270Sstevel@tonic-gate * Otherwise, we create a front file, get the vnode for it and stick
11280Sstevel@tonic-gate * it in the cnode.
11290Sstevel@tonic-gate */
11300Sstevel@tonic-gate if (cp->c_flags & CN_STALE) {
11310Sstevel@tonic-gate cp->c_flags |= CN_NOCACHE;
11320Sstevel@tonic-gate error = ESTALE;
11330Sstevel@tonic-gate goto out;
11340Sstevel@tonic-gate }
11350Sstevel@tonic-gate
11360Sstevel@tonic-gate /*
11370Sstevel@tonic-gate * If the cnode is being populated, and we're not the populating
11380Sstevel@tonic-gate * thread, then block until the pop thread completes. If we are the
11390Sstevel@tonic-gate * pop thread, then we may come in here, but not to nuke the directory
11400Sstevel@tonic-gate * cnode at a critical juncture. If we return from a cv_wait and the
11410Sstevel@tonic-gate * cnode is now stale, don't bother trying to get the front file.
11420Sstevel@tonic-gate */
11430Sstevel@tonic-gate while ((cp->c_flags & CN_ASYNC_POP_WORKING) &&
11440Sstevel@tonic-gate (cp->c_popthrp != curthread)) {
11450Sstevel@tonic-gate cv_wait(&cp->c_popcv, &cp->c_statelock);
11460Sstevel@tonic-gate if (cp->c_flags & CN_STALE) {
11470Sstevel@tonic-gate cp->c_flags |= CN_NOCACHE;
11480Sstevel@tonic-gate error = ESTALE;
11490Sstevel@tonic-gate goto out;
11500Sstevel@tonic-gate }
11510Sstevel@tonic-gate }
11520Sstevel@tonic-gate
11530Sstevel@tonic-gate if ((cp->c_metadata.md_flags & MD_FILE) == 0) {
11540Sstevel@tonic-gate #ifdef CFSDEBUG
11550Sstevel@tonic-gate if (cp->c_frontvp != NULL)
11560Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_FRONT)
1157*11066Srafael.vanoni@sun.com printf("c_getfrontfile: !MD_FILE and frontvp "
1158*11066Srafael.vanoni@sun.com "not null cp %p\n", (void *)cp);
11590Sstevel@tonic-gate #endif
11600Sstevel@tonic-gate if (CTOV(cp)->v_type == VDIR)
11610Sstevel@tonic-gate ASSERT((cp->c_metadata.md_flags & MD_POPULATED) == 0);
11620Sstevel@tonic-gate error = cachefs_createfrontfile(cp, fgp);
11630Sstevel@tonic-gate if (error)
11640Sstevel@tonic-gate goto out;
11650Sstevel@tonic-gate } else {
11660Sstevel@tonic-gate /*
11670Sstevel@tonic-gate * A front file exists, all we need to do is to grab the fid,
11680Sstevel@tonic-gate * do a VFS_VGET() on the fid, stuff the vnode in the cnode,
11690Sstevel@tonic-gate * and return.
11700Sstevel@tonic-gate */
11710Sstevel@tonic-gate if (fgp->fg_dirvp == NULL) {
11720Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: gff0: corrupted file system"
1173*11066Srafael.vanoni@sun.com " run fsck\n");
11740Sstevel@tonic-gate cachefs_inval_object(cp);
11750Sstevel@tonic-gate cp->c_flags |= CN_NOCACHE;
11760Sstevel@tonic-gate error = ESTALE;
11770Sstevel@tonic-gate goto out;
11780Sstevel@tonic-gate }
11790Sstevel@tonic-gate error = VFS_VGET(fgp->fg_dirvp->v_vfsp, &cp->c_frontvp,
1180*11066Srafael.vanoni@sun.com &cp->c_metadata.md_fid);
11810Sstevel@tonic-gate if (error || (cp->c_frontvp == NULL)) {
11820Sstevel@tonic-gate #ifdef CFSDEBUG
11830Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_FRONT)
11840Sstevel@tonic-gate printf("cachefs: "
11850Sstevel@tonic-gate "gff1: front file system error %d\n",
11860Sstevel@tonic-gate error);
11870Sstevel@tonic-gate #endif /* CFSDEBUG */
11880Sstevel@tonic-gate cachefs_inval_object(cp);
11890Sstevel@tonic-gate cp->c_flags |= CN_NOCACHE;
11900Sstevel@tonic-gate error = ESTALE;
11910Sstevel@tonic-gate goto out;
11920Sstevel@tonic-gate }
11930Sstevel@tonic-gate
11940Sstevel@tonic-gate /* don't need to check timestamps if need_front_sync is set */
11950Sstevel@tonic-gate if (cp->c_flags & CN_NEED_FRONT_SYNC) {
11960Sstevel@tonic-gate error = 0;
11970Sstevel@tonic-gate goto out;
11980Sstevel@tonic-gate }
11990Sstevel@tonic-gate
12000Sstevel@tonic-gate /* don't need to check empty directories */
12010Sstevel@tonic-gate if (CTOV(cp)->v_type == VDIR &&
12020Sstevel@tonic-gate ((cp->c_metadata.md_flags & MD_POPULATED) == 0)) {
12030Sstevel@tonic-gate error = 0;
12040Sstevel@tonic-gate goto out;
12050Sstevel@tonic-gate }
12060Sstevel@tonic-gate
12070Sstevel@tonic-gate /* get modify time of the front file */
12080Sstevel@tonic-gate va.va_mask = AT_MTIME;
12095331Samw error = VOP_GETATTR(cp->c_frontvp, &va, 0, kcred, NULL);
12100Sstevel@tonic-gate if (error) {
12110Sstevel@tonic-gate cmn_err(CE_WARN, "cachefs: gff2: front file"
1212*11066Srafael.vanoni@sun.com " system error %d", error);
12130Sstevel@tonic-gate cachefs_inval_object(cp);
12140Sstevel@tonic-gate error = (cp->c_flags & CN_NOCACHE) ? ESTALE : 0;
12150Sstevel@tonic-gate goto out;
12160Sstevel@tonic-gate }
12170Sstevel@tonic-gate
12180Sstevel@tonic-gate /* compare with modify time stored in metadata */
12190Sstevel@tonic-gate if (bcmp(&va.va_mtime, &cp->c_metadata.md_timestamp,
12200Sstevel@tonic-gate sizeof (timestruc_t)) != 0) {
12210Sstevel@tonic-gate #ifdef CFSDEBUG
12220Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_GENERAL | CFSDEBUG_INVALIDATE) {
12230Sstevel@tonic-gate long sec, nsec;
12240Sstevel@tonic-gate sec = cp->c_metadata.md_timestamp.tv_sec;
12250Sstevel@tonic-gate nsec = cp->c_metadata.md_timestamp.tv_nsec;
12260Sstevel@tonic-gate printf("c_getfrontfile: timestamps don't"
1227*11066Srafael.vanoni@sun.com " match fileno %lld va %lx %lx"
1228*11066Srafael.vanoni@sun.com " meta %lx %lx\n",
1229*11066Srafael.vanoni@sun.com (u_longlong_t)cp->c_id.cid_fileno,
1230*11066Srafael.vanoni@sun.com va.va_mtime.tv_sec,
1231*11066Srafael.vanoni@sun.com va.va_mtime.tv_nsec, sec, nsec);
12320Sstevel@tonic-gate }
12330Sstevel@tonic-gate #endif
12340Sstevel@tonic-gate cachefs_inval_object(cp);
12350Sstevel@tonic-gate error = (cp->c_flags & CN_NOCACHE) ? ESTALE : 0;
12360Sstevel@tonic-gate }
12370Sstevel@tonic-gate }
12380Sstevel@tonic-gate out:
12390Sstevel@tonic-gate #ifdef CFSDEBUG
12400Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_FRONT)
12410Sstevel@tonic-gate printf("c_getfrontfile: EXIT error = %d\n", error);
12420Sstevel@tonic-gate #endif
12430Sstevel@tonic-gate return (error);
12440Sstevel@tonic-gate }
12450Sstevel@tonic-gate
12460Sstevel@tonic-gate void
cachefs_inval_object(cnode_t * cp)12470Sstevel@tonic-gate cachefs_inval_object(cnode_t *cp)
12480Sstevel@tonic-gate {
12490Sstevel@tonic-gate cachefscache_t *cachep = C_TO_FSCACHE(cp)->fs_cache;
12500Sstevel@tonic-gate struct filegrp *fgp = cp->c_filegrp;
12510Sstevel@tonic-gate int error;
12520Sstevel@tonic-gate
12530Sstevel@tonic-gate ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(cp)) == 0);
12540Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cp->c_statelock));
12550Sstevel@tonic-gate ASSERT((cp->c_flags & CN_ASYNC_POP_WORKING) == 0 ||
1256*11066Srafael.vanoni@sun.com cp->c_popthrp == curthread);
12570Sstevel@tonic-gate #if 0
12580Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_SUBR)
12590Sstevel@tonic-gate printf("c_inval_object: ENTER cp %p\n", (void *)cp);
12600Sstevel@tonic-gate if (cp->c_flags & (CN_ASYNC_POPULATE | CN_ASYNC_POP_WORKING))
12610Sstevel@tonic-gate debug_enter("inval object during async pop");
12620Sstevel@tonic-gate #endif
12630Sstevel@tonic-gate cp->c_flags |= CN_NOCACHE;
12640Sstevel@tonic-gate
12650Sstevel@tonic-gate /* if we cannot modify the cache */
12660Sstevel@tonic-gate if (C_TO_FSCACHE(cp)->fs_cache->c_flags &
12670Sstevel@tonic-gate (CACHE_NOFILL | CACHE_NOCACHE)) {
12680Sstevel@tonic-gate goto out;
12690Sstevel@tonic-gate }
12700Sstevel@tonic-gate
12710Sstevel@tonic-gate /* if there is a front file */
12720Sstevel@tonic-gate if (cp->c_metadata.md_flags & MD_FILE) {
12730Sstevel@tonic-gate if (fgp->fg_dirvp == NULL)
12740Sstevel@tonic-gate goto out;
12750Sstevel@tonic-gate
12760Sstevel@tonic-gate /* get the front file vp if necessary */
12770Sstevel@tonic-gate if (cp->c_frontvp == NULL) {
12780Sstevel@tonic-gate
12790Sstevel@tonic-gate error = VFS_VGET(fgp->fg_dirvp->v_vfsp, &cp->c_frontvp,
1280*11066Srafael.vanoni@sun.com &cp->c_metadata.md_fid);
12810Sstevel@tonic-gate if (error || (cp->c_frontvp == NULL)) {
12820Sstevel@tonic-gate #ifdef CFSDEBUG
12830Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_FRONT)
12840Sstevel@tonic-gate printf("cachefs: "
12850Sstevel@tonic-gate "io: front file error %d\n", error);
12860Sstevel@tonic-gate #endif /* CFSDEBUG */
12870Sstevel@tonic-gate goto out;
12880Sstevel@tonic-gate }
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate
12910Sstevel@tonic-gate /* truncate the file to zero size */
12920Sstevel@tonic-gate error = cachefs_frontfile_size(cp, 0);
12930Sstevel@tonic-gate if (error)
12940Sstevel@tonic-gate goto out;
12950Sstevel@tonic-gate cp->c_flags &= ~CN_NOCACHE;
12960Sstevel@tonic-gate
12970Sstevel@tonic-gate /* if a directory, v_type is zero if called from initcnode */
12980Sstevel@tonic-gate if (cp->c_attr.va_type == VDIR) {
12990Sstevel@tonic-gate if (cp->c_usage < CFS_DIRCACHE_COST) {
13000Sstevel@tonic-gate cp->c_invals++;
13010Sstevel@tonic-gate if (cp->c_invals > CFS_DIRCACHE_INVAL) {
13020Sstevel@tonic-gate cp->c_invals = 0;
13030Sstevel@tonic-gate }
13040Sstevel@tonic-gate } else
13050Sstevel@tonic-gate cp->c_invals = 0;
13060Sstevel@tonic-gate cp->c_usage = 0;
13070Sstevel@tonic-gate }
13080Sstevel@tonic-gate } else {
13090Sstevel@tonic-gate cp->c_flags &= ~CN_NOCACHE;
13100Sstevel@tonic-gate }
13110Sstevel@tonic-gate
13120Sstevel@tonic-gate out:
13130Sstevel@tonic-gate if ((cp->c_metadata.md_flags & MD_PACKED) &&
13140Sstevel@tonic-gate (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) &&
13150Sstevel@tonic-gate ((cachep->c_flags & CACHE_NOFILL) == 0)) {
13160Sstevel@tonic-gate ASSERT(cp->c_metadata.md_rlno != 0);
13170Sstevel@tonic-gate if (cp->c_metadata.md_rltype != CACHEFS_RL_PACKED_PENDING) {
13180Sstevel@tonic-gate cachefs_rlent_moveto(cachep,
13190Sstevel@tonic-gate CACHEFS_RL_PACKED_PENDING,
13200Sstevel@tonic-gate cp->c_metadata.md_rlno,
13210Sstevel@tonic-gate cp->c_metadata.md_frontblks);
13220Sstevel@tonic-gate cp->c_metadata.md_rltype = CACHEFS_RL_PACKED_PENDING;
13230Sstevel@tonic-gate /* unconditionally set CN_UPDATED below */
13240Sstevel@tonic-gate }
13250Sstevel@tonic-gate }
13260Sstevel@tonic-gate
13270Sstevel@tonic-gate cachefs_purgeacl(cp);
13280Sstevel@tonic-gate
13290Sstevel@tonic-gate if (cp->c_flags & CN_ASYNC_POP_WORKING)
13300Sstevel@tonic-gate cp->c_flags |= CN_NOCACHE;
13310Sstevel@tonic-gate cp->c_metadata.md_flags &= ~(MD_POPULATED | MD_INVALREADDIR |
13320Sstevel@tonic-gate MD_FASTSYMLNK);
13330Sstevel@tonic-gate cp->c_flags &= ~CN_NEED_FRONT_SYNC;
13340Sstevel@tonic-gate cp->c_flags |= CN_UPDATED;
13350Sstevel@tonic-gate
13360Sstevel@tonic-gate /*
13370Sstevel@tonic-gate * If the object invalidated is a directory, the dnlc should be purged
13380Sstevel@tonic-gate * to elide all references to this (directory) vnode.
13390Sstevel@tonic-gate */
13400Sstevel@tonic-gate if (CTOV(cp)->v_type == VDIR)
13410Sstevel@tonic-gate dnlc_purge_vp(CTOV(cp));
13420Sstevel@tonic-gate
13430Sstevel@tonic-gate #ifdef CFSDEBUG
13440Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_SUBR)
13450Sstevel@tonic-gate printf("c_inval_object: EXIT\n");
13460Sstevel@tonic-gate #endif
13470Sstevel@tonic-gate }
13480Sstevel@tonic-gate
13490Sstevel@tonic-gate void
make_ascii_name(cfs_cid_t * cidp,char * strp)13500Sstevel@tonic-gate make_ascii_name(cfs_cid_t *cidp, char *strp)
13510Sstevel@tonic-gate {
13520Sstevel@tonic-gate int i = sizeof (uint_t) * 4;
13530Sstevel@tonic-gate u_longlong_t index;
13540Sstevel@tonic-gate ino64_t name;
13550Sstevel@tonic-gate
13560Sstevel@tonic-gate if (cidp->cid_flags & CFS_CID_LOCAL)
13570Sstevel@tonic-gate *strp++ = 'L';
13580Sstevel@tonic-gate name = (ino64_t)cidp->cid_fileno;
13590Sstevel@tonic-gate do {
13600Sstevel@tonic-gate index = (((u_longlong_t)name) & 0xf000000000000000) >> 60;
13610Sstevel@tonic-gate index &= (u_longlong_t)0xf;
13620Sstevel@tonic-gate ASSERT(index < (u_longlong_t)16);
13630Sstevel@tonic-gate *strp++ = "0123456789abcdef"[index];
13640Sstevel@tonic-gate name <<= 4;
13650Sstevel@tonic-gate } while (--i);
13660Sstevel@tonic-gate *strp = '\0';
13670Sstevel@tonic-gate }
13680Sstevel@tonic-gate
13690Sstevel@tonic-gate void
cachefs_nocache(cnode_t * cp)13700Sstevel@tonic-gate cachefs_nocache(cnode_t *cp)
13710Sstevel@tonic-gate {
13720Sstevel@tonic-gate fscache_t *fscp = C_TO_FSCACHE(cp);
13730Sstevel@tonic-gate cachefscache_t *cachep = fscp->fs_cache;
13740Sstevel@tonic-gate
13750Sstevel@tonic-gate #ifdef CFSDEBUG
13760Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_SUBR)
13770Sstevel@tonic-gate printf("c_nocache: ENTER cp %p\n", (void *)cp);
13780Sstevel@tonic-gate #endif
13790Sstevel@tonic-gate
13800Sstevel@tonic-gate ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
13810Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cp->c_statelock));
13820Sstevel@tonic-gate if ((cp->c_flags & CN_NOCACHE) == 0) {
13830Sstevel@tonic-gate #ifdef CFSDEBUG
13840Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_INVALIDATE)
13850Sstevel@tonic-gate printf("cachefs_nocache: invalidating %llu\n",
13860Sstevel@tonic-gate (u_longlong_t)cp->c_id.cid_fileno);
13870Sstevel@tonic-gate #endif
13880Sstevel@tonic-gate /*
13890Sstevel@tonic-gate * Here we are waiting until inactive time to do
13900Sstevel@tonic-gate * the inval_object. In case we don't get to inactive
13910Sstevel@tonic-gate * (because of a crash, say) we set up a timestamp mismatch
13920Sstevel@tonic-gate * such that getfrontfile will blow the front file away
13930Sstevel@tonic-gate * next time we try to use it.
13940Sstevel@tonic-gate */
13950Sstevel@tonic-gate cp->c_metadata.md_timestamp.tv_sec = 0;
13960Sstevel@tonic-gate cp->c_metadata.md_timestamp.tv_nsec = 0;
13970Sstevel@tonic-gate cp->c_metadata.md_flags &= ~(MD_POPULATED | MD_INVALREADDIR |
13980Sstevel@tonic-gate MD_FASTSYMLNK);
13990Sstevel@tonic-gate cp->c_flags &= ~CN_NEED_FRONT_SYNC;
14000Sstevel@tonic-gate
14010Sstevel@tonic-gate cachefs_purgeacl(cp);
14020Sstevel@tonic-gate
14030Sstevel@tonic-gate /*
14040Sstevel@tonic-gate * It is possible we can nocache while disconnected.
14050Sstevel@tonic-gate * A directory could be nocached by running out of space.
14060Sstevel@tonic-gate * A regular file should only be nocached if an I/O error
14070Sstevel@tonic-gate * occurs to the front fs.
14080Sstevel@tonic-gate * We count on the item staying on the modified list
14090Sstevel@tonic-gate * so we do not loose the cid to fid mapping for directories.
14100Sstevel@tonic-gate */
14110Sstevel@tonic-gate
14120Sstevel@tonic-gate if ((cp->c_metadata.md_flags & MD_PACKED) &&
14130Sstevel@tonic-gate (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) &&
14140Sstevel@tonic-gate ((cachep->c_flags & CACHE_NOFILL) == 0)) {
14150Sstevel@tonic-gate ASSERT(cp->c_metadata.md_rlno != 0);
14160Sstevel@tonic-gate if (cp->c_metadata.md_rltype !=
14170Sstevel@tonic-gate CACHEFS_RL_PACKED_PENDING) {
14180Sstevel@tonic-gate cachefs_rlent_moveto(cachep,
14190Sstevel@tonic-gate CACHEFS_RL_PACKED_PENDING,
14200Sstevel@tonic-gate cp->c_metadata.md_rlno,
14210Sstevel@tonic-gate cp->c_metadata.md_frontblks);
14220Sstevel@tonic-gate cp->c_metadata.md_rltype =
14230Sstevel@tonic-gate CACHEFS_RL_PACKED_PENDING;
14240Sstevel@tonic-gate /* unconditionally set CN_UPDATED below */
14250Sstevel@tonic-gate }
14260Sstevel@tonic-gate }
14270Sstevel@tonic-gate
14280Sstevel@tonic-gate if (CTOV(cp)->v_type == VDIR)
14290Sstevel@tonic-gate dnlc_purge_vp(CTOV(cp));
14300Sstevel@tonic-gate cp->c_flags |= (CN_NOCACHE | CN_UPDATED);
14310Sstevel@tonic-gate }
14320Sstevel@tonic-gate
14330Sstevel@tonic-gate if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_NOCACHE))
14340Sstevel@tonic-gate cachefs_log_nocache(cachep, 0, fscp->fs_cfsvfsp,
14350Sstevel@tonic-gate &cp->c_metadata.md_cookie, cp->c_id.cid_fileno);
14360Sstevel@tonic-gate
14370Sstevel@tonic-gate #ifdef CFSDEBUG
14380Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_SUBR)
14390Sstevel@tonic-gate printf("c_nocache: EXIT cp %p\n", (void *)cp);
14400Sstevel@tonic-gate #endif
14410Sstevel@tonic-gate }
14420Sstevel@tonic-gate
14430Sstevel@tonic-gate /*
14440Sstevel@tonic-gate * Checks to see if the page is in the disk cache, by checking the allocmap.
14450Sstevel@tonic-gate */
14460Sstevel@tonic-gate int
cachefs_check_allocmap(cnode_t * cp,u_offset_t off)14470Sstevel@tonic-gate cachefs_check_allocmap(cnode_t *cp, u_offset_t off)
14480Sstevel@tonic-gate {
14490Sstevel@tonic-gate int i;
14500Sstevel@tonic-gate size_t dbl_size_to_look = cp->c_attr.va_size - off;
14510Sstevel@tonic-gate uint_t size_to_look;
14520Sstevel@tonic-gate
14530Sstevel@tonic-gate if (dbl_size_to_look > (u_offset_t)PAGESIZE)
14540Sstevel@tonic-gate size_to_look = (uint_t)PAGESIZE;
14550Sstevel@tonic-gate else
14560Sstevel@tonic-gate /*LINTED alignment okay*/
14570Sstevel@tonic-gate size_to_look = (uint_t)dbl_size_to_look;
14580Sstevel@tonic-gate
14590Sstevel@tonic-gate for (i = 0; i < cp->c_metadata.md_allocents; i++) {
14600Sstevel@tonic-gate struct cachefs_allocmap *allocp =
1461*11066Srafael.vanoni@sun.com cp->c_metadata.md_allocinfo + i;
14620Sstevel@tonic-gate
14630Sstevel@tonic-gate if (off >= allocp->am_start_off) {
14640Sstevel@tonic-gate if ((off + size_to_look) <=
14650Sstevel@tonic-gate (allocp->am_start_off + allocp->am_size)) {
14660Sstevel@tonic-gate struct fscache *fscp = C_TO_FSCACHE(cp);
14670Sstevel@tonic-gate cachefscache_t *cachep = fscp->fs_cache;
14680Sstevel@tonic-gate
14690Sstevel@tonic-gate if (CACHEFS_LOG_LOGGING(cachep,
14700Sstevel@tonic-gate CACHEFS_LOG_CALLOC))
14710Sstevel@tonic-gate cachefs_log_calloc(cachep, 0,
14720Sstevel@tonic-gate fscp->fs_cfsvfsp,
14730Sstevel@tonic-gate &cp->c_metadata.md_cookie,
14740Sstevel@tonic-gate cp->c_id.cid_fileno,
14750Sstevel@tonic-gate off, size_to_look);
14760Sstevel@tonic-gate /*
14770Sstevel@tonic-gate * Found the page in the CFS disk cache.
14780Sstevel@tonic-gate */
14790Sstevel@tonic-gate return (1);
14800Sstevel@tonic-gate }
14810Sstevel@tonic-gate } else {
14820Sstevel@tonic-gate return (0);
14830Sstevel@tonic-gate }
14840Sstevel@tonic-gate }
14850Sstevel@tonic-gate return (0);
14860Sstevel@tonic-gate }
14870Sstevel@tonic-gate
14880Sstevel@tonic-gate /*
14890Sstevel@tonic-gate * Merges adjacent allocmap entries together where possible, e.g.
14900Sstevel@tonic-gate * offset=0x0, size=0x40000
14910Sstevel@tonic-gate * offset=0x40000, size=0x20000 becomes just offset=0x0, size-0x90000
14920Sstevel@tonic-gate * offset=0x60000, size=0x30000
14930Sstevel@tonic-gate */
14940Sstevel@tonic-gate
14950Sstevel@tonic-gate
14960Sstevel@tonic-gate void
cachefs_coalesce_allocmap(struct cachefs_metadata * cmd)14970Sstevel@tonic-gate cachefs_coalesce_allocmap(struct cachefs_metadata *cmd)
14980Sstevel@tonic-gate {
14990Sstevel@tonic-gate int i, reduced = 0;
15000Sstevel@tonic-gate struct cachefs_allocmap *allocp, *nallocp;
15010Sstevel@tonic-gate
15020Sstevel@tonic-gate nallocp = allocp = cmd->md_allocinfo;
15030Sstevel@tonic-gate allocp++;
15040Sstevel@tonic-gate for (i = 1; i < cmd->md_allocents; i++, allocp++) {
15050Sstevel@tonic-gate if (nallocp->am_start_off + nallocp->am_size ==
1506*11066Srafael.vanoni@sun.com allocp->am_start_off) {
15070Sstevel@tonic-gate nallocp->am_size += allocp->am_size;
15080Sstevel@tonic-gate reduced++;
15090Sstevel@tonic-gate } else {
15100Sstevel@tonic-gate nallocp++;
15110Sstevel@tonic-gate nallocp->am_start_off = allocp->am_start_off;
15120Sstevel@tonic-gate nallocp->am_size = allocp->am_size;
15130Sstevel@tonic-gate }
15140Sstevel@tonic-gate }
15150Sstevel@tonic-gate cmd->md_allocents -= reduced;
15160Sstevel@tonic-gate }
15170Sstevel@tonic-gate
15180Sstevel@tonic-gate /*
15190Sstevel@tonic-gate * Updates the allocmap to reflect a new chunk of data that has been
15200Sstevel@tonic-gate * populated.
15210Sstevel@tonic-gate */
15220Sstevel@tonic-gate void
cachefs_update_allocmap(cnode_t * cp,u_offset_t off,size_t size)15230Sstevel@tonic-gate cachefs_update_allocmap(cnode_t *cp, u_offset_t off, size_t size)
15240Sstevel@tonic-gate {
15250Sstevel@tonic-gate int i;
15260Sstevel@tonic-gate struct cachefs_allocmap *allocp;
15270Sstevel@tonic-gate struct fscache *fscp = C_TO_FSCACHE(cp);
15280Sstevel@tonic-gate cachefscache_t *cachep = fscp->fs_cache;
15290Sstevel@tonic-gate u_offset_t saveoff;
15300Sstevel@tonic-gate u_offset_t savesize;
15310Sstevel@tonic-gate u_offset_t logoff = off;
15320Sstevel@tonic-gate size_t logsize = size;
15330Sstevel@tonic-gate u_offset_t endoff;
15340Sstevel@tonic-gate u_offset_t tmpendoff;
15350Sstevel@tonic-gate
15360Sstevel@tonic-gate /*
15370Sstevel@tonic-gate * We try to see if we can coalesce the current block into an existing
15380Sstevel@tonic-gate * allocation and mark it as such.
15390Sstevel@tonic-gate * If we can't do that then we make a new entry in the allocmap.
15400Sstevel@tonic-gate * when we run out of allocmaps, put the cnode in NOCACHE mode.
15410Sstevel@tonic-gate */
15420Sstevel@tonic-gate again:
15430Sstevel@tonic-gate allocp = cp->c_metadata.md_allocinfo;
15440Sstevel@tonic-gate for (i = 0; i < cp->c_metadata.md_allocents; i++, allocp++) {
15450Sstevel@tonic-gate
15460Sstevel@tonic-gate if (off <= (allocp->am_start_off)) {
15470Sstevel@tonic-gate endoff = off + size;
15480Sstevel@tonic-gate if (endoff >= allocp->am_start_off) {
15490Sstevel@tonic-gate tmpendoff = allocp->am_start_off +
1550*11066Srafael.vanoni@sun.com allocp->am_size;
15510Sstevel@tonic-gate if (endoff < tmpendoff)
15520Sstevel@tonic-gate endoff = tmpendoff;
15530Sstevel@tonic-gate allocp->am_size = endoff - off;
15540Sstevel@tonic-gate allocp->am_start_off = off;
15550Sstevel@tonic-gate cachefs_coalesce_allocmap(&cp->c_metadata);
15560Sstevel@tonic-gate allocp = cp->c_metadata.md_allocinfo;
15570Sstevel@tonic-gate if (allocp->am_size >= cp->c_size)
15580Sstevel@tonic-gate cp->c_metadata.md_flags |= MD_POPULATED;
15590Sstevel@tonic-gate return;
15600Sstevel@tonic-gate } else {
15610Sstevel@tonic-gate saveoff = off;
15620Sstevel@tonic-gate savesize = size;
15630Sstevel@tonic-gate off = allocp->am_start_off;
15640Sstevel@tonic-gate size = allocp->am_size;
15650Sstevel@tonic-gate allocp->am_size = savesize;
15660Sstevel@tonic-gate allocp->am_start_off = saveoff;
15670Sstevel@tonic-gate goto again;
15680Sstevel@tonic-gate }
15690Sstevel@tonic-gate } else {
15700Sstevel@tonic-gate endoff = allocp->am_start_off + allocp->am_size;
15710Sstevel@tonic-gate if (off < endoff) {
15720Sstevel@tonic-gate tmpendoff = off + size;
15730Sstevel@tonic-gate if (endoff < tmpendoff)
15740Sstevel@tonic-gate endoff = tmpendoff;
15750Sstevel@tonic-gate allocp->am_size = endoff - allocp->am_start_off;
15760Sstevel@tonic-gate cachefs_coalesce_allocmap(&cp->c_metadata);
15770Sstevel@tonic-gate allocp = cp->c_metadata.md_allocinfo;
15780Sstevel@tonic-gate if (allocp->am_size >= cp->c_size)
15790Sstevel@tonic-gate cp->c_metadata.md_flags |= MD_POPULATED;
15800Sstevel@tonic-gate return;
15810Sstevel@tonic-gate }
15820Sstevel@tonic-gate if (off == (allocp->am_start_off + allocp->am_size)) {
15830Sstevel@tonic-gate allocp->am_size += size;
15840Sstevel@tonic-gate cachefs_coalesce_allocmap(&cp->c_metadata);
15850Sstevel@tonic-gate allocp = cp->c_metadata.md_allocinfo;
15860Sstevel@tonic-gate if (allocp->am_size >= cp->c_size)
15870Sstevel@tonic-gate cp->c_metadata.md_flags |= MD_POPULATED;
15880Sstevel@tonic-gate return;
15890Sstevel@tonic-gate }
15900Sstevel@tonic-gate }
15910Sstevel@tonic-gate }
15920Sstevel@tonic-gate if (i == C_MAX_ALLOCINFO_SLOTS) {
15930Sstevel@tonic-gate #ifdef CFSDEBUG
15940Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_ALLOCMAP)
15950Sstevel@tonic-gate printf("c_update_alloc_map: "
15960Sstevel@tonic-gate "Too many allinfo entries cp %p fileno %llu %p\n",
15970Sstevel@tonic-gate (void *)cp, (u_longlong_t)cp->c_id.cid_fileno,
15980Sstevel@tonic-gate (void *)cp->c_metadata.md_allocinfo);
15990Sstevel@tonic-gate #endif
16000Sstevel@tonic-gate cachefs_nocache(cp);
16010Sstevel@tonic-gate return;
16020Sstevel@tonic-gate }
16030Sstevel@tonic-gate allocp->am_start_off = off;
16040Sstevel@tonic-gate allocp->am_size = (u_offset_t)size;
16050Sstevel@tonic-gate if (allocp->am_size >= cp->c_size)
16060Sstevel@tonic-gate cp->c_metadata.md_flags |= MD_POPULATED;
16070Sstevel@tonic-gate cp->c_metadata.md_allocents++;
16080Sstevel@tonic-gate
16090Sstevel@tonic-gate if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_UALLOC))
16100Sstevel@tonic-gate cachefs_log_ualloc(cachep, 0, fscp->fs_cfsvfsp,
16110Sstevel@tonic-gate &cp->c_metadata.md_cookie, cp->c_id.cid_fileno,
16120Sstevel@tonic-gate logoff, logsize);
16130Sstevel@tonic-gate }
16140Sstevel@tonic-gate
16150Sstevel@tonic-gate /*
16160Sstevel@tonic-gate * CFS population function
16170Sstevel@tonic-gate *
16180Sstevel@tonic-gate * before async population, this function used to turn on the cnode
16190Sstevel@tonic-gate * flags CN_UPDATED, CN_NEED_FRONT_SYNC, and CN_POPULATION_PENDING.
16200Sstevel@tonic-gate * now, however, it's the responsibility of the caller to do this if
16210Sstevel@tonic-gate * this function returns 0 (no error).
16220Sstevel@tonic-gate */
16230Sstevel@tonic-gate
16240Sstevel@tonic-gate int
cachefs_populate(cnode_t * cp,u_offset_t off,size_t popsize,vnode_t * frontvp,vnode_t * backvp,u_offset_t cpsize,cred_t * cr)16250Sstevel@tonic-gate cachefs_populate(cnode_t *cp, u_offset_t off, size_t popsize, vnode_t *frontvp,
16260Sstevel@tonic-gate vnode_t *backvp, u_offset_t cpsize, cred_t *cr)
16270Sstevel@tonic-gate {
16280Sstevel@tonic-gate int error = 0;
16290Sstevel@tonic-gate caddr_t addr;
16300Sstevel@tonic-gate u_offset_t upto;
16310Sstevel@tonic-gate uint_t size;
16320Sstevel@tonic-gate u_offset_t from = off;
16330Sstevel@tonic-gate cachefscache_t *cachep = C_TO_FSCACHE(cp)->fs_cache;
16340Sstevel@tonic-gate ssize_t resid;
16350Sstevel@tonic-gate struct fbuf *fbp;
16360Sstevel@tonic-gate caddr_t buf = kmem_alloc(MAXBSIZE, KM_SLEEP);
16370Sstevel@tonic-gate
16380Sstevel@tonic-gate #ifdef CFSDEBUG
16390Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_VOPS)
16400Sstevel@tonic-gate printf("cachefs_populate: ENTER cp %p off %lld\n",
16410Sstevel@tonic-gate (void *)cp, off);
16420Sstevel@tonic-gate #endif
16430Sstevel@tonic-gate
16440Sstevel@tonic-gate upto = MIN((off + popsize), cpsize);
16450Sstevel@tonic-gate
16460Sstevel@tonic-gate while (from < upto) {
16470Sstevel@tonic-gate u_offset_t blkoff = (from & (offset_t)MAXBMASK);
16480Sstevel@tonic-gate uint_t n = from - blkoff;
16490Sstevel@tonic-gate
16500Sstevel@tonic-gate size = upto - from;
16510Sstevel@tonic-gate if (upto > (blkoff + MAXBSIZE))
16520Sstevel@tonic-gate size = MAXBSIZE - n;
16530Sstevel@tonic-gate
16540Sstevel@tonic-gate error = fbread(backvp, (offset_t)blkoff, n + size,
1655*11066Srafael.vanoni@sun.com S_OTHER, &fbp);
16560Sstevel@tonic-gate if (CFS_TIMEOUT(C_TO_FSCACHE(cp), error))
16570Sstevel@tonic-gate goto out;
16580Sstevel@tonic-gate else if (error) {
16590Sstevel@tonic-gate #ifdef CFSDEBUG
16600Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_BACK)
16610Sstevel@tonic-gate printf("cachefs_populate: fbread error %d\n",
16620Sstevel@tonic-gate error);
16630Sstevel@tonic-gate #endif
16640Sstevel@tonic-gate goto out;
16650Sstevel@tonic-gate }
16660Sstevel@tonic-gate
16670Sstevel@tonic-gate addr = fbp->fb_addr;
16680Sstevel@tonic-gate ASSERT(addr != NULL);
16690Sstevel@tonic-gate ASSERT(n + size <= MAXBSIZE);
16700Sstevel@tonic-gate bcopy(addr, buf, n + size);
16710Sstevel@tonic-gate fbrelse(fbp, S_OTHER);
16720Sstevel@tonic-gate
16730Sstevel@tonic-gate if (n == 0 || cachefs_check_allocmap(cp, blkoff) == 0) {
16740Sstevel@tonic-gate if (error = cachefs_allocblocks(cachep, 1,
16750Sstevel@tonic-gate cp->c_metadata.md_rltype))
16760Sstevel@tonic-gate goto out;
16770Sstevel@tonic-gate cp->c_metadata.md_frontblks++;
16780Sstevel@tonic-gate }
16790Sstevel@tonic-gate resid = 0;
16800Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, frontvp, buf + n, size,
1681*11066Srafael.vanoni@sun.com (offset_t)from, UIO_SYSSPACE, 0,
1682*11066Srafael.vanoni@sun.com (rlim64_t)RLIM64_INFINITY, cr, &resid);
16830Sstevel@tonic-gate if (error) {
16840Sstevel@tonic-gate #ifdef CFSDEBUG
16850Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_FRONT)
16860Sstevel@tonic-gate printf("cachefs_populate: "
16870Sstevel@tonic-gate "Got error = %d from vn_rdwr\n", error);
16880Sstevel@tonic-gate #endif
16890Sstevel@tonic-gate goto out;
16900Sstevel@tonic-gate }
16910Sstevel@tonic-gate #ifdef CFSDEBUG
16920Sstevel@tonic-gate if (resid)
16930Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_FRONT)
16940Sstevel@tonic-gate printf("cachefs_populate: non-zero resid %ld\n",
16950Sstevel@tonic-gate resid);
16960Sstevel@tonic-gate #endif
16970Sstevel@tonic-gate from += size;
16980Sstevel@tonic-gate }
16990Sstevel@tonic-gate (void) cachefs_update_allocmap(cp, off, upto - off);
17000Sstevel@tonic-gate out:
17010Sstevel@tonic-gate if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_POPULATE))
17020Sstevel@tonic-gate cachefs_log_populate(cachep, error,
17030Sstevel@tonic-gate C_TO_FSCACHE(cp)->fs_cfsvfsp,
17040Sstevel@tonic-gate &cp->c_metadata.md_cookie, cp->c_id.cid_fileno, off,
17050Sstevel@tonic-gate popsize);
17060Sstevel@tonic-gate
17070Sstevel@tonic-gate #ifdef CFSDEBUG
17080Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_VOPS)
17090Sstevel@tonic-gate printf("cachefs_populate: EXIT cp %p error %d\n",
17100Sstevel@tonic-gate (void *)cp, error);
17110Sstevel@tonic-gate #endif
17120Sstevel@tonic-gate kmem_free(buf, MAXBSIZE);
17130Sstevel@tonic-gate
17140Sstevel@tonic-gate return (error);
17150Sstevel@tonic-gate }
17160Sstevel@tonic-gate
17170Sstevel@tonic-gate /*
17180Sstevel@tonic-gate * due to compiler error we shifted cnode to the last argument slot.
17195331Samw * occurred during large files project - XXX.
17200Sstevel@tonic-gate */
17210Sstevel@tonic-gate void
cachefs_cluster_allocmap(u_offset_t off,u_offset_t * popoffp,size_t * popsizep,size_t size,struct cnode * cp)1722*11066Srafael.vanoni@sun.com cachefs_cluster_allocmap(u_offset_t off, u_offset_t *popoffp, size_t *popsizep,
1723*11066Srafael.vanoni@sun.com size_t size, struct cnode *cp)
17240Sstevel@tonic-gate {
17250Sstevel@tonic-gate int i;
17260Sstevel@tonic-gate u_offset_t lastoff = 0;
17270Sstevel@tonic-gate u_offset_t forward_diff = 0;
17280Sstevel@tonic-gate u_offset_t backward_diff = 0;
17290Sstevel@tonic-gate
17300Sstevel@tonic-gate ASSERT(size <= C_TO_FSCACHE(cp)->fs_info.fi_popsize);
17310Sstevel@tonic-gate
17320Sstevel@tonic-gate #ifdef CFSDEBUG
17330Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_SUBR)
17340Sstevel@tonic-gate printf("cachefs_cluster_allocmap: off %llx, size %llx, "
1735*11066Srafael.vanoni@sun.com "c_size %llx\n", off, size, (longlong_t)cp->c_size);
17360Sstevel@tonic-gate #endif /* CFSDEBUG */
17370Sstevel@tonic-gate for (i = 0; i < cp->c_metadata.md_allocents; i++) {
17380Sstevel@tonic-gate struct cachefs_allocmap *allocp =
1739*11066Srafael.vanoni@sun.com cp->c_metadata.md_allocinfo + i;
17400Sstevel@tonic-gate
17410Sstevel@tonic-gate if (allocp->am_start_off > off) {
17420Sstevel@tonic-gate if ((off + size) > allocp->am_start_off) {
17430Sstevel@tonic-gate forward_diff = allocp->am_start_off - off;
17440Sstevel@tonic-gate backward_diff = size - forward_diff;
17450Sstevel@tonic-gate if (backward_diff > off)
17460Sstevel@tonic-gate backward_diff = off;
17470Sstevel@tonic-gate if (lastoff > (off - backward_diff))
17480Sstevel@tonic-gate backward_diff = off - lastoff;
17490Sstevel@tonic-gate } else {
17500Sstevel@tonic-gate forward_diff = size;
17510Sstevel@tonic-gate }
17520Sstevel@tonic-gate *popoffp = (off - backward_diff) & (offset_t)PAGEMASK;
17530Sstevel@tonic-gate *popsizep = ((off + forward_diff) - *popoffp) &
1754*11066Srafael.vanoni@sun.com (offset_t)PAGEMASK;
17550Sstevel@tonic-gate return;
17560Sstevel@tonic-gate } else {
17570Sstevel@tonic-gate lastoff = allocp->am_start_off + allocp->am_size;
17580Sstevel@tonic-gate }
17590Sstevel@tonic-gate }
17600Sstevel@tonic-gate if ((lastoff + size) > off) {
17610Sstevel@tonic-gate *popoffp = (lastoff & (offset_t)PAGEMASK);
17620Sstevel@tonic-gate } else {
1763*11066Srafael.vanoni@sun.com *popoffp = off & (offset_t)PAGEMASK;
17640Sstevel@tonic-gate }
17650Sstevel@tonic-gate
17660Sstevel@tonic-gate /*
17670Sstevel@tonic-gate * 64bit project: popsize is the chunk size used to populate the
17680Sstevel@tonic-gate * cache (default 64K). As such, 32 bit should suffice.
17690Sstevel@tonic-gate */
17700Sstevel@tonic-gate if ((*popoffp + size) > cp->c_size)
17710Sstevel@tonic-gate *popsizep = (cp->c_size - *popoffp + PAGEOFFSET) &
1772*11066Srafael.vanoni@sun.com (offset_t)PAGEMASK;
17730Sstevel@tonic-gate else if (size < PAGESIZE)
1774*11066Srafael.vanoni@sun.com *popsizep = (size + PAGEOFFSET) & (offset_t)PAGEMASK;
17750Sstevel@tonic-gate else
17760Sstevel@tonic-gate *popsizep = size & (offset_t)PAGEMASK;
17770Sstevel@tonic-gate
17780Sstevel@tonic-gate #ifdef CFSDEBUG
17790Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_SUBR)
17800Sstevel@tonic-gate printf("cachefs_cluster_allocmap: popoff %llx, popsize %llx\n",
1781*11066Srafael.vanoni@sun.com (u_longlong_t)(*popoffp), (u_longlong_t)(*popsizep));
17820Sstevel@tonic-gate #endif /* CFSDEBUG */
17830Sstevel@tonic-gate }
17840Sstevel@tonic-gate
17850Sstevel@tonic-gate /*
17860Sstevel@tonic-gate * "populate" a symlink in the cache
17870Sstevel@tonic-gate */
17880Sstevel@tonic-gate int
cachefs_stuffsymlink(cnode_t * cp,caddr_t buf,int buflen)17890Sstevel@tonic-gate cachefs_stuffsymlink(cnode_t *cp, caddr_t buf, int buflen)
17900Sstevel@tonic-gate {
17910Sstevel@tonic-gate int error = 0;
17920Sstevel@tonic-gate struct fscache *fscp = C_TO_FSCACHE(cp);
17930Sstevel@tonic-gate cachefscache_t *cachep = fscp->fs_cache;
17940Sstevel@tonic-gate struct cachefs_metadata *mdp = &cp->c_metadata;
17950Sstevel@tonic-gate
17960Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&cp->c_rwlock));
17970Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cp->c_statelock));
17980Sstevel@tonic-gate
17990Sstevel@tonic-gate if (CFS_ISFS_BACKFS_NFSV4(fscp))
18000Sstevel@tonic-gate goto out;
18010Sstevel@tonic-gate
18020Sstevel@tonic-gate if (cp->c_flags & CN_NOCACHE)
18030Sstevel@tonic-gate return (ENOENT);
18040Sstevel@tonic-gate
18050Sstevel@tonic-gate cp->c_size = (u_offset_t)buflen;
18060Sstevel@tonic-gate
18070Sstevel@tonic-gate /* if can create a fast sym link */
18080Sstevel@tonic-gate if (buflen <= C_FSL_SIZE) {
18090Sstevel@tonic-gate /* give up the front file resources */
18100Sstevel@tonic-gate if (mdp->md_rlno) {
18110Sstevel@tonic-gate cachefs_removefrontfile(mdp, &cp->c_id, cp->c_filegrp);
18120Sstevel@tonic-gate cachefs_rlent_moveto(cachep, CACHEFS_RL_FREE,
18130Sstevel@tonic-gate mdp->md_rlno, 0);
18140Sstevel@tonic-gate mdp->md_rlno = 0;
18150Sstevel@tonic-gate mdp->md_rltype = CACHEFS_RL_NONE;
18160Sstevel@tonic-gate }
18170Sstevel@tonic-gate /* put sym link contents in allocinfo in metadata */
18180Sstevel@tonic-gate bzero(mdp->md_allocinfo, C_FSL_SIZE);
18190Sstevel@tonic-gate bcopy(buf, mdp->md_allocinfo, buflen);
18200Sstevel@tonic-gate
18210Sstevel@tonic-gate mdp->md_flags |= MD_FASTSYMLNK;
18220Sstevel@tonic-gate cp->c_flags &= ~CN_NEED_FRONT_SYNC;
18230Sstevel@tonic-gate cp->c_flags |= CN_UPDATED;
18240Sstevel@tonic-gate goto out;
18250Sstevel@tonic-gate }
18260Sstevel@tonic-gate
18270Sstevel@tonic-gate /* else create a sym link in a front file */
18280Sstevel@tonic-gate if (cp->c_frontvp == NULL)
18290Sstevel@tonic-gate error = cachefs_getfrontfile(cp);
18300Sstevel@tonic-gate if (error)
18310Sstevel@tonic-gate goto out;
18320Sstevel@tonic-gate
18330Sstevel@tonic-gate /* truncate front file */
18340Sstevel@tonic-gate error = cachefs_frontfile_size(cp, 0);
18350Sstevel@tonic-gate mdp->md_flags &= ~(MD_FASTSYMLNK | MD_POPULATED);
18360Sstevel@tonic-gate if (error)
18370Sstevel@tonic-gate goto out;
18380Sstevel@tonic-gate
18390Sstevel@tonic-gate /* get space for the sym link */
18400Sstevel@tonic-gate error = cachefs_allocblocks(cachep, 1, cp->c_metadata.md_rltype);
18410Sstevel@tonic-gate if (error)
18420Sstevel@tonic-gate goto out;
18430Sstevel@tonic-gate
18440Sstevel@tonic-gate /* write the sym link to the front file */
18450Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, cp->c_frontvp, buf, buflen, 0,
18460Sstevel@tonic-gate UIO_SYSSPACE, 0, RLIM_INFINITY, kcred, NULL);
18470Sstevel@tonic-gate if (error) {
18480Sstevel@tonic-gate cachefs_freeblocks(cachep, 1, cp->c_metadata.md_rltype);
18490Sstevel@tonic-gate goto out;
18500Sstevel@tonic-gate }
18510Sstevel@tonic-gate
18520Sstevel@tonic-gate cp->c_metadata.md_flags |= MD_POPULATED;
18530Sstevel@tonic-gate cp->c_flags |= CN_NEED_FRONT_SYNC;
18540Sstevel@tonic-gate cp->c_flags |= CN_UPDATED;
18550Sstevel@tonic-gate
18560Sstevel@tonic-gate out:
18570Sstevel@tonic-gate if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_CSYMLINK))
18580Sstevel@tonic-gate cachefs_log_csymlink(cachep, error, fscp->fs_cfsvfsp,
18590Sstevel@tonic-gate &cp->c_metadata.md_cookie, cp->c_id.cid_fileno, buflen);
18600Sstevel@tonic-gate
18610Sstevel@tonic-gate return (error);
18620Sstevel@tonic-gate }
18630Sstevel@tonic-gate
18640Sstevel@tonic-gate /*
18650Sstevel@tonic-gate * Reads the full contents of the symbolic link from the back file system.
18660Sstevel@tonic-gate * *bufp is set to a MAXPATHLEN buffer that must be freed when done
18670Sstevel@tonic-gate * *buflenp is the length of the link
18680Sstevel@tonic-gate */
18690Sstevel@tonic-gate int
cachefs_readlink_back(cnode_t * cp,cred_t * cr,caddr_t * bufp,int * buflenp)18700Sstevel@tonic-gate cachefs_readlink_back(cnode_t *cp, cred_t *cr, caddr_t *bufp, int *buflenp)
18710Sstevel@tonic-gate {
18720Sstevel@tonic-gate int error;
18730Sstevel@tonic-gate struct uio uio;
18740Sstevel@tonic-gate struct iovec iov;
18750Sstevel@tonic-gate caddr_t buf;
18760Sstevel@tonic-gate fscache_t *fscp = C_TO_FSCACHE(cp);
18770Sstevel@tonic-gate
18780Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cp->c_statelock));
18790Sstevel@tonic-gate
18800Sstevel@tonic-gate *bufp = NULL;
18810Sstevel@tonic-gate
18820Sstevel@tonic-gate /* get back vnode */
18830Sstevel@tonic-gate if (cp->c_backvp == NULL) {
18840Sstevel@tonic-gate error = cachefs_getbackvp(fscp, cp);
18850Sstevel@tonic-gate if (error)
18860Sstevel@tonic-gate return (error);
18870Sstevel@tonic-gate }
18880Sstevel@tonic-gate
18890Sstevel@tonic-gate /* set up for the readlink */
18900Sstevel@tonic-gate bzero(&uio, sizeof (struct uio));
18910Sstevel@tonic-gate bzero(&iov, sizeof (struct iovec));
18920Sstevel@tonic-gate buf = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
18930Sstevel@tonic-gate iov.iov_base = buf;
18940Sstevel@tonic-gate iov.iov_len = MAXPATHLEN;
18950Sstevel@tonic-gate uio.uio_iov = &iov;
18960Sstevel@tonic-gate uio.uio_iovcnt = 1;
18970Sstevel@tonic-gate uio.uio_resid = MAXPATHLEN;
18980Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE;
18990Sstevel@tonic-gate uio.uio_loffset = 0;
19000Sstevel@tonic-gate uio.uio_fmode = 0;
19010Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED;
19020Sstevel@tonic-gate uio.uio_llimit = MAXOFFSET_T;
19030Sstevel@tonic-gate
19040Sstevel@tonic-gate /* get the link data */
19050Sstevel@tonic-gate CFS_DPRINT_BACKFS_NFSV4(fscp,
1906*11066Srafael.vanoni@sun.com ("cachefs_readlink (nfsv4): cnode %p, backvp %p\n",
1907*11066Srafael.vanoni@sun.com cp, cp->c_backvp));
19085331Samw error = VOP_READLINK(cp->c_backvp, &uio, cr, NULL);
19090Sstevel@tonic-gate if (error) {
19100Sstevel@tonic-gate cachefs_kmem_free(buf, MAXPATHLEN);
19110Sstevel@tonic-gate } else {
19120Sstevel@tonic-gate *bufp = buf;
19130Sstevel@tonic-gate /*LINTED alignment okay*/
19140Sstevel@tonic-gate *buflenp = MAXPATHLEN - (int)uio.uio_resid;
19150Sstevel@tonic-gate }
19160Sstevel@tonic-gate
19170Sstevel@tonic-gate return (error);
19180Sstevel@tonic-gate }
19190Sstevel@tonic-gate
19200Sstevel@tonic-gate int
cachefs_getbackvp(struct fscache * fscp,struct cnode * cp)19210Sstevel@tonic-gate cachefs_getbackvp(struct fscache *fscp, struct cnode *cp)
19220Sstevel@tonic-gate {
19230Sstevel@tonic-gate int error = 0;
19240Sstevel@tonic-gate int flag;
19250Sstevel@tonic-gate
19260Sstevel@tonic-gate #ifdef CFSDEBUG
19270Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_CHEAT | CFSDEBUG_BACK)
19280Sstevel@tonic-gate printf("cachefs_getbackvp: ENTER fscp %p cp %p\n",
19290Sstevel@tonic-gate (void *)fscp, (void *)cp);
19300Sstevel@tonic-gate #endif
19310Sstevel@tonic-gate ASSERT(cp != NULL);
19320Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cp->c_statelock));
19330Sstevel@tonic-gate ASSERT(cp->c_backvp == NULL);
19340Sstevel@tonic-gate ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
19350Sstevel@tonic-gate
19360Sstevel@tonic-gate /*
19370Sstevel@tonic-gate * If destroy is set then the last link to a file has been
19380Sstevel@tonic-gate * removed. Oddly enough NFS will still return a vnode
19390Sstevel@tonic-gate * for the file if the timeout has not expired.
19400Sstevel@tonic-gate * This causes headaches for cachefs_push because the
19410Sstevel@tonic-gate * vnode is really stale.
19420Sstevel@tonic-gate * So we just short circuit the problem here.
19430Sstevel@tonic-gate */
19440Sstevel@tonic-gate if (cp->c_flags & CN_DESTROY)
19450Sstevel@tonic-gate return (ESTALE);
19460Sstevel@tonic-gate
19470Sstevel@tonic-gate ASSERT(fscp->fs_backvfsp);
19480Sstevel@tonic-gate if (fscp->fs_backvfsp == NULL)
19490Sstevel@tonic-gate return (ETIMEDOUT);
19500Sstevel@tonic-gate error = VFS_VGET(fscp->fs_backvfsp, &cp->c_backvp,
19510Sstevel@tonic-gate (struct fid *)&cp->c_cookie);
19520Sstevel@tonic-gate if (cp->c_backvp && cp->c_cred &&
19530Sstevel@tonic-gate ((cp->c_flags & CN_NEEDOPEN) || (cp->c_attr.va_type == VREG))) {
19540Sstevel@tonic-gate /*
19550Sstevel@tonic-gate * XXX bob: really should pass in the correct flag,
19560Sstevel@tonic-gate * fortunately nobody pays attention to it
19570Sstevel@tonic-gate */
19580Sstevel@tonic-gate flag = 0;
19590Sstevel@tonic-gate /*
19600Sstevel@tonic-gate * If NEEDOOPEN is set, then this file was opened VOP_OPEN'd
19610Sstevel@tonic-gate * but the backvp was not. So, for the sake of the vnode
19620Sstevel@tonic-gate * open counts used by delegation, we need to OPEN the backvp
19630Sstevel@tonic-gate * with the same flags that were used for this cnode. That way
19640Sstevel@tonic-gate * when the file is VOP_CLOSE'd the counts won't go negative.
19650Sstevel@tonic-gate */
19660Sstevel@tonic-gate if (cp->c_flags & CN_NEEDOPEN) {
19670Sstevel@tonic-gate cp->c_flags &= ~CN_NEEDOPEN;
19680Sstevel@tonic-gate if (cp->c_rdcnt > 0) {
19690Sstevel@tonic-gate cp->c_rdcnt--;
19700Sstevel@tonic-gate flag |= FREAD;
19710Sstevel@tonic-gate }
19720Sstevel@tonic-gate if (cp->c_wrcnt > 0) {
19730Sstevel@tonic-gate cp->c_wrcnt--;
19740Sstevel@tonic-gate flag |= FWRITE;
19750Sstevel@tonic-gate }
19760Sstevel@tonic-gate }
19775331Samw error = VOP_OPEN(&cp->c_backvp, flag, cp->c_cred, NULL);
19780Sstevel@tonic-gate if (error) {
19790Sstevel@tonic-gate VN_RELE(cp->c_backvp);
19800Sstevel@tonic-gate cp->c_backvp = NULL;
19810Sstevel@tonic-gate }
19820Sstevel@tonic-gate }
19830Sstevel@tonic-gate
19840Sstevel@tonic-gate #ifdef CFSDEBUG
19850Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_GENERAL | CFSDEBUG_BACK) {
19860Sstevel@tonic-gate if (error || cp->c_backvp == NULL) {
19870Sstevel@tonic-gate printf("Stale cookie cp %p fileno %llu type %d \n",
19880Sstevel@tonic-gate (void *)cp, (u_longlong_t)cp->c_id.cid_fileno,
19890Sstevel@tonic-gate CTOV(cp)->v_type);
19900Sstevel@tonic-gate }
19910Sstevel@tonic-gate }
19920Sstevel@tonic-gate #endif
19930Sstevel@tonic-gate
19940Sstevel@tonic-gate #ifdef CFSDEBUG
19950Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_CHEAT | CFSDEBUG_BACK)
19960Sstevel@tonic-gate printf("cachefs_getbackvp: EXIT error = %d\n", error);
19970Sstevel@tonic-gate #endif
19980Sstevel@tonic-gate return (error);
19990Sstevel@tonic-gate }
20000Sstevel@tonic-gate
20010Sstevel@tonic-gate int
cachefs_getcookie(vnode_t * vp,struct fid * cookiep,struct vattr * attrp,cred_t * cr,uint32_t valid_fid)20020Sstevel@tonic-gate cachefs_getcookie(
20030Sstevel@tonic-gate vnode_t *vp,
20040Sstevel@tonic-gate struct fid *cookiep,
20050Sstevel@tonic-gate struct vattr *attrp,
20060Sstevel@tonic-gate cred_t *cr,
20070Sstevel@tonic-gate uint32_t valid_fid)
20080Sstevel@tonic-gate {
20090Sstevel@tonic-gate int error = 0;
20100Sstevel@tonic-gate
20110Sstevel@tonic-gate #ifdef CFSDEBUG
20120Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_CHEAT)
20130Sstevel@tonic-gate printf("cachefs_getcookie: ENTER vp %p\n", (void *)vp);
20140Sstevel@tonic-gate #endif
20150Sstevel@tonic-gate /*
20160Sstevel@tonic-gate * Get the FID only if the caller has indicated it is valid,
20170Sstevel@tonic-gate * otherwise, zero the cookie.
20180Sstevel@tonic-gate */
20190Sstevel@tonic-gate if (valid_fid) {
20200Sstevel@tonic-gate /*
20210Sstevel@tonic-gate * This assumes that the cookie is a full size fid, if we go to
20220Sstevel@tonic-gate * variable length fids we will need to change this.
20230Sstevel@tonic-gate */
20240Sstevel@tonic-gate cookiep->fid_len = MAXFIDSZ;
20255331Samw error = VOP_FID(vp, cookiep, NULL);
20260Sstevel@tonic-gate } else {
20270Sstevel@tonic-gate bzero(cookiep, sizeof (*cookiep));
20280Sstevel@tonic-gate }
20290Sstevel@tonic-gate
20300Sstevel@tonic-gate if (!error) {
20310Sstevel@tonic-gate if (attrp) {
20320Sstevel@tonic-gate ASSERT(attrp != NULL);
20330Sstevel@tonic-gate attrp->va_mask = AT_ALL;
20345331Samw error = VOP_GETATTR(vp, attrp, 0, cr, NULL);
20350Sstevel@tonic-gate }
20360Sstevel@tonic-gate } else {
20370Sstevel@tonic-gate if (error == ENOSPC) {
20380Sstevel@tonic-gate /*
20390Sstevel@tonic-gate * This is an indication that the underlying filesystem
20400Sstevel@tonic-gate * needs a bigger fid. For now just map to EINVAL.
20410Sstevel@tonic-gate */
20420Sstevel@tonic-gate error = EINVAL;
20430Sstevel@tonic-gate }
20440Sstevel@tonic-gate }
20450Sstevel@tonic-gate #ifdef CFSDEBUG
20460Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_CHEAT)
20470Sstevel@tonic-gate printf("cachefs_getcookie: EXIT error = %d\n", error);
20480Sstevel@tonic-gate #endif
20490Sstevel@tonic-gate return (error);
20500Sstevel@tonic-gate }
20510Sstevel@tonic-gate
20520Sstevel@tonic-gate void
cachefs_workq_init(struct cachefs_workq * qp)20530Sstevel@tonic-gate cachefs_workq_init(struct cachefs_workq *qp)
20540Sstevel@tonic-gate {
20550Sstevel@tonic-gate qp->wq_head = qp->wq_tail = NULL;
20560Sstevel@tonic-gate qp->wq_length =
20570Sstevel@tonic-gate qp->wq_thread_count =
20580Sstevel@tonic-gate qp->wq_max_len =
20590Sstevel@tonic-gate qp->wq_halt_request = 0;
20600Sstevel@tonic-gate qp->wq_keepone = 0;
20610Sstevel@tonic-gate cv_init(&qp->wq_req_cv, NULL, CV_DEFAULT, NULL);
20620Sstevel@tonic-gate cv_init(&qp->wq_halt_cv, NULL, CV_DEFAULT, NULL);
20630Sstevel@tonic-gate mutex_init(&qp->wq_queue_lock, NULL, MUTEX_DEFAULT, NULL);
20640Sstevel@tonic-gate }
20650Sstevel@tonic-gate
20660Sstevel@tonic-gate /*
20670Sstevel@tonic-gate * return non-zero if it's `okay' to queue more requests (policy)
20680Sstevel@tonic-gate */
20690Sstevel@tonic-gate
20700Sstevel@tonic-gate static int cachefs_async_max = 512;
20710Sstevel@tonic-gate static int cachefs_async_count = 0;
20720Sstevel@tonic-gate kmutex_t cachefs_async_lock;
20730Sstevel@tonic-gate
20740Sstevel@tonic-gate int
cachefs_async_okay(void)20750Sstevel@tonic-gate cachefs_async_okay(void)
20760Sstevel@tonic-gate {
20770Sstevel@tonic-gate /*
20780Sstevel@tonic-gate * a value of -1 for max means to ignore freemem
20790Sstevel@tonic-gate */
20800Sstevel@tonic-gate
20810Sstevel@tonic-gate if (cachefs_async_max == -1)
20820Sstevel@tonic-gate return (1);
20830Sstevel@tonic-gate
20840Sstevel@tonic-gate if (freemem < minfree)
20850Sstevel@tonic-gate return (0);
20860Sstevel@tonic-gate
20870Sstevel@tonic-gate /*
20880Sstevel@tonic-gate * a value of 0 for max means no arbitrary limit (only `freemen')
20890Sstevel@tonic-gate */
20900Sstevel@tonic-gate
20910Sstevel@tonic-gate if (cachefs_async_max == 0)
20920Sstevel@tonic-gate return (1);
20930Sstevel@tonic-gate
20940Sstevel@tonic-gate ASSERT(cachefs_async_max > 0);
20950Sstevel@tonic-gate
20960Sstevel@tonic-gate /*
20970Sstevel@tonic-gate * check the global count against the max.
20980Sstevel@tonic-gate *
20990Sstevel@tonic-gate * we don't need to grab cachefs_async_lock -- we're just
21000Sstevel@tonic-gate * looking, and a little bit of `fuzz' is okay.
21010Sstevel@tonic-gate */
21020Sstevel@tonic-gate
21030Sstevel@tonic-gate if (cachefs_async_count >= cachefs_async_max)
21040Sstevel@tonic-gate return (0);
21050Sstevel@tonic-gate
21060Sstevel@tonic-gate return (1);
21070Sstevel@tonic-gate }
21080Sstevel@tonic-gate
21090Sstevel@tonic-gate void
cachefs_async_start(struct cachefs_workq * qp)21100Sstevel@tonic-gate cachefs_async_start(struct cachefs_workq *qp)
21110Sstevel@tonic-gate {
21120Sstevel@tonic-gate struct cachefs_req *rp;
21130Sstevel@tonic-gate int left;
21140Sstevel@tonic-gate callb_cpr_t cprinfo;
21150Sstevel@tonic-gate
21160Sstevel@tonic-gate CALLB_CPR_INIT(&cprinfo, &qp->wq_queue_lock, callb_generic_cpr, "cas");
21170Sstevel@tonic-gate mutex_enter(&qp->wq_queue_lock);
21180Sstevel@tonic-gate left = 1;
21190Sstevel@tonic-gate for (;;) {
21200Sstevel@tonic-gate /* if there are no pending requests */
21210Sstevel@tonic-gate if ((qp->wq_head == NULL) && (qp->wq_logwork == 0)) {
21220Sstevel@tonic-gate /* see if thread should exit */
21230Sstevel@tonic-gate if (qp->wq_halt_request || (left == -1)) {
21240Sstevel@tonic-gate if ((qp->wq_thread_count > 1) ||
21250Sstevel@tonic-gate (qp->wq_keepone == 0))
21260Sstevel@tonic-gate break;
21270Sstevel@tonic-gate }
21280Sstevel@tonic-gate
21290Sstevel@tonic-gate /* wake up thread in async_halt if necessary */
21300Sstevel@tonic-gate if (qp->wq_halt_request)
21310Sstevel@tonic-gate cv_broadcast(&qp->wq_halt_cv);
21320Sstevel@tonic-gate
21330Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo);
21340Sstevel@tonic-gate /* sleep until there is something to do */
2135*11066Srafael.vanoni@sun.com left = cv_reltimedwait(&qp->wq_req_cv,
2136*11066Srafael.vanoni@sun.com &qp->wq_queue_lock, CFS_ASYNC_TIMEOUT,
2137*11066Srafael.vanoni@sun.com TR_CLOCK_TICK);
2138*11066Srafael.vanoni@sun.com CALLB_CPR_SAFE_END(&cprinfo, &qp->wq_queue_lock);
21390Sstevel@tonic-gate if ((qp->wq_head == NULL) && (qp->wq_logwork == 0))
21400Sstevel@tonic-gate continue;
21410Sstevel@tonic-gate }
21420Sstevel@tonic-gate left = 1;
21430Sstevel@tonic-gate
21440Sstevel@tonic-gate if (qp->wq_logwork) {
21450Sstevel@tonic-gate qp->wq_logwork = 0;
21460Sstevel@tonic-gate mutex_exit(&qp->wq_queue_lock);
21470Sstevel@tonic-gate cachefs_log_process_queue(qp->wq_cachep, 1);
21480Sstevel@tonic-gate mutex_enter(&qp->wq_queue_lock);
21490Sstevel@tonic-gate continue;
21500Sstevel@tonic-gate }
21510Sstevel@tonic-gate
21520Sstevel@tonic-gate /* remove request from the list */
21530Sstevel@tonic-gate rp = qp->wq_head;
21540Sstevel@tonic-gate qp->wq_head = rp->cfs_next;
21550Sstevel@tonic-gate if (rp->cfs_next == NULL)
21560Sstevel@tonic-gate qp->wq_tail = NULL;
21570Sstevel@tonic-gate
21580Sstevel@tonic-gate /* do the request */
21590Sstevel@tonic-gate mutex_exit(&qp->wq_queue_lock);
21600Sstevel@tonic-gate cachefs_do_req(rp);
21610Sstevel@tonic-gate mutex_enter(&qp->wq_queue_lock);
21620Sstevel@tonic-gate
21630Sstevel@tonic-gate /* decrement count of requests */
21640Sstevel@tonic-gate qp->wq_length--;
21650Sstevel@tonic-gate mutex_enter(&cachefs_async_lock);
21660Sstevel@tonic-gate --cachefs_async_count;
21670Sstevel@tonic-gate mutex_exit(&cachefs_async_lock);
21680Sstevel@tonic-gate }
21690Sstevel@tonic-gate ASSERT(qp->wq_head == NULL);
21700Sstevel@tonic-gate qp->wq_thread_count--;
21710Sstevel@tonic-gate if (qp->wq_halt_request && qp->wq_thread_count == 0)
21720Sstevel@tonic-gate cv_broadcast(&qp->wq_halt_cv);
21730Sstevel@tonic-gate CALLB_CPR_EXIT(&cprinfo);
21740Sstevel@tonic-gate thread_exit();
21750Sstevel@tonic-gate /*NOTREACHED*/
21760Sstevel@tonic-gate }
21770Sstevel@tonic-gate
21780Sstevel@tonic-gate /*
21790Sstevel@tonic-gate * attempt to halt all the async threads associated with a given workq
21800Sstevel@tonic-gate */
21810Sstevel@tonic-gate int
cachefs_async_halt(struct cachefs_workq * qp,int force)21820Sstevel@tonic-gate cachefs_async_halt(struct cachefs_workq *qp, int force)
21830Sstevel@tonic-gate {
21840Sstevel@tonic-gate int error = 0;
21850Sstevel@tonic-gate
21860Sstevel@tonic-gate mutex_enter(&qp->wq_queue_lock);
21870Sstevel@tonic-gate if (force)
21880Sstevel@tonic-gate qp->wq_keepone = 0;
21890Sstevel@tonic-gate
21900Sstevel@tonic-gate if (qp->wq_thread_count > 0) {
21910Sstevel@tonic-gate qp->wq_halt_request++;
21920Sstevel@tonic-gate cv_broadcast(&qp->wq_req_cv);
2193*11066Srafael.vanoni@sun.com (void) cv_reltimedwait(&qp->wq_halt_cv,
2194*11066Srafael.vanoni@sun.com &qp->wq_queue_lock, (60 * hz), TR_CLOCK_TICK);
21950Sstevel@tonic-gate qp->wq_halt_request--;
21960Sstevel@tonic-gate if (qp->wq_thread_count > 0) {
21970Sstevel@tonic-gate if ((qp->wq_thread_count == 1) &&
21980Sstevel@tonic-gate (qp->wq_length == 0) && qp->wq_keepone)
21990Sstevel@tonic-gate error = EAGAIN;
22000Sstevel@tonic-gate else
22010Sstevel@tonic-gate error = EBUSY;
22020Sstevel@tonic-gate } else {
22030Sstevel@tonic-gate ASSERT(qp->wq_length == 0 && qp->wq_head == NULL);
22040Sstevel@tonic-gate }
22050Sstevel@tonic-gate }
22060Sstevel@tonic-gate mutex_exit(&qp->wq_queue_lock);
22070Sstevel@tonic-gate return (error);
22080Sstevel@tonic-gate }
22090Sstevel@tonic-gate
22100Sstevel@tonic-gate void
cachefs_addqueue(struct cachefs_req * rp,struct cachefs_workq * qp)22110Sstevel@tonic-gate cachefs_addqueue(struct cachefs_req *rp, struct cachefs_workq *qp)
22120Sstevel@tonic-gate {
22130Sstevel@tonic-gate mutex_enter(&qp->wq_queue_lock);
22140Sstevel@tonic-gate if (qp->wq_thread_count < cachefs_max_threads) {
22150Sstevel@tonic-gate if (qp->wq_thread_count == 0 ||
22160Sstevel@tonic-gate (qp->wq_length >= (qp->wq_thread_count * 2))) {
22170Sstevel@tonic-gate (void) thread_create(NULL, 0, cachefs_async_start,
22180Sstevel@tonic-gate qp, 0, &p0, TS_RUN, minclsyspri);
22190Sstevel@tonic-gate qp->wq_thread_count++;
22200Sstevel@tonic-gate }
22210Sstevel@tonic-gate }
22220Sstevel@tonic-gate mutex_enter(&rp->cfs_req_lock);
22230Sstevel@tonic-gate if (qp->wq_tail)
22240Sstevel@tonic-gate qp->wq_tail->cfs_next = rp;
22250Sstevel@tonic-gate else
22260Sstevel@tonic-gate qp->wq_head = rp;
22270Sstevel@tonic-gate qp->wq_tail = rp;
22280Sstevel@tonic-gate rp->cfs_next = NULL;
22290Sstevel@tonic-gate qp->wq_length++;
22300Sstevel@tonic-gate if (qp->wq_length > qp->wq_max_len)
22310Sstevel@tonic-gate qp->wq_max_len = qp->wq_length;
22320Sstevel@tonic-gate mutex_enter(&cachefs_async_lock);
22330Sstevel@tonic-gate ++cachefs_async_count;
22340Sstevel@tonic-gate mutex_exit(&cachefs_async_lock);
22350Sstevel@tonic-gate
22360Sstevel@tonic-gate cv_signal(&qp->wq_req_cv);
22370Sstevel@tonic-gate mutex_exit(&rp->cfs_req_lock);
22380Sstevel@tonic-gate mutex_exit(&qp->wq_queue_lock);
22390Sstevel@tonic-gate }
22400Sstevel@tonic-gate
22410Sstevel@tonic-gate void
cachefs_async_putpage(struct cachefs_putpage_req * prp,cred_t * cr)22420Sstevel@tonic-gate cachefs_async_putpage(struct cachefs_putpage_req *prp, cred_t *cr)
22430Sstevel@tonic-gate {
22440Sstevel@tonic-gate struct cnode *cp = VTOC(prp->cp_vp);
22450Sstevel@tonic-gate
22460Sstevel@tonic-gate ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(cp)) == 0);
22470Sstevel@tonic-gate
22480Sstevel@tonic-gate (void) VOP_PUTPAGE(prp->cp_vp, prp->cp_off, prp->cp_len,
2249*11066Srafael.vanoni@sun.com prp->cp_flags, cr, NULL);
22500Sstevel@tonic-gate
22510Sstevel@tonic-gate mutex_enter(&cp->c_iomutex);
22520Sstevel@tonic-gate if (--cp->c_nio == 0)
22530Sstevel@tonic-gate cv_broadcast(&cp->c_iocv);
22540Sstevel@tonic-gate if (prp->cp_off == 0 && prp->cp_len == 0 &&
22550Sstevel@tonic-gate (cp->c_ioflags & CIO_PUTPAGES)) {
22560Sstevel@tonic-gate cp->c_ioflags &= ~CIO_PUTPAGES;
22570Sstevel@tonic-gate }
22580Sstevel@tonic-gate mutex_exit(&cp->c_iomutex);
22590Sstevel@tonic-gate }
22600Sstevel@tonic-gate
22610Sstevel@tonic-gate void
cachefs_async_populate(struct cachefs_populate_req * pop,cred_t * cr)22620Sstevel@tonic-gate cachefs_async_populate(struct cachefs_populate_req *pop, cred_t *cr)
22630Sstevel@tonic-gate {
22640Sstevel@tonic-gate struct cnode *cp = VTOC(pop->cpop_vp);
22650Sstevel@tonic-gate struct fscache *fscp = C_TO_FSCACHE(cp);
22660Sstevel@tonic-gate struct filegrp *fgp = cp->c_filegrp;
22670Sstevel@tonic-gate int error = 0; /* not returned -- used as a place-holder */
22680Sstevel@tonic-gate vnode_t *frontvp = NULL, *backvp = NULL;
22690Sstevel@tonic-gate int havelock = 0;
22700Sstevel@tonic-gate vattr_t va;
22710Sstevel@tonic-gate
22720Sstevel@tonic-gate ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
22730Sstevel@tonic-gate
22740Sstevel@tonic-gate if (((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0) ||
22750Sstevel@tonic-gate (fscp->fs_cdconnected != CFS_CD_CONNECTED)) {
22760Sstevel@tonic-gate mutex_enter(&cp->c_statelock);
22770Sstevel@tonic-gate cp->c_flags &= ~CN_ASYNC_POPULATE;
22780Sstevel@tonic-gate mutex_exit(&cp->c_statelock);
22790Sstevel@tonic-gate return; /* goto out */
22800Sstevel@tonic-gate }
22810Sstevel@tonic-gate
22820Sstevel@tonic-gate error = cachefs_cd_access(fscp, 0, 0);
22830Sstevel@tonic-gate if (error) {
22840Sstevel@tonic-gate #ifdef CFSDEBUG
22850Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_ASYNCPOP)
22860Sstevel@tonic-gate printf("async_pop: cd_access: err %d con %d\n",
22870Sstevel@tonic-gate error, fscp->fs_cdconnected);
22880Sstevel@tonic-gate #endif /* CFSDEBUG */
22890Sstevel@tonic-gate mutex_enter(&cp->c_statelock);
22900Sstevel@tonic-gate cp->c_flags &= ~CN_ASYNC_POPULATE;
22910Sstevel@tonic-gate mutex_exit(&cp->c_statelock);
22920Sstevel@tonic-gate return; /* goto out */
22930Sstevel@tonic-gate }
22940Sstevel@tonic-gate
22950Sstevel@tonic-gate /*
22960Sstevel@tonic-gate * grab the statelock for some minimal things
22970Sstevel@tonic-gate */
22980Sstevel@tonic-gate
22990Sstevel@tonic-gate rw_enter(&cp->c_rwlock, RW_WRITER);
23000Sstevel@tonic-gate mutex_enter(&cp->c_statelock);
23010Sstevel@tonic-gate havelock = 1;
23020Sstevel@tonic-gate
23030Sstevel@tonic-gate if ((cp->c_flags & CN_ASYNC_POPULATE) == 0)
23040Sstevel@tonic-gate goto out;
23050Sstevel@tonic-gate
23060Sstevel@tonic-gate /* there can be only one */
23070Sstevel@tonic-gate ASSERT((cp->c_flags & CN_ASYNC_POP_WORKING) == 0);
23080Sstevel@tonic-gate cp->c_flags |= CN_ASYNC_POP_WORKING;
23090Sstevel@tonic-gate cp->c_popthrp = curthread;
23100Sstevel@tonic-gate
23110Sstevel@tonic-gate if (cp->c_metadata.md_flags & MD_POPULATED)
23120Sstevel@tonic-gate goto out;
23130Sstevel@tonic-gate
23140Sstevel@tonic-gate if (cp->c_flags & CN_NOCACHE) {
23150Sstevel@tonic-gate #ifdef CFSDEBUG
23160Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_ASYNCPOP)
23170Sstevel@tonic-gate printf("cachefs_async_populate: nocache bit on\n");
23180Sstevel@tonic-gate #endif /* CFSDEBUG */
23190Sstevel@tonic-gate error = EINVAL;
23200Sstevel@tonic-gate goto out;
23210Sstevel@tonic-gate }
23220Sstevel@tonic-gate
23230Sstevel@tonic-gate if (cp->c_frontvp == NULL) {
23240Sstevel@tonic-gate if ((cp->c_metadata.md_flags & MD_FILE) == 0) {
23250Sstevel@tonic-gate struct cfs_cid cid = cp->c_id;
23260Sstevel@tonic-gate
23270Sstevel@tonic-gate mutex_exit(&cp->c_statelock);
23280Sstevel@tonic-gate havelock = 0;
23290Sstevel@tonic-gate
23300Sstevel@tonic-gate /*
23310Sstevel@tonic-gate * if frontfile doesn't exist, drop the lock
23320Sstevel@tonic-gate * to do some of the file creation stuff.
23330Sstevel@tonic-gate */
23340Sstevel@tonic-gate
23350Sstevel@tonic-gate if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
23360Sstevel@tonic-gate error = filegrp_allocattr(fgp);
23370Sstevel@tonic-gate if (error != 0)
23380Sstevel@tonic-gate goto out;
23390Sstevel@tonic-gate }
23400Sstevel@tonic-gate if (fgp->fg_flags & CFS_FG_ALLOC_FILE) {
23410Sstevel@tonic-gate mutex_enter(&fgp->fg_mutex);
23420Sstevel@tonic-gate if (fgp->fg_flags & CFS_FG_ALLOC_FILE) {
23430Sstevel@tonic-gate if (fgp->fg_header->ach_nffs == 0)
23440Sstevel@tonic-gate error = filegrpdir_create(fgp);
23450Sstevel@tonic-gate else
23460Sstevel@tonic-gate error = filegrpdir_find(fgp);
23470Sstevel@tonic-gate if (error != 0) {
23480Sstevel@tonic-gate mutex_exit(&fgp->fg_mutex);
23490Sstevel@tonic-gate goto out;
23500Sstevel@tonic-gate }
23510Sstevel@tonic-gate }
23520Sstevel@tonic-gate mutex_exit(&fgp->fg_mutex);
23530Sstevel@tonic-gate }
23540Sstevel@tonic-gate
23550Sstevel@tonic-gate if (fgp->fg_dirvp != NULL) {
23560Sstevel@tonic-gate char name[CFS_FRONTFILE_NAME_SIZE];
23570Sstevel@tonic-gate struct vattr *attrp;
23580Sstevel@tonic-gate
23590Sstevel@tonic-gate attrp = cachefs_kmem_zalloc(
23600Sstevel@tonic-gate sizeof (struct vattr), KM_SLEEP);
23610Sstevel@tonic-gate attrp->va_mode = S_IFREG | 0666;
23620Sstevel@tonic-gate attrp->va_uid = 0;
23630Sstevel@tonic-gate attrp->va_gid = 0;
23640Sstevel@tonic-gate attrp->va_type = VREG;
23650Sstevel@tonic-gate attrp->va_size = 0;
23660Sstevel@tonic-gate attrp->va_mask =
23670Sstevel@tonic-gate AT_SIZE | AT_TYPE | AT_MODE |
23680Sstevel@tonic-gate AT_UID | AT_GID;
23690Sstevel@tonic-gate
23700Sstevel@tonic-gate make_ascii_name(&cid, name);
23710Sstevel@tonic-gate
23720Sstevel@tonic-gate (void) VOP_CREATE(fgp->fg_dirvp, name, attrp,
23735331Samw EXCL, 0666, &frontvp, kcred, 0, NULL, NULL);
23740Sstevel@tonic-gate
23750Sstevel@tonic-gate cachefs_kmem_free(attrp,
23760Sstevel@tonic-gate sizeof (struct vattr));
23770Sstevel@tonic-gate }
23780Sstevel@tonic-gate
23790Sstevel@tonic-gate mutex_enter(&cp->c_statelock);
23800Sstevel@tonic-gate havelock = 1;
23810Sstevel@tonic-gate }
23820Sstevel@tonic-gate error = cachefs_getfrontfile(cp);
23830Sstevel@tonic-gate ASSERT((error != 0) ||
23840Sstevel@tonic-gate (frontvp == NULL) ||
23850Sstevel@tonic-gate (frontvp == cp->c_frontvp));
23860Sstevel@tonic-gate }
23870Sstevel@tonic-gate if ((error != 0) || (cp->c_frontvp == NULL))
23880Sstevel@tonic-gate goto out;
23890Sstevel@tonic-gate
23900Sstevel@tonic-gate if (frontvp != NULL)
23910Sstevel@tonic-gate VN_RELE(frontvp);
23920Sstevel@tonic-gate
23930Sstevel@tonic-gate frontvp = cp->c_frontvp;
23940Sstevel@tonic-gate VN_HOLD(frontvp);
23950Sstevel@tonic-gate
23960Sstevel@tonic-gate if (cp->c_backvp == NULL) {
23970Sstevel@tonic-gate error = cachefs_getbackvp(fscp, cp);
23980Sstevel@tonic-gate if ((error != 0) || (cp->c_backvp == NULL))
23990Sstevel@tonic-gate goto out;
24000Sstevel@tonic-gate }
24010Sstevel@tonic-gate backvp = cp->c_backvp;
24020Sstevel@tonic-gate VN_HOLD(backvp);
24030Sstevel@tonic-gate
24040Sstevel@tonic-gate switch (pop->cpop_vp->v_type) {
24050Sstevel@tonic-gate case VREG:
24060Sstevel@tonic-gate mutex_exit(&cp->c_statelock);
24070Sstevel@tonic-gate havelock = 0;
24080Sstevel@tonic-gate error = cachefs_async_populate_reg(pop, cr, backvp, frontvp);
24090Sstevel@tonic-gate break;
24100Sstevel@tonic-gate case VDIR:
24110Sstevel@tonic-gate error = cachefs_async_populate_dir(pop, cr, backvp, frontvp);
24120Sstevel@tonic-gate mutex_exit(&cp->c_statelock);
24130Sstevel@tonic-gate havelock = 0;
24140Sstevel@tonic-gate break;
24150Sstevel@tonic-gate default:
24160Sstevel@tonic-gate #ifdef CFSDEBUG
24170Sstevel@tonic-gate printf("cachefs_async_populate: warning: vnode type = %d\n",
24180Sstevel@tonic-gate pop->cpop_vp->v_type);
24190Sstevel@tonic-gate ASSERT(0);
24200Sstevel@tonic-gate #endif /* CFSDEBUG */
24210Sstevel@tonic-gate error = EINVAL;
24220Sstevel@tonic-gate break;
24230Sstevel@tonic-gate }
24240Sstevel@tonic-gate
24250Sstevel@tonic-gate if (error != 0)
24260Sstevel@tonic-gate goto out;
24270Sstevel@tonic-gate
24285331Samw error = VOP_FSYNC(frontvp, FSYNC, cr, NULL);
24290Sstevel@tonic-gate if (error != 0) {
24300Sstevel@tonic-gate #ifdef CFSDEBUG
24310Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_ASYNCPOP)
24320Sstevel@tonic-gate printf("cachefs_async_populate: fsync\n");
24330Sstevel@tonic-gate #endif /* CFSDEBUG */
24340Sstevel@tonic-gate goto out;
24350Sstevel@tonic-gate }
24360Sstevel@tonic-gate
24370Sstevel@tonic-gate /* grab the lock and finish up */
24380Sstevel@tonic-gate mutex_enter(&cp->c_statelock);
24390Sstevel@tonic-gate havelock = 1;
24400Sstevel@tonic-gate
24410Sstevel@tonic-gate /* if went nocache while lock was dropped, get out */
24420Sstevel@tonic-gate if ((cp->c_flags & CN_NOCACHE) || (cp->c_frontvp == NULL)) {
24430Sstevel@tonic-gate error = EINVAL;
24440Sstevel@tonic-gate goto out;
24450Sstevel@tonic-gate }
24460Sstevel@tonic-gate
24470Sstevel@tonic-gate va.va_mask = AT_MTIME;
24485331Samw error = VOP_GETATTR(cp->c_frontvp, &va, 0, cr, NULL);
24490Sstevel@tonic-gate if (error) {
24500Sstevel@tonic-gate #ifdef CFSDEBUG
24510Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_ASYNCPOP)
24520Sstevel@tonic-gate printf("cachefs_async_populate: getattr\n");
24530Sstevel@tonic-gate #endif /* CFSDEBUG */
24540Sstevel@tonic-gate goto out;
24550Sstevel@tonic-gate }
24560Sstevel@tonic-gate cp->c_metadata.md_timestamp = va.va_mtime;
24570Sstevel@tonic-gate cp->c_metadata.md_flags |= MD_POPULATED;
24580Sstevel@tonic-gate cp->c_metadata.md_flags &= ~MD_INVALREADDIR;
24590Sstevel@tonic-gate cp->c_flags |= CN_UPDATED;
24600Sstevel@tonic-gate
24610Sstevel@tonic-gate out:
24620Sstevel@tonic-gate if (! havelock)
24630Sstevel@tonic-gate mutex_enter(&cp->c_statelock);
24640Sstevel@tonic-gate
24650Sstevel@tonic-gate /* see if an error happened behind our backs */
24660Sstevel@tonic-gate if ((error == 0) && (cp->c_flags & CN_NOCACHE)) {
24670Sstevel@tonic-gate #ifdef CFSDEBUG
24680Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_ASYNCPOP)
24690Sstevel@tonic-gate printf("cachefs_async_populate: "
24700Sstevel@tonic-gate "nocache behind our backs\n");
24710Sstevel@tonic-gate #endif /* CFSDEBUG */
24720Sstevel@tonic-gate error = EINVAL;
24730Sstevel@tonic-gate }
24740Sstevel@tonic-gate
24750Sstevel@tonic-gate cp->c_flags &= ~(CN_NEED_FRONT_SYNC | CN_POPULATION_PENDING |
24760Sstevel@tonic-gate CN_ASYNC_POPULATE | CN_ASYNC_POP_WORKING);
24770Sstevel@tonic-gate cp->c_popthrp = NULL;
24780Sstevel@tonic-gate
24790Sstevel@tonic-gate if (error != 0)
24800Sstevel@tonic-gate cachefs_nocache(cp);
24810Sstevel@tonic-gate
24820Sstevel@tonic-gate /* unblock any threads waiting for populate to finish */
24830Sstevel@tonic-gate cv_broadcast(&cp->c_popcv);
24840Sstevel@tonic-gate mutex_exit(&cp->c_statelock);
24850Sstevel@tonic-gate rw_exit(&cp->c_rwlock);
24860Sstevel@tonic-gate cachefs_cd_release(fscp);
24870Sstevel@tonic-gate
24880Sstevel@tonic-gate if (backvp != NULL) {
24890Sstevel@tonic-gate VN_RELE(backvp);
24900Sstevel@tonic-gate }
24910Sstevel@tonic-gate if (frontvp != NULL) {
24920Sstevel@tonic-gate VN_RELE(frontvp);
24930Sstevel@tonic-gate }
24940Sstevel@tonic-gate }
24950Sstevel@tonic-gate
24960Sstevel@tonic-gate /*
24970Sstevel@tonic-gate * only to be called from cachefs_async_populate
24980Sstevel@tonic-gate */
24990Sstevel@tonic-gate
25000Sstevel@tonic-gate static int
cachefs_async_populate_reg(struct cachefs_populate_req * pop,cred_t * cr,vnode_t * backvp,vnode_t * frontvp)25010Sstevel@tonic-gate cachefs_async_populate_reg(struct cachefs_populate_req *pop, cred_t *cr,
25020Sstevel@tonic-gate vnode_t *backvp, vnode_t *frontvp)
25030Sstevel@tonic-gate {
25040Sstevel@tonic-gate struct cnode *cp = VTOC(pop->cpop_vp);
25050Sstevel@tonic-gate int error = 0;
25060Sstevel@tonic-gate u_offset_t popoff;
25070Sstevel@tonic-gate size_t popsize;
25080Sstevel@tonic-gate
25090Sstevel@tonic-gate cachefs_cluster_allocmap(pop->cpop_off, &popoff,
25100Sstevel@tonic-gate &popsize, pop->cpop_size, cp);
25110Sstevel@tonic-gate if (popsize == 0) {
25120Sstevel@tonic-gate #ifdef CFSDEBUG
25130Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_ASYNCPOP)
25140Sstevel@tonic-gate printf("cachefs_async_populate: popsize == 0\n");
25150Sstevel@tonic-gate #endif /* CFSDEBUG */
25160Sstevel@tonic-gate goto out;
25170Sstevel@tonic-gate }
25180Sstevel@tonic-gate
25190Sstevel@tonic-gate error = cachefs_populate(cp, popoff, popsize, frontvp, backvp,
25200Sstevel@tonic-gate cp->c_size, cr);
25210Sstevel@tonic-gate if (error != 0) {
25220Sstevel@tonic-gate #ifdef CFSDEBUG
25230Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_ASYNCPOP)
25240Sstevel@tonic-gate printf("cachefs_async_populate: cachefs_populate\n");
25250Sstevel@tonic-gate #endif /* CFSDEBUG */
25260Sstevel@tonic-gate goto out;
25270Sstevel@tonic-gate }
25280Sstevel@tonic-gate
25290Sstevel@tonic-gate out:
25300Sstevel@tonic-gate return (error);
25310Sstevel@tonic-gate }
25320Sstevel@tonic-gate
25330Sstevel@tonic-gate void
cachefs_do_req(struct cachefs_req * rp)25340Sstevel@tonic-gate cachefs_do_req(struct cachefs_req *rp)
25350Sstevel@tonic-gate {
25360Sstevel@tonic-gate struct cachefscache *cachep;
25370Sstevel@tonic-gate
25380Sstevel@tonic-gate mutex_enter(&rp->cfs_req_lock);
25390Sstevel@tonic-gate switch (rp->cfs_cmd) {
25400Sstevel@tonic-gate case CFS_INVALID:
25410Sstevel@tonic-gate panic("cachefs_do_req: CFS_INVALID operation on queue");
25420Sstevel@tonic-gate /*NOTREACHED*/
25430Sstevel@tonic-gate case CFS_CACHE_SYNC:
25440Sstevel@tonic-gate cachep = rp->cfs_req_u.cu_fs_sync.cf_cachep;
25450Sstevel@tonic-gate cachefs_cache_sync(cachep);
25460Sstevel@tonic-gate break;
25470Sstevel@tonic-gate case CFS_IDLE:
25480Sstevel@tonic-gate cachefs_cnode_idle(rp->cfs_req_u.cu_idle.ci_vp, rp->cfs_cr);
25490Sstevel@tonic-gate break;
25500Sstevel@tonic-gate case CFS_PUTPAGE:
25510Sstevel@tonic-gate cachefs_async_putpage(&rp->cfs_req_u.cu_putpage, rp->cfs_cr);
25520Sstevel@tonic-gate VN_RELE(rp->cfs_req_u.cu_putpage.cp_vp);
25530Sstevel@tonic-gate break;
25540Sstevel@tonic-gate case CFS_POPULATE:
25550Sstevel@tonic-gate cachefs_async_populate(&rp->cfs_req_u.cu_populate, rp->cfs_cr);
25560Sstevel@tonic-gate VN_RELE(rp->cfs_req_u.cu_populate.cpop_vp);
25570Sstevel@tonic-gate break;
25580Sstevel@tonic-gate case CFS_NOOP:
25590Sstevel@tonic-gate break;
25600Sstevel@tonic-gate default:
25610Sstevel@tonic-gate panic("c_do_req: Invalid CFS async operation");
25620Sstevel@tonic-gate }
25630Sstevel@tonic-gate crfree(rp->cfs_cr);
25640Sstevel@tonic-gate rp->cfs_cmd = CFS_INVALID;
25650Sstevel@tonic-gate mutex_exit(&rp->cfs_req_lock);
25660Sstevel@tonic-gate kmem_cache_free(cachefs_req_cache, rp);
25670Sstevel@tonic-gate }
25680Sstevel@tonic-gate
25690Sstevel@tonic-gate
25700Sstevel@tonic-gate
25710Sstevel@tonic-gate
25720Sstevel@tonic-gate ssize_t cachefs_mem_usage = 0;
25730Sstevel@tonic-gate
25740Sstevel@tonic-gate struct km_wrap {
25750Sstevel@tonic-gate size_t kw_size;
25760Sstevel@tonic-gate struct km_wrap *kw_other;
25770Sstevel@tonic-gate };
25780Sstevel@tonic-gate
25790Sstevel@tonic-gate kmutex_t cachefs_kmem_lock;
25800Sstevel@tonic-gate
25810Sstevel@tonic-gate void *
cachefs_kmem_alloc(size_t size,int flag)25820Sstevel@tonic-gate cachefs_kmem_alloc(size_t size, int flag)
25830Sstevel@tonic-gate {
25840Sstevel@tonic-gate #ifdef DEBUG
25850Sstevel@tonic-gate caddr_t mp = NULL;
25860Sstevel@tonic-gate struct km_wrap *kwp;
25870Sstevel@tonic-gate size_t n = (size + (2 * sizeof (struct km_wrap)) + 7) & ~7;
25880Sstevel@tonic-gate
25890Sstevel@tonic-gate ASSERT(n >= (size + 8));
25900Sstevel@tonic-gate mp = kmem_alloc(n, flag);
25910Sstevel@tonic-gate if (mp == NULL) {
25920Sstevel@tonic-gate return (NULL);
25930Sstevel@tonic-gate }
25940Sstevel@tonic-gate /*LINTED alignment okay*/
25950Sstevel@tonic-gate kwp = (struct km_wrap *)mp;
25960Sstevel@tonic-gate kwp->kw_size = n;
25970Sstevel@tonic-gate /*LINTED alignment okay*/
25980Sstevel@tonic-gate kwp->kw_other = (struct km_wrap *)(mp + n - sizeof (struct km_wrap));
25990Sstevel@tonic-gate kwp = (struct km_wrap *)kwp->kw_other;
26000Sstevel@tonic-gate kwp->kw_size = n;
26010Sstevel@tonic-gate /*LINTED alignment okay*/
26020Sstevel@tonic-gate kwp->kw_other = (struct km_wrap *)mp;
26030Sstevel@tonic-gate
26040Sstevel@tonic-gate mutex_enter(&cachefs_kmem_lock);
26050Sstevel@tonic-gate ASSERT(cachefs_mem_usage >= 0);
26060Sstevel@tonic-gate cachefs_mem_usage += n;
26070Sstevel@tonic-gate mutex_exit(&cachefs_kmem_lock);
26080Sstevel@tonic-gate
26090Sstevel@tonic-gate return (mp + sizeof (struct km_wrap));
26100Sstevel@tonic-gate #else /* DEBUG */
26110Sstevel@tonic-gate return (kmem_alloc(size, flag));
26120Sstevel@tonic-gate #endif /* DEBUG */
26130Sstevel@tonic-gate }
26140Sstevel@tonic-gate
26150Sstevel@tonic-gate void *
cachefs_kmem_zalloc(size_t size,int flag)26160Sstevel@tonic-gate cachefs_kmem_zalloc(size_t size, int flag)
26170Sstevel@tonic-gate {
26180Sstevel@tonic-gate #ifdef DEBUG
26190Sstevel@tonic-gate caddr_t mp = NULL;
26200Sstevel@tonic-gate struct km_wrap *kwp;
26210Sstevel@tonic-gate size_t n = (size + (2 * sizeof (struct km_wrap)) + 7) & ~7;
26220Sstevel@tonic-gate
26230Sstevel@tonic-gate ASSERT(n >= (size + 8));
26240Sstevel@tonic-gate mp = kmem_zalloc(n, flag);
26250Sstevel@tonic-gate if (mp == NULL) {
26260Sstevel@tonic-gate return (NULL);
26270Sstevel@tonic-gate }
26280Sstevel@tonic-gate /*LINTED alignment okay*/
26290Sstevel@tonic-gate kwp = (struct km_wrap *)mp;
26300Sstevel@tonic-gate kwp->kw_size = n;
26310Sstevel@tonic-gate /*LINTED alignment okay*/
26320Sstevel@tonic-gate kwp->kw_other = (struct km_wrap *)(mp + n - sizeof (struct km_wrap));
26330Sstevel@tonic-gate kwp = (struct km_wrap *)kwp->kw_other;
26340Sstevel@tonic-gate kwp->kw_size = n;
26350Sstevel@tonic-gate /*LINTED alignment okay*/
26360Sstevel@tonic-gate kwp->kw_other = (struct km_wrap *)mp;
26370Sstevel@tonic-gate
26380Sstevel@tonic-gate mutex_enter(&cachefs_kmem_lock);
26390Sstevel@tonic-gate ASSERT(cachefs_mem_usage >= 0);
26400Sstevel@tonic-gate cachefs_mem_usage += n;
26410Sstevel@tonic-gate mutex_exit(&cachefs_kmem_lock);
26420Sstevel@tonic-gate
26430Sstevel@tonic-gate return (mp + sizeof (struct km_wrap));
26440Sstevel@tonic-gate #else /* DEBUG */
26450Sstevel@tonic-gate return (kmem_zalloc(size, flag));
26460Sstevel@tonic-gate #endif /* DEBUG */
26470Sstevel@tonic-gate }
26480Sstevel@tonic-gate
26490Sstevel@tonic-gate void
cachefs_kmem_free(void * mp,size_t size)26500Sstevel@tonic-gate cachefs_kmem_free(void *mp, size_t size)
26510Sstevel@tonic-gate {
26520Sstevel@tonic-gate #ifdef DEBUG
26530Sstevel@tonic-gate struct km_wrap *front_kwp;
26540Sstevel@tonic-gate struct km_wrap *back_kwp;
26550Sstevel@tonic-gate size_t n = (size + (2 * sizeof (struct km_wrap)) + 7) & ~7;
26560Sstevel@tonic-gate void *p;
26570Sstevel@tonic-gate
26580Sstevel@tonic-gate ASSERT(n >= (size + 8));
26590Sstevel@tonic-gate front_kwp = (struct km_wrap *)((uintptr_t)mp - sizeof (struct km_wrap));
26600Sstevel@tonic-gate back_kwp = (struct km_wrap *)
2661*11066Srafael.vanoni@sun.com ((uintptr_t)front_kwp + n - sizeof (struct km_wrap));
26620Sstevel@tonic-gate
26630Sstevel@tonic-gate ASSERT(front_kwp->kw_other == back_kwp);
26640Sstevel@tonic-gate ASSERT(front_kwp->kw_size == n);
26650Sstevel@tonic-gate ASSERT(back_kwp->kw_other == front_kwp);
26660Sstevel@tonic-gate ASSERT(back_kwp->kw_size == n);
26670Sstevel@tonic-gate
26680Sstevel@tonic-gate mutex_enter(&cachefs_kmem_lock);
26690Sstevel@tonic-gate cachefs_mem_usage -= n;
26700Sstevel@tonic-gate ASSERT(cachefs_mem_usage >= 0);
26710Sstevel@tonic-gate mutex_exit(&cachefs_kmem_lock);
26720Sstevel@tonic-gate
26730Sstevel@tonic-gate p = front_kwp;
26740Sstevel@tonic-gate front_kwp->kw_size = back_kwp->kw_size = 0;
26750Sstevel@tonic-gate front_kwp->kw_other = back_kwp->kw_other = NULL;
26760Sstevel@tonic-gate kmem_free(p, n);
26770Sstevel@tonic-gate #else /* DEBUG */
26780Sstevel@tonic-gate kmem_free(mp, size);
26790Sstevel@tonic-gate #endif /* DEBUG */
26800Sstevel@tonic-gate }
26810Sstevel@tonic-gate
26820Sstevel@tonic-gate char *
cachefs_strdup(char * s)26830Sstevel@tonic-gate cachefs_strdup(char *s)
26840Sstevel@tonic-gate {
26850Sstevel@tonic-gate char *rc;
26860Sstevel@tonic-gate
26870Sstevel@tonic-gate ASSERT(s != NULL);
26880Sstevel@tonic-gate
26890Sstevel@tonic-gate rc = cachefs_kmem_alloc(strlen(s) + 1, KM_SLEEP);
26900Sstevel@tonic-gate (void) strcpy(rc, s);
26910Sstevel@tonic-gate
26920Sstevel@tonic-gate return (rc);
26930Sstevel@tonic-gate }
26940Sstevel@tonic-gate
26950Sstevel@tonic-gate int
cachefs_stats_kstat_snapshot(kstat_t * ksp,void * buf,int rw)26960Sstevel@tonic-gate cachefs_stats_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
26970Sstevel@tonic-gate {
26980Sstevel@tonic-gate struct fscache *fscp = (struct fscache *)ksp->ks_data;
26990Sstevel@tonic-gate cachefscache_t *cachep = fscp->fs_cache;
27000Sstevel@tonic-gate int error = 0;
27010Sstevel@tonic-gate
27020Sstevel@tonic-gate if (rw == KSTAT_WRITE) {
27030Sstevel@tonic-gate bcopy(buf, &fscp->fs_stats, sizeof (fscp->fs_stats));
27040Sstevel@tonic-gate cachep->c_gc_count = fscp->fs_stats.st_gc_count;
27050Sstevel@tonic-gate CACHEFS_CFS_TIME_TO_TIME_COPY(fscp->fs_stats.st_gc_time,
2706*11066Srafael.vanoni@sun.com cachep->c_gc_time);
27070Sstevel@tonic-gate CACHEFS_CFS_TIME_TO_TIME_COPY(fscp->fs_stats.st_gc_before_atime,
2708*11066Srafael.vanoni@sun.com cachep->c_gc_before);
27090Sstevel@tonic-gate CACHEFS_CFS_TIME_TO_TIME_COPY(fscp->fs_stats.st_gc_after_atime,
2710*11066Srafael.vanoni@sun.com cachep->c_gc_after);
27110Sstevel@tonic-gate return (error);
27120Sstevel@tonic-gate }
27130Sstevel@tonic-gate
27140Sstevel@tonic-gate fscp->fs_stats.st_gc_count = cachep->c_gc_count;
27150Sstevel@tonic-gate CACHEFS_TIME_TO_CFS_TIME_COPY(cachep->c_gc_time,
2716*11066Srafael.vanoni@sun.com fscp->fs_stats.st_gc_time, error);
27170Sstevel@tonic-gate CACHEFS_TIME_TO_CFS_TIME_COPY(cachep->c_gc_before,
2718*11066Srafael.vanoni@sun.com fscp->fs_stats.st_gc_before_atime, error);
27190Sstevel@tonic-gate CACHEFS_TIME_TO_CFS_TIME_COPY(cachep->c_gc_after,
2720*11066Srafael.vanoni@sun.com fscp->fs_stats.st_gc_after_atime, error);
27210Sstevel@tonic-gate bcopy(&fscp->fs_stats, buf, sizeof (fscp->fs_stats));
27220Sstevel@tonic-gate
27230Sstevel@tonic-gate return (error);
27240Sstevel@tonic-gate }
27250Sstevel@tonic-gate
27260Sstevel@tonic-gate #ifdef DEBUG
27270Sstevel@tonic-gate cachefs_debug_info_t *
cachefs_debug_save(cachefs_debug_info_t * oldcdb,int chain,char * message,uint_t flags,int number,void * pointer,cachefscache_t * cachep,struct fscache * fscp,struct cnode * cp)27280Sstevel@tonic-gate cachefs_debug_save(cachefs_debug_info_t *oldcdb, int chain,
27290Sstevel@tonic-gate char *message, uint_t flags, int number, void *pointer,
27300Sstevel@tonic-gate cachefscache_t *cachep, struct fscache *fscp, struct cnode *cp)
27310Sstevel@tonic-gate {
27320Sstevel@tonic-gate cachefs_debug_info_t *cdb;
27330Sstevel@tonic-gate
27340Sstevel@tonic-gate if ((chain) || (oldcdb == NULL))
27350Sstevel@tonic-gate cdb = cachefs_kmem_zalloc(sizeof (*cdb), KM_SLEEP);
27360Sstevel@tonic-gate else
27370Sstevel@tonic-gate cdb = oldcdb;
27380Sstevel@tonic-gate if (chain)
27390Sstevel@tonic-gate cdb->cdb_next = oldcdb;
27400Sstevel@tonic-gate
27410Sstevel@tonic-gate if (message != NULL) {
27420Sstevel@tonic-gate if (cdb->cdb_message != NULL)
27430Sstevel@tonic-gate cachefs_kmem_free(cdb->cdb_message,
27440Sstevel@tonic-gate strlen(cdb->cdb_message) + 1);
27450Sstevel@tonic-gate cdb->cdb_message = cachefs_kmem_alloc(strlen(message) + 1,
27460Sstevel@tonic-gate KM_SLEEP);
27470Sstevel@tonic-gate (void) strcpy(cdb->cdb_message, message);
27480Sstevel@tonic-gate }
27490Sstevel@tonic-gate cdb->cdb_flags = flags;
27500Sstevel@tonic-gate cdb->cdb_int = number;
27510Sstevel@tonic-gate cdb->cdb_pointer = pointer;
27520Sstevel@tonic-gate
27530Sstevel@tonic-gate cdb->cdb_count++;
27540Sstevel@tonic-gate
27550Sstevel@tonic-gate cdb->cdb_cnode = cp;
27560Sstevel@tonic-gate if (cp != NULL) {
27570Sstevel@tonic-gate cdb->cdb_frontvp = cp->c_frontvp;
27580Sstevel@tonic-gate cdb->cdb_backvp = cp->c_backvp;
27590Sstevel@tonic-gate }
27600Sstevel@tonic-gate if (fscp != NULL)
27610Sstevel@tonic-gate cdb->cdb_fscp = fscp;
27620Sstevel@tonic-gate else if (cp != NULL)
27630Sstevel@tonic-gate cdb->cdb_fscp = C_TO_FSCACHE(cp);
27640Sstevel@tonic-gate if (cachep != NULL)
27650Sstevel@tonic-gate cdb->cdb_cachep = cachep;
27660Sstevel@tonic-gate else if (cdb->cdb_fscp != NULL)
27670Sstevel@tonic-gate cdb->cdb_cachep = cdb->cdb_fscp->fs_cache;
27680Sstevel@tonic-gate
27690Sstevel@tonic-gate cdb->cdb_thread = curthread;
27700Sstevel@tonic-gate cdb->cdb_timestamp = gethrtime();
27710Sstevel@tonic-gate cdb->cdb_depth = getpcstack(cdb->cdb_stack, CACHEFS_DEBUG_DEPTH);
27720Sstevel@tonic-gate
27730Sstevel@tonic-gate return (cdb);
27740Sstevel@tonic-gate }
27750Sstevel@tonic-gate
27760Sstevel@tonic-gate void
cachefs_debug_show(cachefs_debug_info_t * cdb)27770Sstevel@tonic-gate cachefs_debug_show(cachefs_debug_info_t *cdb)
27780Sstevel@tonic-gate {
27790Sstevel@tonic-gate hrtime_t now = gethrtime();
27800Sstevel@tonic-gate timestruc_t ts;
27810Sstevel@tonic-gate int i;
27820Sstevel@tonic-gate
27830Sstevel@tonic-gate while (cdb != NULL) {
27840Sstevel@tonic-gate hrt2ts(now - cdb->cdb_timestamp, &ts);
27850Sstevel@tonic-gate printf("cdb: %p count: %d timelapse: %ld.%9ld\n",
27860Sstevel@tonic-gate (void *)cdb, cdb->cdb_count, ts.tv_sec, ts.tv_nsec);
27870Sstevel@tonic-gate if (cdb->cdb_message != NULL)
27880Sstevel@tonic-gate printf("message: %s", cdb->cdb_message);
27890Sstevel@tonic-gate printf("flags: %x int: %d pointer: %p\n",
27900Sstevel@tonic-gate cdb->cdb_flags, cdb->cdb_int, (void *)cdb->cdb_pointer);
27910Sstevel@tonic-gate
27920Sstevel@tonic-gate printf("cnode: %p fscp: %p cachep: %p\n",
27930Sstevel@tonic-gate (void *)cdb->cdb_cnode,
27940Sstevel@tonic-gate (void *)cdb->cdb_fscp, (void *)cdb->cdb_cachep);
27950Sstevel@tonic-gate printf("frontvp: %p backvp: %p\n",
27960Sstevel@tonic-gate (void *)cdb->cdb_frontvp, (void *)cdb->cdb_backvp);
27970Sstevel@tonic-gate
27980Sstevel@tonic-gate printf("thread: %p stack...\n", (void *)cdb->cdb_thread);
27990Sstevel@tonic-gate for (i = 0; i < cdb->cdb_depth; i++) {
28000Sstevel@tonic-gate ulong_t off;
28010Sstevel@tonic-gate char *sym;
28020Sstevel@tonic-gate
28030Sstevel@tonic-gate sym = kobj_getsymname(cdb->cdb_stack[i], &off);
28040Sstevel@tonic-gate printf("%s+%lx\n", sym ? sym : "?", off);
28050Sstevel@tonic-gate }
28060Sstevel@tonic-gate delay(2*hz);
28070Sstevel@tonic-gate cdb = cdb->cdb_next;
28080Sstevel@tonic-gate }
28090Sstevel@tonic-gate debug_enter(NULL);
28100Sstevel@tonic-gate }
28110Sstevel@tonic-gate #endif /* DEBUG */
28120Sstevel@tonic-gate
28130Sstevel@tonic-gate /*
28140Sstevel@tonic-gate * Changes the size of the front file.
28150Sstevel@tonic-gate * Returns 0 for success or error if cannot set file size.
28160Sstevel@tonic-gate * NOCACHE bit is ignored.
28170Sstevel@tonic-gate * c_size is ignored.
28180Sstevel@tonic-gate * statelock must be held, frontvp must be set.
28190Sstevel@tonic-gate * File must be populated if setting to a size other than zero.
28200Sstevel@tonic-gate */
28210Sstevel@tonic-gate int
cachefs_frontfile_size(cnode_t * cp,u_offset_t length)28220Sstevel@tonic-gate cachefs_frontfile_size(cnode_t *cp, u_offset_t length)
28230Sstevel@tonic-gate {
28240Sstevel@tonic-gate cachefscache_t *cachep = C_TO_FSCACHE(cp)->fs_cache;
28250Sstevel@tonic-gate vattr_t va;
28260Sstevel@tonic-gate size_t nblks, blkdelta;
28270Sstevel@tonic-gate int error = 0;
28280Sstevel@tonic-gate int alloc = 0;
28290Sstevel@tonic-gate struct cachefs_allocmap *allocp;
28300Sstevel@tonic-gate
28310Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cp->c_statelock));
28320Sstevel@tonic-gate ASSERT(cp->c_frontvp);
28330Sstevel@tonic-gate
28340Sstevel@tonic-gate /* if growing the file, allocate space first, we charge for holes */
28350Sstevel@tonic-gate if (length) {
28360Sstevel@tonic-gate ASSERT(cp->c_metadata.md_flags & MD_POPULATED);
28370Sstevel@tonic-gate
28380Sstevel@tonic-gate nblks = (length + MAXBSIZE - 1) / MAXBSIZE;
28390Sstevel@tonic-gate if (nblks > cp->c_metadata.md_frontblks) {
28400Sstevel@tonic-gate blkdelta = nblks - cp->c_metadata.md_frontblks;
28410Sstevel@tonic-gate error = cachefs_allocblocks(cachep, blkdelta,
28420Sstevel@tonic-gate cp->c_metadata.md_rltype);
28430Sstevel@tonic-gate if (error)
28440Sstevel@tonic-gate goto out;
28450Sstevel@tonic-gate alloc = 1;
28460Sstevel@tonic-gate }
28470Sstevel@tonic-gate }
28480Sstevel@tonic-gate
28490Sstevel@tonic-gate /* change the size of the front file */
28500Sstevel@tonic-gate va.va_mask = AT_SIZE;
28510Sstevel@tonic-gate va.va_size = length;
28520Sstevel@tonic-gate error = VOP_SETATTR(cp->c_frontvp, &va, 0, kcred, NULL);
28530Sstevel@tonic-gate if (error)
28540Sstevel@tonic-gate goto out;
28550Sstevel@tonic-gate
28560Sstevel@tonic-gate /* zero out the alloc map */
28570Sstevel@tonic-gate bzero(&cp->c_metadata.md_allocinfo,
28580Sstevel@tonic-gate cp->c_metadata.md_allocents * sizeof (struct cachefs_allocmap));
28590Sstevel@tonic-gate cp->c_metadata.md_allocents = 0;
28600Sstevel@tonic-gate
28610Sstevel@tonic-gate if (length == 0) {
28620Sstevel@tonic-gate /* free up blocks */
28630Sstevel@tonic-gate if (cp->c_metadata.md_frontblks) {
28640Sstevel@tonic-gate cachefs_freeblocks(cachep, cp->c_metadata.md_frontblks,
28650Sstevel@tonic-gate cp->c_metadata.md_rltype);
28660Sstevel@tonic-gate cp->c_metadata.md_frontblks = 0;
28670Sstevel@tonic-gate }
28680Sstevel@tonic-gate } else {
28690Sstevel@tonic-gate /* update number of blocks if shrinking file */
28700Sstevel@tonic-gate nblks = (length + MAXBSIZE - 1) / MAXBSIZE;
28710Sstevel@tonic-gate if (nblks < cp->c_metadata.md_frontblks) {
28720Sstevel@tonic-gate blkdelta = cp->c_metadata.md_frontblks - nblks;
28730Sstevel@tonic-gate cachefs_freeblocks(cachep, blkdelta,
28740Sstevel@tonic-gate cp->c_metadata.md_rltype);
28750Sstevel@tonic-gate cp->c_metadata.md_frontblks = (uint_t)nblks;
28760Sstevel@tonic-gate }
28770Sstevel@tonic-gate
28780Sstevel@tonic-gate /* fix up alloc map to reflect new size */
28790Sstevel@tonic-gate allocp = cp->c_metadata.md_allocinfo;
28800Sstevel@tonic-gate allocp->am_start_off = 0;
28810Sstevel@tonic-gate allocp->am_size = length;
28820Sstevel@tonic-gate cp->c_metadata.md_allocents = 1;
28830Sstevel@tonic-gate }
28840Sstevel@tonic-gate cp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC;
28850Sstevel@tonic-gate
28860Sstevel@tonic-gate out:
28870Sstevel@tonic-gate if (error && alloc)
28880Sstevel@tonic-gate cachefs_freeblocks(cachep, blkdelta, cp->c_metadata.md_rltype);
28890Sstevel@tonic-gate return (error);
28900Sstevel@tonic-gate }
28910Sstevel@tonic-gate
28920Sstevel@tonic-gate /*ARGSUSED*/
28930Sstevel@tonic-gate int
cachefs_req_create(void * voidp,void * cdrarg,int kmflags)28940Sstevel@tonic-gate cachefs_req_create(void *voidp, void *cdrarg, int kmflags)
28950Sstevel@tonic-gate {
28960Sstevel@tonic-gate struct cachefs_req *rp = (struct cachefs_req *)voidp;
28970Sstevel@tonic-gate
28980Sstevel@tonic-gate /*
28990Sstevel@tonic-gate * XXX don't do this! if you need this, you can't use this
29000Sstevel@tonic-gate * constructor.
29010Sstevel@tonic-gate */
29020Sstevel@tonic-gate
29030Sstevel@tonic-gate bzero(rp, sizeof (struct cachefs_req));
29040Sstevel@tonic-gate
29050Sstevel@tonic-gate mutex_init(&rp->cfs_req_lock, NULL, MUTEX_DEFAULT, NULL);
29060Sstevel@tonic-gate return (0);
29070Sstevel@tonic-gate }
29080Sstevel@tonic-gate
29090Sstevel@tonic-gate /*ARGSUSED*/
29100Sstevel@tonic-gate void
cachefs_req_destroy(void * voidp,void * cdrarg)29110Sstevel@tonic-gate cachefs_req_destroy(void *voidp, void *cdrarg)
29120Sstevel@tonic-gate {
29130Sstevel@tonic-gate struct cachefs_req *rp = (struct cachefs_req *)voidp;
29140Sstevel@tonic-gate
29150Sstevel@tonic-gate mutex_destroy(&rp->cfs_req_lock);
29160Sstevel@tonic-gate }
2917