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
5*5331Samw * Common Development and Distribution License (the "License").
6*5331Samw * 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*5331Samw * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/cred.h>
320Sstevel@tonic-gate #include <sys/proc.h>
330Sstevel@tonic-gate #include <sys/user.h>
340Sstevel@tonic-gate #include <sys/vfs.h>
350Sstevel@tonic-gate #include <sys/vnode.h>
360Sstevel@tonic-gate #include <sys/pathname.h>
370Sstevel@tonic-gate #include <sys/uio.h>
380Sstevel@tonic-gate #include <sys/tiuser.h>
390Sstevel@tonic-gate #include <sys/sysmacros.h>
400Sstevel@tonic-gate #include <sys/kmem.h>
410Sstevel@tonic-gate #include <netinet/in.h>
420Sstevel@tonic-gate #include <sys/mount.h>
430Sstevel@tonic-gate #include <sys/ioctl.h>
440Sstevel@tonic-gate #include <sys/statvfs.h>
450Sstevel@tonic-gate #include <sys/errno.h>
460Sstevel@tonic-gate #include <sys/debug.h>
470Sstevel@tonic-gate #include <sys/cmn_err.h>
480Sstevel@tonic-gate #include <sys/utsname.h>
490Sstevel@tonic-gate #include <sys/bootconf.h>
500Sstevel@tonic-gate #include <sys/modctl.h>
510Sstevel@tonic-gate
520Sstevel@tonic-gate #include <vm/hat.h>
530Sstevel@tonic-gate #include <vm/as.h>
540Sstevel@tonic-gate #include <vm/page.h>
550Sstevel@tonic-gate #include <vm/pvn.h>
560Sstevel@tonic-gate #include <vm/seg.h>
570Sstevel@tonic-gate #include <vm/seg_map.h>
580Sstevel@tonic-gate #include <vm/seg_vn.h>
590Sstevel@tonic-gate #include <vm/rm.h>
600Sstevel@tonic-gate #include <sys/fs/cachefs_fs.h>
610Sstevel@tonic-gate
620Sstevel@tonic-gate #define C_CACHE_VALID(TOKEN_MTIME, NEW_MTIME) \
630Sstevel@tonic-gate ((TOKEN_MTIME.tv_sec == NEW_MTIME.tv_sec) && \
640Sstevel@tonic-gate (TOKEN_MTIME.tv_nsec == NEW_MTIME.tv_nsec))
650Sstevel@tonic-gate
660Sstevel@tonic-gate static int
c_cod_init_cached_object(fscache_t * fscp,cnode_t * cp,vattr_t * vap,cred_t * cr)670Sstevel@tonic-gate c_cod_init_cached_object(fscache_t *fscp, cnode_t *cp, vattr_t *vap,
680Sstevel@tonic-gate cred_t *cr)
690Sstevel@tonic-gate {
700Sstevel@tonic-gate int error;
710Sstevel@tonic-gate cachefs_metadata_t *mdp = &cp->c_metadata;
720Sstevel@tonic-gate
730Sstevel@tonic-gate ASSERT(cr != NULL);
740Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cp->c_statelock));
750Sstevel@tonic-gate
760Sstevel@tonic-gate /* NFSv4 option sets strict consistency */
770Sstevel@tonic-gate ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
780Sstevel@tonic-gate
790Sstevel@tonic-gate /* if attributes not passed in then get them */
800Sstevel@tonic-gate if (vap == NULL) {
810Sstevel@tonic-gate /* if not connected then cannot get attrs */
820Sstevel@tonic-gate if ((fscp->fs_cdconnected != CFS_CD_CONNECTED) ||
830Sstevel@tonic-gate (fscp->fs_backvfsp == NULL))
840Sstevel@tonic-gate return (ETIMEDOUT);
850Sstevel@tonic-gate
860Sstevel@tonic-gate /* get backvp if necessary */
870Sstevel@tonic-gate if (cp->c_backvp == NULL) {
880Sstevel@tonic-gate error = cachefs_getbackvp(fscp, cp);
890Sstevel@tonic-gate if (error)
900Sstevel@tonic-gate return (error);
910Sstevel@tonic-gate }
920Sstevel@tonic-gate
930Sstevel@tonic-gate /* get the attributes */
940Sstevel@tonic-gate cp->c_attr.va_mask = AT_ALL;
95*5331Samw error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr, NULL);
960Sstevel@tonic-gate if (error)
970Sstevel@tonic-gate return (error);
980Sstevel@tonic-gate } else {
990Sstevel@tonic-gate /* copy passed in attributes into the cnode */
1000Sstevel@tonic-gate cp->c_attr = *vap;
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate cp->c_size = cp->c_attr.va_size;
1040Sstevel@tonic-gate mdp->md_x_time = fscp->fs_cod_time;
1050Sstevel@tonic-gate mdp->md_consttype = CFS_FS_CONST_CODCONST;
1060Sstevel@tonic-gate cp->c_flags |= CN_UPDATED;
1070Sstevel@tonic-gate return (0);
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate static int
c_cod_check_cached_object(struct fscache * fscp,struct cnode * cp,int verify_what,cred_t * cr)1110Sstevel@tonic-gate c_cod_check_cached_object(struct fscache *fscp, struct cnode *cp,
1120Sstevel@tonic-gate int verify_what, cred_t *cr)
1130Sstevel@tonic-gate {
1140Sstevel@tonic-gate struct vattr attrs;
1150Sstevel@tonic-gate int fail = 0, backhit = 0;
1160Sstevel@tonic-gate int error = 0;
1170Sstevel@tonic-gate cachefs_metadata_t *mdp = &cp->c_metadata;
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate #ifdef CFSDEBUG
1200Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_VOPS)
1210Sstevel@tonic-gate printf("c_cod_check_cached_object: ENTER cp %p\n", cp);
1220Sstevel@tonic-gate #endif
1230Sstevel@tonic-gate ASSERT(cr);
1240Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cp->c_statelock));
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate /* nothing to do if not connected */
1270Sstevel@tonic-gate if ((fscp->fs_cdconnected != CFS_CD_CONNECTED) ||
1280Sstevel@tonic-gate (fscp->fs_backvfsp == NULL))
1290Sstevel@tonic-gate goto out;
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate /* done if do not have to check and cod button has not been pushed */
1320Sstevel@tonic-gate if (((verify_what & C_BACK_CHECK) == 0) &&
1330Sstevel@tonic-gate (C_CACHE_VALID(mdp->md_x_time, fscp->fs_cod_time)) &&
1340Sstevel@tonic-gate ((mdp->md_flags & MD_NEEDATTRS) == 0))
1350Sstevel@tonic-gate goto out;
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate /* get backvp if necessary */
1380Sstevel@tonic-gate if (cp->c_backvp == NULL) {
1390Sstevel@tonic-gate error = cachefs_getbackvp(fscp, cp);
1400Sstevel@tonic-gate if (error)
1410Sstevel@tonic-gate goto out;
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate /*
1450Sstevel@tonic-gate * If the cnode is being populated, and we're not the populating
1460Sstevel@tonic-gate * thread, then block until the pop thread completes. If we are the
1470Sstevel@tonic-gate * pop thread, then we may come in here, but not to nuke the directory
1480Sstevel@tonic-gate * cnode at a critical juncture.
1490Sstevel@tonic-gate */
1500Sstevel@tonic-gate again:
1510Sstevel@tonic-gate while ((cp->c_flags & CN_ASYNC_POP_WORKING) &&
1520Sstevel@tonic-gate (cp->c_popthrp != curthread)) {
1530Sstevel@tonic-gate cv_wait(&cp->c_popcv, &cp->c_statelock);
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate /*
1560Sstevel@tonic-gate * recheck backvp and connectivity - if backvp now null,
1570Sstevel@tonic-gate * something bad happened, so don't bother trying to 'get' it
1580Sstevel@tonic-gate */
1590Sstevel@tonic-gate if ((cp->c_backvp == NULL) ||
1600Sstevel@tonic-gate (fscp->fs_cdconnected != CFS_CD_CONNECTED) ||
1610Sstevel@tonic-gate (fscp->fs_backvfsp == NULL)) {
1620Sstevel@tonic-gate if (cp->c_flags | CN_STALE) {
1630Sstevel@tonic-gate cp->c_flags |= CN_NOCACHE;
1640Sstevel@tonic-gate error = ESTALE;
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate goto out;
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate /* get the file attributes from the back fs */
1710Sstevel@tonic-gate attrs.va_mask = AT_ALL;
172*5331Samw error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
1730Sstevel@tonic-gate backhit = 1;
1740Sstevel@tonic-gate if (error)
1750Sstevel@tonic-gate goto out;
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate /* if the mtime or size of the file has changed */
1780Sstevel@tonic-gate if ((!C_CACHE_VALID(mdp->md_vattr.va_mtime, attrs.va_mtime) ||
1790Sstevel@tonic-gate (cp->c_size != attrs.va_size)) &&
1800Sstevel@tonic-gate ((mdp->md_flags & MD_NEEDATTRS) == 0)) {
1810Sstevel@tonic-gate fail = 1;
1820Sstevel@tonic-gate if (vn_has_cached_data(CTOV(cp))) {
1830Sstevel@tonic-gate mutex_exit(&cp->c_statelock);
1840Sstevel@tonic-gate error = cachefs_putpage_common(CTOV(cp),
1850Sstevel@tonic-gate (offset_t)0, 0, B_INVAL, cr);
1860Sstevel@tonic-gate mutex_enter(&cp->c_statelock);
1870Sstevel@tonic-gate if (CFS_TIMEOUT(fscp, error))
1880Sstevel@tonic-gate goto out;
1890Sstevel@tonic-gate error = 0;
1900Sstevel@tonic-gate /*
1910Sstevel@tonic-gate * if an async pop started while the lock was
1920Sstevel@tonic-gate * dropped, go back and try again
1930Sstevel@tonic-gate */
1940Sstevel@tonic-gate if ((cp->c_flags & CN_ASYNC_POP_WORKING) &&
1950Sstevel@tonic-gate (cp->c_popthrp != curthread))
1960Sstevel@tonic-gate goto again;
1970Sstevel@tonic-gate }
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate * We should properly handle the CN_NOCACHE flag here.
2000Sstevel@tonic-gate * In fact, we should remember that cachefs_inval_object()
2010Sstevel@tonic-gate * forcibly sets/unsets the flag, so we should keep a
2020Sstevel@tonic-gate * state of the flag over the call.
2030Sstevel@tonic-gate */
2040Sstevel@tonic-gate if ((cp->c_flags & CN_NOCACHE) == 0)
2050Sstevel@tonic-gate cachefs_inval_object(cp);
2060Sstevel@tonic-gate else {
2070Sstevel@tonic-gate cachefs_inval_object(cp);
2080Sstevel@tonic-gate cp->c_flags |= CN_NOCACHE;
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate if ((CTOV(cp))->v_type == VREG) {
2110Sstevel@tonic-gate attrs.va_mask = AT_ALL;
212*5331Samw error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
2130Sstevel@tonic-gate if (error)
2140Sstevel@tonic-gate goto out;
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate if (!vn_has_cached_data(CTOV(cp))) {
2170Sstevel@tonic-gate cp->c_size = attrs.va_size;
2180Sstevel@tonic-gate #ifdef CFSDEBUG
2190Sstevel@tonic-gate } else {
2200Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_VOPS)
2210Sstevel@tonic-gate printf("c_cod_check: v_pages not null\n");
2220Sstevel@tonic-gate #endif
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate /* toss cached acl info if ctime changed */
2270Sstevel@tonic-gate if (!C_CACHE_VALID(mdp->md_vattr.va_ctime, attrs.va_ctime)) {
2280Sstevel@tonic-gate cachefs_purgeacl(cp);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate cp->c_attr = attrs;
2320Sstevel@tonic-gate if (attrs.va_size > cp->c_size)
2330Sstevel@tonic-gate cp->c_size = attrs.va_size;
2340Sstevel@tonic-gate mdp->md_x_time = fscp->fs_cod_time;
2350Sstevel@tonic-gate mdp->md_flags &= ~MD_NEEDATTRS;
2360Sstevel@tonic-gate cachefs_cnode_setlocalstats(cp);
2370Sstevel@tonic-gate cp->c_flags |= CN_UPDATED;
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate out:
2400Sstevel@tonic-gate if (backhit != 0) {
2410Sstevel@tonic-gate if (fail != 0)
2420Sstevel@tonic-gate fscp->fs_stats.st_fails++;
2430Sstevel@tonic-gate else
2440Sstevel@tonic-gate fscp->fs_stats.st_passes++;
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate #ifdef CFSDEBUG
2480Sstevel@tonic-gate CFS_DEBUG(CFSDEBUG_VOPS)
2490Sstevel@tonic-gate printf("c_cod_check_cached_object: EXIT\n");
2500Sstevel@tonic-gate #endif
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate return (error);
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate /*ARGSUSED*/
2560Sstevel@tonic-gate static void
c_cod_modify_cached_object(struct fscache * fscp,struct cnode * cp,cred_t * cr)2570Sstevel@tonic-gate c_cod_modify_cached_object(struct fscache *fscp, struct cnode *cp, cred_t *cr)
2580Sstevel@tonic-gate {
2590Sstevel@tonic-gate struct vattr attrs;
2600Sstevel@tonic-gate int error = 0;
2610Sstevel@tonic-gate nlink_t nlink;
2620Sstevel@tonic-gate cachefs_metadata_t *mdp = &cp->c_metadata;
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cp->c_statelock));
2650Sstevel@tonic-gate ASSERT(fscp->fs_cdconnected == CFS_CD_CONNECTED);
2660Sstevel@tonic-gate ASSERT(fscp->fs_backvfsp);
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate fscp->fs_stats.st_modifies++;
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate /* from now on, make sure we're using the server's idea of time */
2710Sstevel@tonic-gate mdp->md_flags &= ~(MD_LOCALCTIME | MD_LOCALMTIME);
2720Sstevel@tonic-gate mdp->md_flags |= MD_NEEDATTRS;
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate /* if in write-around mode, make sure file is nocached */
2750Sstevel@tonic-gate if (CFS_ISFS_WRITE_AROUND(fscp)) {
2760Sstevel@tonic-gate if ((cp->c_flags & CN_NOCACHE) == 0)
2770Sstevel@tonic-gate cachefs_nocache(cp);
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate /*
2800Sstevel@tonic-gate * If a directory, then defer getting the new attributes
2810Sstevel@tonic-gate * until requested. Might be a little bit faster this way.
2820Sstevel@tonic-gate */
2830Sstevel@tonic-gate if (CTOV(cp)->v_type == VDIR)
2840Sstevel@tonic-gate goto out;
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate
2870Sstevel@tonic-gate /* get the new mtime so the next call to check_cobject does not fail */
2880Sstevel@tonic-gate if (cp->c_backvp == NULL) {
2890Sstevel@tonic-gate error = cachefs_getbackvp(fscp, cp);
2900Sstevel@tonic-gate if (error) {
2910Sstevel@tonic-gate mdp->md_vattr.va_mtime.tv_sec = 0;
2920Sstevel@tonic-gate goto out;
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate attrs.va_mask = AT_ALL;
2960Sstevel@tonic-gate ASSERT(cp->c_backvp != NULL);
297*5331Samw error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
2980Sstevel@tonic-gate if (error) {
2990Sstevel@tonic-gate mdp->md_vattr.va_mtime.tv_sec = 0;
3000Sstevel@tonic-gate goto out;
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate nlink = cp->c_attr.va_nlink;
3030Sstevel@tonic-gate cp->c_attr = attrs;
3040Sstevel@tonic-gate cp->c_attr.va_nlink = nlink;
3050Sstevel@tonic-gate if ((attrs.va_size > cp->c_size) || !vn_has_cached_data(CTOV(cp)))
3060Sstevel@tonic-gate cp->c_size = attrs.va_size;
3070Sstevel@tonic-gate mdp->md_flags &= ~MD_NEEDATTRS;
3080Sstevel@tonic-gate cachefs_cnode_setlocalstats(cp);
3090Sstevel@tonic-gate out:
3100Sstevel@tonic-gate cp->c_flags |= CN_UPDATED;
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate /*ARGSUSED*/
3140Sstevel@tonic-gate static void
c_cod_invalidate_cached_object(struct fscache * fscp,struct cnode * cp,cred_t * cr)3150Sstevel@tonic-gate c_cod_invalidate_cached_object(struct fscache *fscp, struct cnode *cp,
3160Sstevel@tonic-gate cred_t *cr)
3170Sstevel@tonic-gate {
3180Sstevel@tonic-gate cachefs_metadata_t *mdp = &cp->c_metadata;
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cp->c_statelock));
3210Sstevel@tonic-gate mdp->md_vattr.va_mtime.tv_sec = 0;
3220Sstevel@tonic-gate mdp->md_flags |= MD_NEEDATTRS;
3230Sstevel@tonic-gate cp->c_flags |= CN_UPDATED;
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate /*ARGSUSED*/
3270Sstevel@tonic-gate static void
c_cod_convert_cached_object(struct fscache * fscp,struct cnode * cp,cred_t * cr)3280Sstevel@tonic-gate c_cod_convert_cached_object(struct fscache *fscp, struct cnode *cp,
3290Sstevel@tonic-gate cred_t *cr)
3300Sstevel@tonic-gate {
3310Sstevel@tonic-gate cachefs_metadata_t *mdp = &cp->c_metadata;
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cp->c_statelock));
3340Sstevel@tonic-gate mdp->md_flags |= MD_NEEDATTRS;
3350Sstevel@tonic-gate mdp->md_consttype = CFS_FS_CONST_CODCONST;
3360Sstevel@tonic-gate cp->c_flags |= CN_UPDATED;
3370Sstevel@tonic-gate }
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate struct cachefsops codcfsops = {
3400Sstevel@tonic-gate c_cod_init_cached_object,
3410Sstevel@tonic-gate c_cod_check_cached_object,
3420Sstevel@tonic-gate c_cod_modify_cached_object,
3430Sstevel@tonic-gate c_cod_invalidate_cached_object,
3440Sstevel@tonic-gate c_cod_convert_cached_object
3450Sstevel@tonic-gate };
346