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
52720Sfrankho * Common Development and Distribution License (the "License").
62720Sfrankho * 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 /*
224356Scasper * 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/t_lock.h>
300Sstevel@tonic-gate #include <sys/errno.h>
310Sstevel@tonic-gate #include <sys/sysmacros.h>
320Sstevel@tonic-gate #include <sys/buf.h>
330Sstevel@tonic-gate #include <sys/systm.h>
340Sstevel@tonic-gate #include <sys/vfs.h>
350Sstevel@tonic-gate #include <sys/vnode.h>
360Sstevel@tonic-gate #include <sys/kmem.h>
370Sstevel@tonic-gate #include <sys/proc.h>
380Sstevel@tonic-gate #include <sys/cred.h>
390Sstevel@tonic-gate #include <sys/cmn_err.h>
400Sstevel@tonic-gate #include <sys/debug.h>
410Sstevel@tonic-gate #include <vm/pvn.h>
420Sstevel@tonic-gate #include <sys/fs/pc_label.h>
430Sstevel@tonic-gate #include <sys/fs/pc_fs.h>
440Sstevel@tonic-gate #include <sys/fs/pc_dir.h>
450Sstevel@tonic-gate #include <sys/fs/pc_node.h>
460Sstevel@tonic-gate #include <sys/dirent.h>
470Sstevel@tonic-gate #include <sys/fdio.h>
480Sstevel@tonic-gate #include <sys/file.h>
490Sstevel@tonic-gate #include <sys/conf.h>
500Sstevel@tonic-gate
510Sstevel@tonic-gate struct pchead pcfhead[NPCHASH];
520Sstevel@tonic-gate struct pchead pcdhead[NPCHASH];
530Sstevel@tonic-gate
540Sstevel@tonic-gate extern krwlock_t pcnodes_lock;
550Sstevel@tonic-gate
560Sstevel@tonic-gate static int pc_getentryblock(struct pcnode *, struct buf **);
570Sstevel@tonic-gate static int syncpcp(struct pcnode *, int);
580Sstevel@tonic-gate
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate * fake entry for root directory, since this does not have a parent
610Sstevel@tonic-gate * pointing to it.
620Sstevel@tonic-gate */
632720Sfrankho struct pcdir pcfs_rootdirentry = {
640Sstevel@tonic-gate "",
650Sstevel@tonic-gate "",
660Sstevel@tonic-gate PCA_DIR
670Sstevel@tonic-gate };
680Sstevel@tonic-gate
690Sstevel@tonic-gate void
pc_init(void)700Sstevel@tonic-gate pc_init(void)
710Sstevel@tonic-gate {
720Sstevel@tonic-gate struct pchead *hdp, *hfp;
730Sstevel@tonic-gate int i;
740Sstevel@tonic-gate for (i = 0; i < NPCHASH; i++) {
750Sstevel@tonic-gate hdp = &pcdhead[i];
760Sstevel@tonic-gate hfp = &pcfhead[i];
770Sstevel@tonic-gate hdp->pch_forw = (struct pcnode *)hdp;
780Sstevel@tonic-gate hdp->pch_back = (struct pcnode *)hdp;
790Sstevel@tonic-gate hfp->pch_forw = (struct pcnode *)hfp;
800Sstevel@tonic-gate hfp->pch_back = (struct pcnode *)hfp;
810Sstevel@tonic-gate }
820Sstevel@tonic-gate }
830Sstevel@tonic-gate
840Sstevel@tonic-gate struct pcnode *
pc_getnode(struct pcfs * fsp,daddr_t blkno,int offset,struct pcdir * ep)850Sstevel@tonic-gate pc_getnode(
860Sstevel@tonic-gate struct pcfs *fsp, /* filsystem for node */
870Sstevel@tonic-gate daddr_t blkno, /* phys block no of dir entry */
880Sstevel@tonic-gate int offset, /* offset of dir entry in block */
890Sstevel@tonic-gate struct pcdir *ep) /* node dir entry */
900Sstevel@tonic-gate {
910Sstevel@tonic-gate struct pcnode *pcp;
920Sstevel@tonic-gate struct pchead *hp;
930Sstevel@tonic-gate struct vnode *vp;
940Sstevel@tonic-gate pc_cluster32_t scluster;
950Sstevel@tonic-gate
960Sstevel@tonic-gate ASSERT(fsp->pcfs_flags & PCFS_LOCKED);
970Sstevel@tonic-gate if (ep == (struct pcdir *)0) {
982720Sfrankho ep = &pcfs_rootdirentry;
990Sstevel@tonic-gate scluster = 0;
1000Sstevel@tonic-gate } else {
1010Sstevel@tonic-gate scluster = pc_getstartcluster(fsp, ep);
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate /*
1040Sstevel@tonic-gate * First look for active nodes.
1050Sstevel@tonic-gate * File nodes are identified by the location (blkno, offset) of
1060Sstevel@tonic-gate * its directory entry.
1070Sstevel@tonic-gate * Directory nodes are identified by the starting cluster number
1080Sstevel@tonic-gate * for the entries.
1090Sstevel@tonic-gate */
1100Sstevel@tonic-gate if (ep->pcd_attr & PCA_DIR) {
1110Sstevel@tonic-gate hp = &pcdhead[PCDHASH(fsp, scluster)];
1120Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_READER);
1130Sstevel@tonic-gate for (pcp = hp->pch_forw;
1140Sstevel@tonic-gate pcp != (struct pcnode *)hp; pcp = pcp->pc_forw) {
1150Sstevel@tonic-gate if ((fsp == VFSTOPCFS(PCTOV(pcp)->v_vfsp)) &&
1160Sstevel@tonic-gate (scluster == pcp->pc_scluster)) {
1170Sstevel@tonic-gate VN_HOLD(PCTOV(pcp));
1180Sstevel@tonic-gate rw_exit(&pcnodes_lock);
1190Sstevel@tonic-gate return (pcp);
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate }
1220Sstevel@tonic-gate rw_exit(&pcnodes_lock);
1230Sstevel@tonic-gate } else {
1240Sstevel@tonic-gate hp = &pcfhead[PCFHASH(fsp, blkno, offset)];
1250Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_READER);
1260Sstevel@tonic-gate for (pcp = hp->pch_forw;
1270Sstevel@tonic-gate pcp != (struct pcnode *)hp; pcp = pcp->pc_forw) {
1280Sstevel@tonic-gate if ((fsp == VFSTOPCFS(PCTOV(pcp)->v_vfsp)) &&
1290Sstevel@tonic-gate ((pcp->pc_flags & PC_INVAL) == 0) &&
1300Sstevel@tonic-gate (blkno == pcp->pc_eblkno) &&
1310Sstevel@tonic-gate (offset == pcp->pc_eoffset)) {
1320Sstevel@tonic-gate VN_HOLD(PCTOV(pcp));
1330Sstevel@tonic-gate rw_exit(&pcnodes_lock);
1340Sstevel@tonic-gate return (pcp);
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate rw_exit(&pcnodes_lock);
1380Sstevel@tonic-gate }
1390Sstevel@tonic-gate /*
1400Sstevel@tonic-gate * Cannot find node in active list. Allocate memory for a new node
1410Sstevel@tonic-gate * initialize it, and put it on the active list.
1420Sstevel@tonic-gate */
1430Sstevel@tonic-gate pcp = kmem_alloc(sizeof (struct pcnode), KM_SLEEP);
1440Sstevel@tonic-gate bzero(pcp, sizeof (struct pcnode));
1450Sstevel@tonic-gate vp = vn_alloc(KM_SLEEP);
1460Sstevel@tonic-gate pcp->pc_vn = vp;
1470Sstevel@tonic-gate pcp->pc_entry = *ep;
1480Sstevel@tonic-gate pcp->pc_eblkno = blkno;
1490Sstevel@tonic-gate pcp->pc_eoffset = offset;
1500Sstevel@tonic-gate pcp->pc_scluster = scluster;
1510Sstevel@tonic-gate pcp->pc_lcluster = scluster;
1520Sstevel@tonic-gate pcp->pc_lindex = 0;
1530Sstevel@tonic-gate pcp->pc_flags = 0;
1540Sstevel@tonic-gate if (ep->pcd_attr & PCA_DIR) {
1550Sstevel@tonic-gate vn_setops(vp, pcfs_dvnodeops);
1560Sstevel@tonic-gate vp->v_type = VDIR;
1570Sstevel@tonic-gate if (scluster == 0) {
1580Sstevel@tonic-gate vp->v_flag = VROOT;
1590Sstevel@tonic-gate blkno = offset = 0;
1600Sstevel@tonic-gate if (IS_FAT32(fsp)) {
1612972Sfrankho pc_cluster32_t ncl = 0;
1622972Sfrankho
1632972Sfrankho scluster = fsp->pcfs_rdirstart;
1642972Sfrankho if (pc_fileclsize(fsp, scluster, &ncl)) {
1652972Sfrankho PC_DPRINTF1(2, "cluster chain "
1662972Sfrankho "corruption, scluster=%d\n",
1672972Sfrankho scluster);
1682972Sfrankho pcp->pc_flags |= PC_INVAL;
1692972Sfrankho }
1702972Sfrankho pcp->pc_size = fsp->pcfs_clsize * ncl;
1710Sstevel@tonic-gate } else {
1720Sstevel@tonic-gate pcp->pc_size =
1730Sstevel@tonic-gate fsp->pcfs_rdirsec * fsp->pcfs_secsize;
1740Sstevel@tonic-gate }
1752972Sfrankho } else {
1762972Sfrankho pc_cluster32_t ncl = 0;
1772972Sfrankho
1782972Sfrankho if (pc_fileclsize(fsp, scluster, &ncl)) {
1792972Sfrankho PC_DPRINTF1(2, "cluster chain corruption, "
1802972Sfrankho "scluster=%d\n", scluster);
1812972Sfrankho pcp->pc_flags |= PC_INVAL;
1822972Sfrankho }
1832972Sfrankho pcp->pc_size = fsp->pcfs_clsize * ncl;
1842972Sfrankho }
1850Sstevel@tonic-gate } else {
1860Sstevel@tonic-gate vn_setops(vp, pcfs_fvnodeops);
1870Sstevel@tonic-gate vp->v_type = VREG;
1880Sstevel@tonic-gate vp->v_flag = VNOSWAP;
1890Sstevel@tonic-gate fsp->pcfs_frefs++;
1900Sstevel@tonic-gate pcp->pc_size = ltohi(ep->pcd_size);
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate fsp->pcfs_nrefs++;
1932720Sfrankho VFS_HOLD(PCFSTOVFS(fsp));
1940Sstevel@tonic-gate vp->v_data = (caddr_t)pcp;
1950Sstevel@tonic-gate vp->v_vfsp = PCFSTOVFS(fsp);
1960Sstevel@tonic-gate vn_exists(vp);
1970Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_WRITER);
1980Sstevel@tonic-gate insque(pcp, hp);
1990Sstevel@tonic-gate rw_exit(&pcnodes_lock);
2000Sstevel@tonic-gate return (pcp);
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate int
syncpcp(struct pcnode * pcp,int flags)2040Sstevel@tonic-gate syncpcp(struct pcnode *pcp, int flags)
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate int err;
2070Sstevel@tonic-gate if (!vn_has_cached_data(PCTOV(pcp)))
2080Sstevel@tonic-gate err = 0;
2090Sstevel@tonic-gate else
210*5331Samw err = VOP_PUTPAGE(PCTOV(pcp), 0, 0, flags,
211*5331Samw kcred, NULL);
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate return (err);
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate void
pc_rele(struct pcnode * pcp)2170Sstevel@tonic-gate pc_rele(struct pcnode *pcp)
2180Sstevel@tonic-gate {
2190Sstevel@tonic-gate struct pcfs *fsp;
2200Sstevel@tonic-gate struct vnode *vp;
2210Sstevel@tonic-gate int err;
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate vp = PCTOV(pcp);
2240Sstevel@tonic-gate PC_DPRINTF1(8, "pc_rele vp=0x%p\n", (void *)vp);
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
2270Sstevel@tonic-gate ASSERT(fsp->pcfs_flags & PCFS_LOCKED);
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_WRITER);
2300Sstevel@tonic-gate pcp->pc_flags |= PC_RELEHOLD;
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate retry:
2330Sstevel@tonic-gate if (vp->v_type != VDIR && (pcp->pc_flags & PC_INVAL) == 0) {
2340Sstevel@tonic-gate /*
2350Sstevel@tonic-gate * If the file was removed while active it may be safely
2360Sstevel@tonic-gate * truncated now.
2370Sstevel@tonic-gate */
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate if (pcp->pc_entry.pcd_filename[0] == PCD_ERASED) {
2400Sstevel@tonic-gate (void) pc_truncate(pcp, 0);
2410Sstevel@tonic-gate } else if (pcp->pc_flags & PC_CHG) {
2420Sstevel@tonic-gate (void) pc_nodeupdate(pcp);
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate err = syncpcp(pcp, B_INVAL);
2450Sstevel@tonic-gate if (err) {
2465121Sfrankho (void) syncpcp(pcp, B_INVAL | B_FORCE);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate if (vn_has_cached_data(vp)) {
2500Sstevel@tonic-gate /*
2510Sstevel@tonic-gate * pvn_vplist_dirty will abort all old pages
2520Sstevel@tonic-gate */
2530Sstevel@tonic-gate (void) pvn_vplist_dirty(vp, (u_offset_t)0,
2540Sstevel@tonic-gate pcfs_putapage, B_INVAL, (struct cred *)NULL);
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate (void) pc_syncfat(fsp);
2580Sstevel@tonic-gate mutex_enter(&vp->v_lock);
2590Sstevel@tonic-gate if (vn_has_cached_data(vp)) {
2600Sstevel@tonic-gate mutex_exit(&vp->v_lock);
2610Sstevel@tonic-gate goto retry;
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate ASSERT(!vn_has_cached_data(vp));
2640Sstevel@tonic-gate
2650Sstevel@tonic-gate vp->v_count--; /* release our hold from vn_rele */
2660Sstevel@tonic-gate if (vp->v_count > 0) { /* Is this check still needed? */
2670Sstevel@tonic-gate PC_DPRINTF1(3, "pc_rele: pcp=0x%p HELD AGAIN!\n", (void *)pcp);
2680Sstevel@tonic-gate mutex_exit(&vp->v_lock);
2690Sstevel@tonic-gate pcp->pc_flags &= ~PC_RELEHOLD;
2700Sstevel@tonic-gate rw_exit(&pcnodes_lock);
2710Sstevel@tonic-gate return;
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate remque(pcp);
2750Sstevel@tonic-gate rw_exit(&pcnodes_lock);
2762972Sfrankho /*
2772972Sfrankho * XXX - old code had a check for !(pcp->pc_flags & PC_INVAL)
2782972Sfrankho * here. Seems superfluous/incorrect, but then earlier on PC_INVAL
2792972Sfrankho * was never set anywhere in PCFS. Now it is, and we _have_ to drop
2802972Sfrankho * the file reference here. Else, we'd screw up umount/modunload.
2812972Sfrankho */
2822972Sfrankho if ((vp->v_type == VREG)) {
2830Sstevel@tonic-gate fsp->pcfs_frefs--;
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate fsp->pcfs_nrefs--;
2862720Sfrankho VFS_RELE(vp->v_vfsp);
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate if (fsp->pcfs_nrefs < 0) {
2890Sstevel@tonic-gate panic("pc_rele: nrefs count");
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate if (fsp->pcfs_frefs < 0) {
2920Sstevel@tonic-gate panic("pc_rele: frefs count");
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate mutex_exit(&vp->v_lock);
2960Sstevel@tonic-gate vn_invalid(vp);
2970Sstevel@tonic-gate vn_free(vp);
2980Sstevel@tonic-gate kmem_free(pcp, sizeof (struct pcnode));
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate /*
3020Sstevel@tonic-gate * Mark a pcnode as modified with the current time.
3030Sstevel@tonic-gate */
3045121Sfrankho /* ARGSUSED */
3050Sstevel@tonic-gate void
pc_mark_mod(struct pcfs * fsp,struct pcnode * pcp)3065121Sfrankho pc_mark_mod(struct pcfs *fsp, struct pcnode *pcp)
3070Sstevel@tonic-gate {
3080Sstevel@tonic-gate timestruc_t now;
3090Sstevel@tonic-gate
3105121Sfrankho if (PCTOV(pcp)->v_type == VDIR)
3115121Sfrankho return;
3125121Sfrankho
3135121Sfrankho ASSERT(PCTOV(pcp)->v_type == VREG);
3145121Sfrankho
3155121Sfrankho gethrestime(&now);
3165121Sfrankho if (pc_tvtopct(&now, &pcp->pc_entry.pcd_mtime))
3175121Sfrankho PC_DPRINTF1(2, "pc_mark_mod failed timestamp "
3185121Sfrankho "conversion, curtime = %lld\n",
3195121Sfrankho (long long)now.tv_sec);
3205121Sfrankho
3215121Sfrankho pcp->pc_flags |= PC_CHG;
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate /*
3250Sstevel@tonic-gate * Mark a pcnode as accessed with the current time.
3260Sstevel@tonic-gate */
3270Sstevel@tonic-gate void
pc_mark_acc(struct pcfs * fsp,struct pcnode * pcp)3285121Sfrankho pc_mark_acc(struct pcfs *fsp, struct pcnode *pcp)
3290Sstevel@tonic-gate {
3302720Sfrankho struct pctime pt = { 0, 0 };
3310Sstevel@tonic-gate timestruc_t now;
3320Sstevel@tonic-gate
3335121Sfrankho if (fsp->pcfs_flags & PCFS_NOATIME || PCTOV(pcp)->v_type == VDIR)
3345121Sfrankho return;
3355121Sfrankho
3365121Sfrankho ASSERT(PCTOV(pcp)->v_type == VREG);
3375121Sfrankho
3385121Sfrankho gethrestime(&now);
3395121Sfrankho if (pc_tvtopct(&now, &pt)) {
3405121Sfrankho PC_DPRINTF1(2, "pc_mark_acc failed timestamp "
3415121Sfrankho "conversion, curtime = %lld\n",
3425121Sfrankho (long long)now.tv_sec);
3435121Sfrankho return;
3445121Sfrankho }
3455121Sfrankho
3465121Sfrankho /*
3475121Sfrankho * We don't really want to write the adate for every access
3485121Sfrankho * on flash media; make sure it really changed !
3495121Sfrankho */
3505121Sfrankho if (pcp->pc_entry.pcd_ladate != pt.pct_date) {
3510Sstevel@tonic-gate pcp->pc_entry.pcd_ladate = pt.pct_date;
3525121Sfrankho pcp->pc_flags |= (PC_CHG | PC_ACC);
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate /*
3570Sstevel@tonic-gate * Truncate a file to a length.
3580Sstevel@tonic-gate * Node must be locked.
3590Sstevel@tonic-gate */
3600Sstevel@tonic-gate int
pc_truncate(struct pcnode * pcp,uint_t length)3610Sstevel@tonic-gate pc_truncate(struct pcnode *pcp, uint_t length)
3620Sstevel@tonic-gate {
3630Sstevel@tonic-gate struct pcfs *fsp;
3640Sstevel@tonic-gate struct vnode *vp;
3650Sstevel@tonic-gate int error = 0;
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate PC_DPRINTF3(4, "pc_truncate pcp=0x%p, len=%u, size=%u\n",
3680Sstevel@tonic-gate (void *)pcp, length, pcp->pc_size);
3690Sstevel@tonic-gate vp = PCTOV(pcp);
3700Sstevel@tonic-gate if (pcp->pc_flags & PC_INVAL)
3710Sstevel@tonic-gate return (EIO);
3720Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
3730Sstevel@tonic-gate /*
3740Sstevel@tonic-gate * directories are always truncated to zero and are not marked
3750Sstevel@tonic-gate */
3760Sstevel@tonic-gate if (vp->v_type == VDIR) {
3770Sstevel@tonic-gate error = pc_bfree(pcp, 0);
3780Sstevel@tonic-gate return (error);
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate /*
3810Sstevel@tonic-gate * If length is the same as the current size
3820Sstevel@tonic-gate * just mark the pcnode and return.
3830Sstevel@tonic-gate */
3840Sstevel@tonic-gate if (length > pcp->pc_size) {
3850Sstevel@tonic-gate daddr_t bno;
3865121Sfrankho uint_t llcn = howmany((offset_t)length, fsp->pcfs_clsize);
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate /*
3890Sstevel@tonic-gate * We are extending a file.
3900Sstevel@tonic-gate * Extend it with _one_ call to pc_balloc (no holes)
3910Sstevel@tonic-gate * since we don't need to use the block number(s).
3920Sstevel@tonic-gate */
3930Sstevel@tonic-gate if ((daddr_t)howmany((offset_t)pcp->pc_size, fsp->pcfs_clsize) <
3945121Sfrankho (daddr_t)llcn) {
3950Sstevel@tonic-gate error = pc_balloc(pcp, (daddr_t)(llcn - 1), 1, &bno);
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate if (error) {
3982972Sfrankho pc_cluster32_t ncl = 0;
3990Sstevel@tonic-gate PC_DPRINTF1(2, "pc_truncate: error=%d\n", error);
4000Sstevel@tonic-gate /*
4010Sstevel@tonic-gate * probably ran out disk space;
4020Sstevel@tonic-gate * determine current file size
4030Sstevel@tonic-gate */
4042972Sfrankho if (pc_fileclsize(fsp, pcp->pc_scluster, &ncl)) {
4052972Sfrankho PC_DPRINTF1(2, "cluster chain corruption, "
4062972Sfrankho "scluster=%d\n", pcp->pc_scluster);
4072972Sfrankho pcp->pc_flags |= PC_INVAL;
4082972Sfrankho }
4092972Sfrankho pcp->pc_size = fsp->pcfs_clsize * ncl;
4100Sstevel@tonic-gate } else
4110Sstevel@tonic-gate pcp->pc_size = length;
4120Sstevel@tonic-gate
4130Sstevel@tonic-gate } else if (length < pcp->pc_size) {
4140Sstevel@tonic-gate /*
4150Sstevel@tonic-gate * We are shrinking a file.
4160Sstevel@tonic-gate * Free blocks after the block that length points to.
4170Sstevel@tonic-gate */
4180Sstevel@tonic-gate if (pc_blkoff(fsp, length) == 0) {
4190Sstevel@tonic-gate /*
4200Sstevel@tonic-gate * Truncation to a block (cluster size) boundary only
4210Sstevel@tonic-gate * requires us to invalidate everything after the new
4220Sstevel@tonic-gate * end of the file.
4230Sstevel@tonic-gate */
4240Sstevel@tonic-gate (void) pvn_vplist_dirty(PCTOV(pcp), (u_offset_t)length,
4255121Sfrankho pcfs_putapage, B_INVAL | B_TRUNC, CRED());
4260Sstevel@tonic-gate } else {
4270Sstevel@tonic-gate /*
4280Sstevel@tonic-gate * pvn_vpzero() cannot deal with more than MAXBSIZE
4290Sstevel@tonic-gate * chunks. Since the FAT clustersize can get larger
4300Sstevel@tonic-gate * than that, we'll zero from the new length to the
4310Sstevel@tonic-gate * end of the cluster for clustersizes smaller than
4320Sstevel@tonic-gate * MAXBSIZE - or the end of the MAXBSIZE block in
4330Sstevel@tonic-gate * case we've got a large clustersize.
4340Sstevel@tonic-gate */
4350Sstevel@tonic-gate size_t nbytes =
4360Sstevel@tonic-gate roundup(length, MIN(fsp->pcfs_clsize, MAXBSIZE)) -
4370Sstevel@tonic-gate length;
4380Sstevel@tonic-gate
4390Sstevel@tonic-gate pvn_vpzero(PCTOV(pcp), (u_offset_t)length, nbytes);
4400Sstevel@tonic-gate (void) pvn_vplist_dirty(PCTOV(pcp),
4410Sstevel@tonic-gate (u_offset_t)length + nbytes,
4420Sstevel@tonic-gate pcfs_putapage, B_INVAL | B_TRUNC, CRED());
4430Sstevel@tonic-gate }
4445121Sfrankho error = pc_bfree(pcp, (pc_cluster32_t)
4455121Sfrankho howmany((offset_t)length, fsp->pcfs_clsize));
4460Sstevel@tonic-gate pcp->pc_size = length;
4470Sstevel@tonic-gate }
4485121Sfrankho
4495121Sfrankho /*
4505121Sfrankho * This is the only place in PCFS code where pc_mark_mod() is called
4515121Sfrankho * without setting PC_MOD. May be a historical artifact ...
4525121Sfrankho */
4535121Sfrankho pc_mark_mod(fsp, pcp);
4540Sstevel@tonic-gate return (error);
4550Sstevel@tonic-gate }
4560Sstevel@tonic-gate
4570Sstevel@tonic-gate /*
4580Sstevel@tonic-gate * Get block for entry.
4590Sstevel@tonic-gate */
4600Sstevel@tonic-gate static int
pc_getentryblock(struct pcnode * pcp,struct buf ** bpp)4610Sstevel@tonic-gate pc_getentryblock(struct pcnode *pcp, struct buf **bpp)
4620Sstevel@tonic-gate {
4630Sstevel@tonic-gate struct pcfs *fsp;
4640Sstevel@tonic-gate
4650Sstevel@tonic-gate fsp = VFSTOPCFS(PCTOV(pcp)->v_vfsp);
4660Sstevel@tonic-gate if (pcp->pc_eblkno >= fsp->pcfs_datastart ||
4670Sstevel@tonic-gate (pcp->pc_eblkno - fsp->pcfs_rdirstart) <
4680Sstevel@tonic-gate (fsp->pcfs_rdirsec & ~(fsp->pcfs_spcl - 1))) {
4690Sstevel@tonic-gate *bpp = bread(fsp->pcfs_xdev,
4700Sstevel@tonic-gate pc_dbdaddr(fsp, pcp->pc_eblkno), fsp->pcfs_clsize);
4710Sstevel@tonic-gate } else {
4720Sstevel@tonic-gate *bpp = bread(fsp->pcfs_xdev,
4730Sstevel@tonic-gate pc_dbdaddr(fsp, pcp->pc_eblkno),
4745121Sfrankho (int)(fsp->pcfs_datastart - pcp->pc_eblkno) *
4750Sstevel@tonic-gate fsp->pcfs_secsize);
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate if ((*bpp)->b_flags & B_ERROR) {
4780Sstevel@tonic-gate brelse(*bpp);
4790Sstevel@tonic-gate pc_mark_irrecov(fsp);
4800Sstevel@tonic-gate return (EIO);
4810Sstevel@tonic-gate }
4820Sstevel@tonic-gate return (0);
4830Sstevel@tonic-gate }
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate /*
4860Sstevel@tonic-gate * Sync all data associated with a file.
4870Sstevel@tonic-gate * Flush all the blocks in the buffer cache out to disk, sync the FAT and
4880Sstevel@tonic-gate * update the directory entry.
4890Sstevel@tonic-gate */
4900Sstevel@tonic-gate int
pc_nodesync(struct pcnode * pcp)4910Sstevel@tonic-gate pc_nodesync(struct pcnode *pcp)
4920Sstevel@tonic-gate {
4930Sstevel@tonic-gate struct pcfs *fsp;
4940Sstevel@tonic-gate int err;
4950Sstevel@tonic-gate struct vnode *vp;
4960Sstevel@tonic-gate
4970Sstevel@tonic-gate vp = PCTOV(pcp);
4980Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
4990Sstevel@tonic-gate err = 0;
5000Sstevel@tonic-gate if (pcp->pc_flags & PC_MOD) {
5010Sstevel@tonic-gate /*
5020Sstevel@tonic-gate * Flush all data blocks from buffer cache and
5030Sstevel@tonic-gate * update the FAT which points to the data.
5040Sstevel@tonic-gate */
5050Sstevel@tonic-gate if (err = syncpcp(pcp, 0)) { /* %% ?? how to handle error? */
5060Sstevel@tonic-gate if (err == ENOMEM)
5070Sstevel@tonic-gate return (err);
5080Sstevel@tonic-gate else {
5090Sstevel@tonic-gate pc_mark_irrecov(fsp);
5100Sstevel@tonic-gate return (EIO);
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate }
5130Sstevel@tonic-gate pcp->pc_flags &= ~PC_MOD;
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate /*
5160Sstevel@tonic-gate * update the directory entry
5170Sstevel@tonic-gate */
5180Sstevel@tonic-gate if (pcp->pc_flags & PC_CHG)
5190Sstevel@tonic-gate (void) pc_nodeupdate(pcp);
5200Sstevel@tonic-gate return (err);
5210Sstevel@tonic-gate }
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate /*
5240Sstevel@tonic-gate * Update the node's directory entry.
5250Sstevel@tonic-gate */
5260Sstevel@tonic-gate int
pc_nodeupdate(struct pcnode * pcp)5270Sstevel@tonic-gate pc_nodeupdate(struct pcnode *pcp)
5280Sstevel@tonic-gate {
5290Sstevel@tonic-gate struct buf *bp;
5300Sstevel@tonic-gate int error;
5310Sstevel@tonic-gate struct vnode *vp;
5320Sstevel@tonic-gate struct pcfs *fsp;
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate vp = PCTOV(pcp);
5350Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
5360Sstevel@tonic-gate if (IS_FAT32(fsp) && (vp->v_flag & VROOT)) {
5370Sstevel@tonic-gate /* no node to update */
5380Sstevel@tonic-gate pcp->pc_flags &= ~(PC_CHG | PC_MOD | PC_ACC);
5390Sstevel@tonic-gate return (0);
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate if (vp->v_flag & VROOT) {
5420Sstevel@tonic-gate panic("pc_nodeupdate");
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate if (pcp->pc_flags & PC_INVAL)
5450Sstevel@tonic-gate return (0);
5460Sstevel@tonic-gate PC_DPRINTF3(7, "pc_nodeupdate pcp=0x%p, bn=%ld, off=%d\n", (void *)pcp,
5470Sstevel@tonic-gate pcp->pc_eblkno, pcp->pc_eoffset);
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate if (error = pc_getentryblock(pcp, &bp)) {
5500Sstevel@tonic-gate return (error);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate if (vp->v_type == VREG) {
5530Sstevel@tonic-gate if (pcp->pc_flags & PC_CHG)
5540Sstevel@tonic-gate pcp->pc_entry.pcd_attr |= PCA_ARCH;
5550Sstevel@tonic-gate pcp->pc_entry.pcd_size = htoli(pcp->pc_size);
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate pc_setstartcluster(fsp, &pcp->pc_entry, pcp->pc_scluster);
5580Sstevel@tonic-gate *((struct pcdir *)(bp->b_un.b_addr + pcp->pc_eoffset)) = pcp->pc_entry;
5590Sstevel@tonic-gate bwrite2(bp);
5600Sstevel@tonic-gate error = geterror(bp);
5610Sstevel@tonic-gate brelse(bp);
5620Sstevel@tonic-gate if (error) {
5635121Sfrankho error = EIO;
5640Sstevel@tonic-gate pc_mark_irrecov(VFSTOPCFS(vp->v_vfsp));
5650Sstevel@tonic-gate }
5660Sstevel@tonic-gate pcp->pc_flags &= ~(PC_CHG | PC_MOD | PC_ACC);
5670Sstevel@tonic-gate return (error);
5680Sstevel@tonic-gate }
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate /*
5710Sstevel@tonic-gate * Verify that the disk in the drive is the same one that we
5720Sstevel@tonic-gate * got the pcnode from.
5730Sstevel@tonic-gate * MUST be called with node unlocked.
5740Sstevel@tonic-gate */
5750Sstevel@tonic-gate int
pc_verify(struct pcfs * fsp)5760Sstevel@tonic-gate pc_verify(struct pcfs *fsp)
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate int fdstatus = 0;
5790Sstevel@tonic-gate int error = 0;
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate if (!fsp || fsp->pcfs_flags & PCFS_IRRECOV)
5820Sstevel@tonic-gate return (EIO);
5830Sstevel@tonic-gate
5840Sstevel@tonic-gate if (!(fsp->pcfs_flags & PCFS_NOCHK) && fsp->pcfs_fatp) {
5855121Sfrankho /*
5865121Sfrankho * This "has it been removed" check should better be
5875121Sfrankho * modified for removeable media that are not floppies.
5885121Sfrankho * dkio-managed devices such as USB/firewire external
5895121Sfrankho * disks/memory sticks/floppies (gasp) do not understand
5905121Sfrankho * this ioctl.
5915121Sfrankho */
5920Sstevel@tonic-gate PC_DPRINTF1(4, "pc_verify fsp=0x%p\n", (void *)fsp);
5930Sstevel@tonic-gate error = cdev_ioctl(fsp->pcfs_vfs->vfs_dev,
5945121Sfrankho FDGETCHANGE, (intptr_t)&fdstatus, FNATIVE | FKIOCTL,
5950Sstevel@tonic-gate NULL, NULL);
5960Sstevel@tonic-gate
5970Sstevel@tonic-gate if (error) {
5980Sstevel@tonic-gate if (error == ENOTTY || error == ENXIO) {
5995121Sfrankho /*
6005121Sfrankho * See comment above. This is a workaround
6015121Sfrankho * for removeable media that don't understand
6025121Sfrankho * floppy ioctls.
6035121Sfrankho */
6040Sstevel@tonic-gate error = 0;
6050Sstevel@tonic-gate } else {
6060Sstevel@tonic-gate PC_DPRINTF1(1,
6070Sstevel@tonic-gate "pc_verify: FDGETCHANGE ioctl failed: %d\n",
6080Sstevel@tonic-gate error);
6090Sstevel@tonic-gate pc_mark_irrecov(fsp);
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate } else if (fsp->pcfs_fatjustread) {
6120Sstevel@tonic-gate /*
6130Sstevel@tonic-gate * Ignore the results of the ioctl if we just
6140Sstevel@tonic-gate * read the FAT. There is a good chance that
6150Sstevel@tonic-gate * the disk changed bit will be on, because
6160Sstevel@tonic-gate * we've just mounted and we don't want to
6170Sstevel@tonic-gate * give a false positive that the sky is falling.
6180Sstevel@tonic-gate */
6190Sstevel@tonic-gate fsp->pcfs_fatjustread = 0;
6200Sstevel@tonic-gate } else {
6210Sstevel@tonic-gate /*
6220Sstevel@tonic-gate * Oddly enough we can't check just one flag here. The
6230Sstevel@tonic-gate * x86 floppy driver sets a different flag
6240Sstevel@tonic-gate * (FDGC_DETECTED) than the sparc driver does.
6250Sstevel@tonic-gate * I think this MAY be a bug, and I filed 4165938
6260Sstevel@tonic-gate * to get someone to look at the behavior
6270Sstevel@tonic-gate * a bit more closely. In the meantime, my testing and
6280Sstevel@tonic-gate * code examination seem to indicate it is safe to
6290Sstevel@tonic-gate * check for either bit being set.
6300Sstevel@tonic-gate */
6310Sstevel@tonic-gate if (fdstatus & (FDGC_HISTORY | FDGC_DETECTED)) {
6320Sstevel@tonic-gate PC_DPRINTF0(1, "pc_verify: change detected\n");
6330Sstevel@tonic-gate pc_mark_irrecov(fsp);
6340Sstevel@tonic-gate }
6350Sstevel@tonic-gate }
6360Sstevel@tonic-gate }
6375121Sfrankho if (error == 0 && fsp->pcfs_fatp == NULL) {
6380Sstevel@tonic-gate error = pc_getfat(fsp);
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate
6410Sstevel@tonic-gate return (error);
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate
6440Sstevel@tonic-gate /*
6450Sstevel@tonic-gate * The disk has changed, pulling the rug out from beneath us.
6460Sstevel@tonic-gate * Mark the FS as being in an irrecoverable state.
6470Sstevel@tonic-gate * In a short while we'll clean up.
6480Sstevel@tonic-gate */
6490Sstevel@tonic-gate void
pc_mark_irrecov(struct pcfs * fsp)6500Sstevel@tonic-gate pc_mark_irrecov(struct pcfs *fsp)
6510Sstevel@tonic-gate {
6520Sstevel@tonic-gate if (!(fsp->pcfs_flags & PCFS_NOCHK)) {
6530Sstevel@tonic-gate if (pc_lockfs(fsp, 1, 0)) {
6540Sstevel@tonic-gate /*
6550Sstevel@tonic-gate * Locking failed, which currently would
6560Sstevel@tonic-gate * only happen if the FS were already
6570Sstevel@tonic-gate * marked as hosed. If another reason for
6580Sstevel@tonic-gate * failure were to arise in the future, this
6590Sstevel@tonic-gate * routine would have to change.
6600Sstevel@tonic-gate */
6610Sstevel@tonic-gate return;
6620Sstevel@tonic-gate }
6630Sstevel@tonic-gate
6640Sstevel@tonic-gate fsp->pcfs_flags |= PCFS_IRRECOV;
6650Sstevel@tonic-gate cmn_err(CE_WARN,
6665121Sfrankho "Disk was changed during an update or\n"
6675121Sfrankho "an irrecoverable error was encountered.\n"
6685121Sfrankho "File damage is possible. To prevent further\n"
6695121Sfrankho "damage, this pcfs instance will now be frozen.\n"
6705121Sfrankho "Use umount(1M) to release the instance.\n");
6710Sstevel@tonic-gate (void) pc_unlockfs(fsp);
6720Sstevel@tonic-gate }
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate
6750Sstevel@tonic-gate /*
6760Sstevel@tonic-gate * The disk has been changed!
6770Sstevel@tonic-gate */
6780Sstevel@tonic-gate void
pc_diskchanged(struct pcfs * fsp)6790Sstevel@tonic-gate pc_diskchanged(struct pcfs *fsp)
6800Sstevel@tonic-gate {
6812720Sfrankho struct pcnode *pcp, *npcp = NULL;
6822720Sfrankho struct pchead *hp;
6832720Sfrankho struct vnode *vp;
6842720Sfrankho extern vfs_t EIO_vfs;
6852720Sfrankho struct vfs *vfsp;
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate /*
6880Sstevel@tonic-gate * Eliminate all pcnodes (dir & file) associated with this fs.
6890Sstevel@tonic-gate * If the node is internal, ie, no references outside of
6900Sstevel@tonic-gate * pcfs itself, then release the associated vnode structure.
6910Sstevel@tonic-gate * Invalidate the in core FAT.
6920Sstevel@tonic-gate * Invalidate cached data blocks and blocks waiting for I/O.
6930Sstevel@tonic-gate */
6940Sstevel@tonic-gate PC_DPRINTF1(1, "pc_diskchanged fsp=0x%p\n", (void *)fsp);
6950Sstevel@tonic-gate
6962720Sfrankho vfsp = PCFSTOVFS(fsp);
6972720Sfrankho
6980Sstevel@tonic-gate for (hp = pcdhead; hp < &pcdhead[NPCHASH]; hp++) {
6990Sstevel@tonic-gate for (pcp = hp->pch_forw;
7000Sstevel@tonic-gate pcp != (struct pcnode *)hp; pcp = npcp) {
7010Sstevel@tonic-gate npcp = pcp -> pc_forw;
7020Sstevel@tonic-gate vp = PCTOV(pcp);
7032720Sfrankho if ((vp->v_vfsp == vfsp) &&
7040Sstevel@tonic-gate !(pcp->pc_flags & PC_RELEHOLD)) {
7050Sstevel@tonic-gate mutex_enter(&(vp)->v_lock);
7060Sstevel@tonic-gate if (vp->v_count > 0) {
7070Sstevel@tonic-gate mutex_exit(&(vp)->v_lock);
7080Sstevel@tonic-gate continue;
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate mutex_exit(&(vp)->v_lock);
7110Sstevel@tonic-gate VN_HOLD(vp);
7120Sstevel@tonic-gate remque(pcp);
7130Sstevel@tonic-gate vp->v_data = NULL;
7140Sstevel@tonic-gate vp->v_vfsp = &EIO_vfs;
7150Sstevel@tonic-gate vp->v_type = VBAD;
7160Sstevel@tonic-gate VN_RELE(vp);
7172720Sfrankho if (!(pcp->pc_flags & PC_EXTERNAL)) {
7182720Sfrankho (void) pvn_vplist_dirty(vp,
7192720Sfrankho (u_offset_t)0, pcfs_putapage,
7202720Sfrankho B_INVAL | B_TRUNC,
7212720Sfrankho (struct cred *)NULL);
7220Sstevel@tonic-gate vn_free(vp);
7232720Sfrankho }
7240Sstevel@tonic-gate kmem_free(pcp, sizeof (struct pcnode));
7250Sstevel@tonic-gate fsp->pcfs_nrefs --;
7262720Sfrankho VFS_RELE(vfsp);
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate }
7290Sstevel@tonic-gate }
7300Sstevel@tonic-gate for (hp = pcfhead; fsp->pcfs_frefs && hp < &pcfhead[NPCHASH]; hp++) {
7310Sstevel@tonic-gate for (pcp = hp->pch_forw; fsp->pcfs_frefs &&
7320Sstevel@tonic-gate pcp != (struct pcnode *)hp; pcp = npcp) {
7330Sstevel@tonic-gate npcp = pcp -> pc_forw;
7340Sstevel@tonic-gate vp = PCTOV(pcp);
7352720Sfrankho if ((vp->v_vfsp == vfsp) &&
7360Sstevel@tonic-gate !(pcp->pc_flags & PC_RELEHOLD)) {
7370Sstevel@tonic-gate mutex_enter(&(vp)->v_lock);
7380Sstevel@tonic-gate if (vp->v_count > 0) {
7390Sstevel@tonic-gate mutex_exit(&(vp)->v_lock);
7400Sstevel@tonic-gate continue;
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate mutex_exit(&(vp)->v_lock);
7430Sstevel@tonic-gate VN_HOLD(vp);
7440Sstevel@tonic-gate remque(pcp);
7450Sstevel@tonic-gate vp->v_data = NULL;
7460Sstevel@tonic-gate vp->v_vfsp = &EIO_vfs;
7470Sstevel@tonic-gate vp->v_type = VBAD;
7480Sstevel@tonic-gate VN_RELE(vp);
7492720Sfrankho if (!(pcp->pc_flags & PC_EXTERNAL)) {
7502720Sfrankho (void) pvn_vplist_dirty(vp,
7512720Sfrankho (u_offset_t)0, pcfs_putapage,
7522720Sfrankho B_INVAL | B_TRUNC,
7532720Sfrankho (struct cred *)NULL);
7540Sstevel@tonic-gate vn_free(vp);
7552720Sfrankho }
7560Sstevel@tonic-gate kmem_free(pcp, sizeof (struct pcnode));
7572972Sfrankho fsp->pcfs_frefs--;
7582972Sfrankho fsp->pcfs_nrefs--;
7592720Sfrankho VFS_RELE(vfsp);
7600Sstevel@tonic-gate }
7610Sstevel@tonic-gate }
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate #ifdef undef
7640Sstevel@tonic-gate if (fsp->pcfs_frefs) {
7650Sstevel@tonic-gate rw_exit(&pcnodes_lock);
7660Sstevel@tonic-gate panic("pc_diskchanged: frefs");
7670Sstevel@tonic-gate }
7680Sstevel@tonic-gate if (fsp->pcfs_nrefs) {
7690Sstevel@tonic-gate rw_exit(&pcnodes_lock);
7700Sstevel@tonic-gate panic("pc_diskchanged: nrefs");
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate #endif
7732720Sfrankho if (!(vfsp->vfs_flag & VFS_UNMOUNTED) &&
7742720Sfrankho fsp->pcfs_fatp != (uchar_t *)0) {
7750Sstevel@tonic-gate pc_invalfat(fsp);
7760Sstevel@tonic-gate } else {
7770Sstevel@tonic-gate binval(fsp->pcfs_xdev);
7780Sstevel@tonic-gate }
7790Sstevel@tonic-gate }
780