xref: /onnv-gate/usr/src/uts/common/fs/pcfs/pc_node.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/param.h>
30*0Sstevel@tonic-gate #include <sys/t_lock.h>
31*0Sstevel@tonic-gate #include <sys/errno.h>
32*0Sstevel@tonic-gate #include <sys/sysmacros.h>
33*0Sstevel@tonic-gate #include <sys/buf.h>
34*0Sstevel@tonic-gate #include <sys/systm.h>
35*0Sstevel@tonic-gate #include <sys/vfs.h>
36*0Sstevel@tonic-gate #include <sys/vnode.h>
37*0Sstevel@tonic-gate #include <sys/kmem.h>
38*0Sstevel@tonic-gate #include <sys/proc.h>
39*0Sstevel@tonic-gate #include <sys/cred.h>
40*0Sstevel@tonic-gate #include <sys/cmn_err.h>
41*0Sstevel@tonic-gate #include <sys/debug.h>
42*0Sstevel@tonic-gate #include <vm/pvn.h>
43*0Sstevel@tonic-gate #include <sys/fs/pc_label.h>
44*0Sstevel@tonic-gate #include <sys/fs/pc_fs.h>
45*0Sstevel@tonic-gate #include <sys/fs/pc_dir.h>
46*0Sstevel@tonic-gate #include <sys/fs/pc_node.h>
47*0Sstevel@tonic-gate #include <sys/dirent.h>
48*0Sstevel@tonic-gate #include <sys/fdio.h>
49*0Sstevel@tonic-gate #include <sys/file.h>
50*0Sstevel@tonic-gate #include <sys/conf.h>
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate struct pchead pcfhead[NPCHASH];
53*0Sstevel@tonic-gate struct pchead pcdhead[NPCHASH];
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate extern krwlock_t pcnodes_lock;
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate static int	pc_getentryblock(struct pcnode *, struct buf **);
58*0Sstevel@tonic-gate static int	syncpcp(struct pcnode *, int);
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate /*
61*0Sstevel@tonic-gate  * fake entry for root directory, since this does not have a parent
62*0Sstevel@tonic-gate  * pointing to it.
63*0Sstevel@tonic-gate  */
64*0Sstevel@tonic-gate static struct pcdir rootentry = {
65*0Sstevel@tonic-gate 	"",
66*0Sstevel@tonic-gate 	"",
67*0Sstevel@tonic-gate 	PCA_DIR
68*0Sstevel@tonic-gate };
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate void
71*0Sstevel@tonic-gate pc_init(void)
72*0Sstevel@tonic-gate {
73*0Sstevel@tonic-gate 	struct pchead *hdp, *hfp;
74*0Sstevel@tonic-gate 	int i;
75*0Sstevel@tonic-gate 	for (i = 0; i < NPCHASH; i++) {
76*0Sstevel@tonic-gate 		hdp = &pcdhead[i];
77*0Sstevel@tonic-gate 		hfp = &pcfhead[i];
78*0Sstevel@tonic-gate 		hdp->pch_forw =  (struct pcnode *)hdp;
79*0Sstevel@tonic-gate 		hdp->pch_back =  (struct pcnode *)hdp;
80*0Sstevel@tonic-gate 		hfp->pch_forw =  (struct pcnode *)hfp;
81*0Sstevel@tonic-gate 		hfp->pch_back =  (struct pcnode *)hfp;
82*0Sstevel@tonic-gate 	}
83*0Sstevel@tonic-gate }
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate struct pcnode *
86*0Sstevel@tonic-gate pc_getnode(
87*0Sstevel@tonic-gate 	struct pcfs *fsp,	/* filsystem for node */
88*0Sstevel@tonic-gate 	daddr_t blkno,		/* phys block no of dir entry */
89*0Sstevel@tonic-gate 	int offset,		/* offset of dir entry in block */
90*0Sstevel@tonic-gate 	struct pcdir *ep)	/* node dir entry */
91*0Sstevel@tonic-gate {
92*0Sstevel@tonic-gate 	struct pcnode *pcp;
93*0Sstevel@tonic-gate 	struct pchead *hp;
94*0Sstevel@tonic-gate 	struct vnode *vp;
95*0Sstevel@tonic-gate 	pc_cluster32_t scluster;
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 	ASSERT(fsp->pcfs_flags & PCFS_LOCKED);
98*0Sstevel@tonic-gate 	if (ep == (struct pcdir *)0) {
99*0Sstevel@tonic-gate 		ep = &rootentry;
100*0Sstevel@tonic-gate 		scluster = 0;
101*0Sstevel@tonic-gate 	} else {
102*0Sstevel@tonic-gate 		scluster = pc_getstartcluster(fsp, ep);
103*0Sstevel@tonic-gate 	}
104*0Sstevel@tonic-gate 	/*
105*0Sstevel@tonic-gate 	 * First look for active nodes.
106*0Sstevel@tonic-gate 	 * File nodes are identified by the location (blkno, offset) of
107*0Sstevel@tonic-gate 	 * its directory entry.
108*0Sstevel@tonic-gate 	 * Directory nodes are identified by the starting cluster number
109*0Sstevel@tonic-gate 	 * for the entries.
110*0Sstevel@tonic-gate 	 */
111*0Sstevel@tonic-gate 	if (ep->pcd_attr & PCA_DIR) {
112*0Sstevel@tonic-gate 		hp = &pcdhead[PCDHASH(fsp, scluster)];
113*0Sstevel@tonic-gate 		rw_enter(&pcnodes_lock, RW_READER);
114*0Sstevel@tonic-gate 		for (pcp = hp->pch_forw;
115*0Sstevel@tonic-gate 		    pcp != (struct pcnode *)hp; pcp = pcp->pc_forw) {
116*0Sstevel@tonic-gate 			if ((fsp == VFSTOPCFS(PCTOV(pcp)->v_vfsp)) &&
117*0Sstevel@tonic-gate 			    (scluster == pcp->pc_scluster)) {
118*0Sstevel@tonic-gate 				VN_HOLD(PCTOV(pcp));
119*0Sstevel@tonic-gate 				rw_exit(&pcnodes_lock);
120*0Sstevel@tonic-gate 				return (pcp);
121*0Sstevel@tonic-gate 			}
122*0Sstevel@tonic-gate 		}
123*0Sstevel@tonic-gate 		rw_exit(&pcnodes_lock);
124*0Sstevel@tonic-gate 	} else {
125*0Sstevel@tonic-gate 		hp = &pcfhead[PCFHASH(fsp, blkno, offset)];
126*0Sstevel@tonic-gate 		rw_enter(&pcnodes_lock, RW_READER);
127*0Sstevel@tonic-gate 		for (pcp = hp->pch_forw;
128*0Sstevel@tonic-gate 		    pcp != (struct pcnode *)hp; pcp = pcp->pc_forw) {
129*0Sstevel@tonic-gate 			if ((fsp == VFSTOPCFS(PCTOV(pcp)->v_vfsp)) &&
130*0Sstevel@tonic-gate 			    ((pcp->pc_flags & PC_INVAL) == 0) &&
131*0Sstevel@tonic-gate 			    (blkno == pcp->pc_eblkno) &&
132*0Sstevel@tonic-gate 			    (offset == pcp->pc_eoffset)) {
133*0Sstevel@tonic-gate 				VN_HOLD(PCTOV(pcp));
134*0Sstevel@tonic-gate 				rw_exit(&pcnodes_lock);
135*0Sstevel@tonic-gate 				return (pcp);
136*0Sstevel@tonic-gate 			}
137*0Sstevel@tonic-gate 		}
138*0Sstevel@tonic-gate 		rw_exit(&pcnodes_lock);
139*0Sstevel@tonic-gate 	}
140*0Sstevel@tonic-gate 	/*
141*0Sstevel@tonic-gate 	 * Cannot find node in active list. Allocate memory for a new node
142*0Sstevel@tonic-gate 	 * initialize it, and put it on the active list.
143*0Sstevel@tonic-gate 	 */
144*0Sstevel@tonic-gate 	pcp = kmem_alloc(sizeof (struct pcnode), KM_SLEEP);
145*0Sstevel@tonic-gate 	bzero(pcp, sizeof (struct pcnode));
146*0Sstevel@tonic-gate 	vp = vn_alloc(KM_SLEEP);
147*0Sstevel@tonic-gate 	pcp->pc_vn = vp;
148*0Sstevel@tonic-gate 	pcp->pc_entry = *ep;
149*0Sstevel@tonic-gate 	pcp->pc_eblkno = blkno;
150*0Sstevel@tonic-gate 	pcp->pc_eoffset = offset;
151*0Sstevel@tonic-gate 	pcp->pc_scluster = scluster;
152*0Sstevel@tonic-gate 	pcp->pc_lcluster = scluster;
153*0Sstevel@tonic-gate 	pcp->pc_lindex = 0;
154*0Sstevel@tonic-gate 	pcp->pc_flags = 0;
155*0Sstevel@tonic-gate 	if (ep->pcd_attr & PCA_DIR) {
156*0Sstevel@tonic-gate 		vn_setops(vp, pcfs_dvnodeops);
157*0Sstevel@tonic-gate 		vp->v_type = VDIR;
158*0Sstevel@tonic-gate 		if (scluster == 0) {
159*0Sstevel@tonic-gate 			vp->v_flag = VROOT;
160*0Sstevel@tonic-gate 			blkno = offset = 0;
161*0Sstevel@tonic-gate 			if (IS_FAT32(fsp)) {
162*0Sstevel@tonic-gate 				pcp->pc_size = pc_fileclsize(fsp,
163*0Sstevel@tonic-gate 				    fsp->pcfs_rdirstart) * fsp->pcfs_clsize;
164*0Sstevel@tonic-gate 			} else {
165*0Sstevel@tonic-gate 				pcp->pc_size =
166*0Sstevel@tonic-gate 				    fsp->pcfs_rdirsec * fsp->pcfs_secsize;
167*0Sstevel@tonic-gate 			}
168*0Sstevel@tonic-gate 		} else
169*0Sstevel@tonic-gate 			pcp->pc_size = pc_fileclsize(fsp, scluster) *
170*0Sstevel@tonic-gate 			    fsp->pcfs_clsize;
171*0Sstevel@tonic-gate 	} else {
172*0Sstevel@tonic-gate 		vn_setops(vp, pcfs_fvnodeops);
173*0Sstevel@tonic-gate 		vp->v_type = VREG;
174*0Sstevel@tonic-gate 		vp->v_flag = VNOSWAP;
175*0Sstevel@tonic-gate 		fsp->pcfs_frefs++;
176*0Sstevel@tonic-gate 		pcp->pc_size = ltohi(ep->pcd_size);
177*0Sstevel@tonic-gate 	}
178*0Sstevel@tonic-gate 	fsp->pcfs_nrefs++;
179*0Sstevel@tonic-gate 	vp->v_data = (caddr_t)pcp;
180*0Sstevel@tonic-gate 	vp->v_vfsp = PCFSTOVFS(fsp);
181*0Sstevel@tonic-gate 	vn_exists(vp);
182*0Sstevel@tonic-gate 	rw_enter(&pcnodes_lock, RW_WRITER);
183*0Sstevel@tonic-gate 	insque(pcp, hp);
184*0Sstevel@tonic-gate 	rw_exit(&pcnodes_lock);
185*0Sstevel@tonic-gate 	return (pcp);
186*0Sstevel@tonic-gate }
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate int
189*0Sstevel@tonic-gate syncpcp(struct pcnode *pcp, int flags)
190*0Sstevel@tonic-gate {
191*0Sstevel@tonic-gate 	int err;
192*0Sstevel@tonic-gate 	if (!vn_has_cached_data(PCTOV(pcp)))
193*0Sstevel@tonic-gate 		err = 0;
194*0Sstevel@tonic-gate 	else
195*0Sstevel@tonic-gate 		err = VOP_PUTPAGE(PCTOV(pcp), (offset_t)0, (uint_t)0,
196*0Sstevel@tonic-gate 		    flags, (struct cred *)0);
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 	return (err);
199*0Sstevel@tonic-gate }
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate void
202*0Sstevel@tonic-gate pc_rele(struct pcnode *pcp)
203*0Sstevel@tonic-gate {
204*0Sstevel@tonic-gate 	struct pcfs *fsp;
205*0Sstevel@tonic-gate 	struct vnode *vp;
206*0Sstevel@tonic-gate 	int err;
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	vp = PCTOV(pcp);
209*0Sstevel@tonic-gate 	PC_DPRINTF1(8, "pc_rele vp=0x%p\n", (void *)vp);
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
212*0Sstevel@tonic-gate 	ASSERT(fsp->pcfs_flags & PCFS_LOCKED);
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	rw_enter(&pcnodes_lock, RW_WRITER);
215*0Sstevel@tonic-gate 	pcp->pc_flags |= PC_RELEHOLD;
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate retry:
218*0Sstevel@tonic-gate 	if (vp->v_type != VDIR && (pcp->pc_flags & PC_INVAL) == 0) {
219*0Sstevel@tonic-gate 		/*
220*0Sstevel@tonic-gate 		 * If the file was removed while active it may be safely
221*0Sstevel@tonic-gate 		 * truncated now.
222*0Sstevel@tonic-gate 		 */
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 		if (pcp->pc_entry.pcd_filename[0] == PCD_ERASED) {
225*0Sstevel@tonic-gate 			(void) pc_truncate(pcp, 0);
226*0Sstevel@tonic-gate 		} else if (pcp->pc_flags & PC_CHG) {
227*0Sstevel@tonic-gate 			(void) pc_nodeupdate(pcp);
228*0Sstevel@tonic-gate 		}
229*0Sstevel@tonic-gate 		err = syncpcp(pcp, B_INVAL);
230*0Sstevel@tonic-gate 		if (err) {
231*0Sstevel@tonic-gate 			(void) syncpcp(pcp, B_INVAL|B_FORCE);
232*0Sstevel@tonic-gate 		}
233*0Sstevel@tonic-gate 	}
234*0Sstevel@tonic-gate 	if (vn_has_cached_data(vp)) {
235*0Sstevel@tonic-gate 		/*
236*0Sstevel@tonic-gate 		 * pvn_vplist_dirty will abort all old pages
237*0Sstevel@tonic-gate 		 */
238*0Sstevel@tonic-gate 		(void) pvn_vplist_dirty(vp, (u_offset_t)0,
239*0Sstevel@tonic-gate 		    pcfs_putapage, B_INVAL, (struct cred *)NULL);
240*0Sstevel@tonic-gate 	}
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	(void) pc_syncfat(fsp);
243*0Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
244*0Sstevel@tonic-gate 	if (vn_has_cached_data(vp)) {
245*0Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
246*0Sstevel@tonic-gate 		goto retry;
247*0Sstevel@tonic-gate 	}
248*0Sstevel@tonic-gate 	ASSERT(!vn_has_cached_data(vp));
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	vp->v_count--;  /* release our hold from vn_rele */
251*0Sstevel@tonic-gate 	if (vp->v_count > 0) { /* Is this check still needed? */
252*0Sstevel@tonic-gate 		PC_DPRINTF1(3, "pc_rele: pcp=0x%p HELD AGAIN!\n", (void *)pcp);
253*0Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
254*0Sstevel@tonic-gate 		pcp->pc_flags &= ~PC_RELEHOLD;
255*0Sstevel@tonic-gate 		rw_exit(&pcnodes_lock);
256*0Sstevel@tonic-gate 		return;
257*0Sstevel@tonic-gate 	}
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 	remque(pcp);
260*0Sstevel@tonic-gate 	rw_exit(&pcnodes_lock);
261*0Sstevel@tonic-gate 	if ((vp->v_type == VREG) && !(pcp->pc_flags & PC_INVAL)) {
262*0Sstevel@tonic-gate 		fsp->pcfs_frefs--;
263*0Sstevel@tonic-gate 	}
264*0Sstevel@tonic-gate 	fsp->pcfs_nrefs--;
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	if (fsp->pcfs_nrefs < 0) {
267*0Sstevel@tonic-gate 		panic("pc_rele: nrefs count");
268*0Sstevel@tonic-gate 	}
269*0Sstevel@tonic-gate 	if (fsp->pcfs_frefs < 0) {
270*0Sstevel@tonic-gate 		panic("pc_rele: frefs count");
271*0Sstevel@tonic-gate 	}
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
274*0Sstevel@tonic-gate 	vn_invalid(vp);
275*0Sstevel@tonic-gate 	vn_free(vp);
276*0Sstevel@tonic-gate 	kmem_free(pcp, sizeof (struct pcnode));
277*0Sstevel@tonic-gate }
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate /*
280*0Sstevel@tonic-gate  * Mark a pcnode as modified with the current time.
281*0Sstevel@tonic-gate  */
282*0Sstevel@tonic-gate void
283*0Sstevel@tonic-gate pc_mark_mod(struct pcnode *pcp)
284*0Sstevel@tonic-gate {
285*0Sstevel@tonic-gate 	timestruc_t now;
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	if (PCTOV(pcp)->v_type == VREG) {
288*0Sstevel@tonic-gate 		gethrestime(&now);
289*0Sstevel@tonic-gate 		pc_tvtopct(&now, &pcp->pc_entry.pcd_mtime);
290*0Sstevel@tonic-gate 		pcp->pc_flags |= PC_CHG;
291*0Sstevel@tonic-gate 	}
292*0Sstevel@tonic-gate }
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate /*
295*0Sstevel@tonic-gate  * Mark a pcnode as accessed with the current time.
296*0Sstevel@tonic-gate  */
297*0Sstevel@tonic-gate void
298*0Sstevel@tonic-gate pc_mark_acc(struct pcnode *pcp)
299*0Sstevel@tonic-gate {
300*0Sstevel@tonic-gate 	struct pctime pt;
301*0Sstevel@tonic-gate 	timestruc_t now;
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 	if (PCTOV(pcp)->v_type == VREG) {
304*0Sstevel@tonic-gate 		gethrestime(&now);
305*0Sstevel@tonic-gate 		pc_tvtopct(&now, &pt);
306*0Sstevel@tonic-gate 		pcp->pc_entry.pcd_ladate = pt.pct_date;
307*0Sstevel@tonic-gate 		pcp->pc_flags |= PC_CHG;
308*0Sstevel@tonic-gate 	}
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate /*
312*0Sstevel@tonic-gate  * Truncate a file to a length.
313*0Sstevel@tonic-gate  * Node must be locked.
314*0Sstevel@tonic-gate  */
315*0Sstevel@tonic-gate int
316*0Sstevel@tonic-gate pc_truncate(struct pcnode *pcp, uint_t length)
317*0Sstevel@tonic-gate {
318*0Sstevel@tonic-gate 	struct pcfs *fsp;
319*0Sstevel@tonic-gate 	struct vnode *vp;
320*0Sstevel@tonic-gate 	int error = 0;
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	PC_DPRINTF3(4, "pc_truncate pcp=0x%p, len=%u, size=%u\n",
323*0Sstevel@tonic-gate 	    (void *)pcp, length, pcp->pc_size);
324*0Sstevel@tonic-gate 	vp = PCTOV(pcp);
325*0Sstevel@tonic-gate 	if (pcp->pc_flags & PC_INVAL)
326*0Sstevel@tonic-gate 		return (EIO);
327*0Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
328*0Sstevel@tonic-gate 	/*
329*0Sstevel@tonic-gate 	 * directories are always truncated to zero and are not marked
330*0Sstevel@tonic-gate 	 */
331*0Sstevel@tonic-gate 	if (vp->v_type == VDIR) {
332*0Sstevel@tonic-gate 		error = pc_bfree(pcp, 0);
333*0Sstevel@tonic-gate 		return (error);
334*0Sstevel@tonic-gate 	}
335*0Sstevel@tonic-gate 	/*
336*0Sstevel@tonic-gate 	 * If length is the same as the current size
337*0Sstevel@tonic-gate 	 * just mark the pcnode and return.
338*0Sstevel@tonic-gate 	 */
339*0Sstevel@tonic-gate 	if (length > pcp->pc_size) {
340*0Sstevel@tonic-gate 		daddr_t bno;
341*0Sstevel@tonic-gate 		uint_t llcn;
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 		/*
344*0Sstevel@tonic-gate 		 * We are extending a file.
345*0Sstevel@tonic-gate 		 * Extend it with _one_ call to pc_balloc (no holes)
346*0Sstevel@tonic-gate 		 * since we don't need to use the block number(s).
347*0Sstevel@tonic-gate 		 */
348*0Sstevel@tonic-gate 		if ((daddr_t)howmany((offset_t)pcp->pc_size, fsp->pcfs_clsize) <
349*0Sstevel@tonic-gate 		    (llcn = (daddr_t)howmany((offset_t)length,
350*0Sstevel@tonic-gate 				fsp->pcfs_clsize))) {
351*0Sstevel@tonic-gate 			error = pc_balloc(pcp, (daddr_t)(llcn - 1), 1, &bno);
352*0Sstevel@tonic-gate 		}
353*0Sstevel@tonic-gate 		if (error) {
354*0Sstevel@tonic-gate 			PC_DPRINTF1(2, "pc_truncate: error=%d\n", error);
355*0Sstevel@tonic-gate 			/*
356*0Sstevel@tonic-gate 			 * probably ran out disk space;
357*0Sstevel@tonic-gate 			 * determine current file size
358*0Sstevel@tonic-gate 			 */
359*0Sstevel@tonic-gate 			pcp->pc_size = fsp->pcfs_clsize *
360*0Sstevel@tonic-gate 			    pc_fileclsize(fsp, pcp->pc_scluster);
361*0Sstevel@tonic-gate 		} else
362*0Sstevel@tonic-gate 			pcp->pc_size = length;
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 	} else if (length < pcp->pc_size) {
365*0Sstevel@tonic-gate 		/*
366*0Sstevel@tonic-gate 		 * We are shrinking a file.
367*0Sstevel@tonic-gate 		 * Free blocks after the block that length points to.
368*0Sstevel@tonic-gate 		 */
369*0Sstevel@tonic-gate 		if (pc_blkoff(fsp, length) == 0) {
370*0Sstevel@tonic-gate 			/*
371*0Sstevel@tonic-gate 			 * Truncation to a block (cluster size) boundary only
372*0Sstevel@tonic-gate 			 * requires us to invalidate everything after the new
373*0Sstevel@tonic-gate 			 * end of the file.
374*0Sstevel@tonic-gate 			 */
375*0Sstevel@tonic-gate 			(void) pvn_vplist_dirty(PCTOV(pcp), (u_offset_t)length,
376*0Sstevel@tonic-gate 				pcfs_putapage, B_INVAL | B_TRUNC, CRED());
377*0Sstevel@tonic-gate 		} else {
378*0Sstevel@tonic-gate 			/*
379*0Sstevel@tonic-gate 			 * pvn_vpzero() cannot deal with more than MAXBSIZE
380*0Sstevel@tonic-gate 			 * chunks. Since the FAT clustersize can get larger
381*0Sstevel@tonic-gate 			 * than that, we'll zero from the new length to the
382*0Sstevel@tonic-gate 			 * end of the cluster for clustersizes smaller than
383*0Sstevel@tonic-gate 			 * MAXBSIZE - or the end of the MAXBSIZE block in
384*0Sstevel@tonic-gate 			 * case we've got a large clustersize.
385*0Sstevel@tonic-gate 			 */
386*0Sstevel@tonic-gate 			size_t nbytes =
387*0Sstevel@tonic-gate 			    roundup(length, MIN(fsp->pcfs_clsize, MAXBSIZE)) -
388*0Sstevel@tonic-gate 			    length;
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 			pvn_vpzero(PCTOV(pcp), (u_offset_t)length, nbytes);
391*0Sstevel@tonic-gate 			(void) pvn_vplist_dirty(PCTOV(pcp),
392*0Sstevel@tonic-gate 			    (u_offset_t)length + nbytes,
393*0Sstevel@tonic-gate 			    pcfs_putapage, B_INVAL | B_TRUNC, CRED());
394*0Sstevel@tonic-gate 		}
395*0Sstevel@tonic-gate 		error = pc_bfree(pcp,
396*0Sstevel@tonic-gate 		    (pc_cluster32_t)howmany((offset_t)length,
397*0Sstevel@tonic-gate 			    fsp->pcfs_clsize));
398*0Sstevel@tonic-gate 		pcp->pc_size = length;
399*0Sstevel@tonic-gate 	}
400*0Sstevel@tonic-gate 	pc_mark_mod(pcp);
401*0Sstevel@tonic-gate 	return (error);
402*0Sstevel@tonic-gate }
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate /*
405*0Sstevel@tonic-gate  * Get block for entry.
406*0Sstevel@tonic-gate  */
407*0Sstevel@tonic-gate static int
408*0Sstevel@tonic-gate pc_getentryblock(struct pcnode *pcp, struct buf **bpp)
409*0Sstevel@tonic-gate {
410*0Sstevel@tonic-gate 	struct pcfs *fsp;
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 	PC_DPRINTF0(7, "pc_getentryblock ");
413*0Sstevel@tonic-gate 	fsp = VFSTOPCFS(PCTOV(pcp)->v_vfsp);
414*0Sstevel@tonic-gate 	if (pcp->pc_eblkno >= fsp->pcfs_datastart ||
415*0Sstevel@tonic-gate 	    (pcp->pc_eblkno - fsp->pcfs_rdirstart) <
416*0Sstevel@tonic-gate 	    (fsp->pcfs_rdirsec & ~(fsp->pcfs_spcl - 1))) {
417*0Sstevel@tonic-gate 		*bpp = bread(fsp->pcfs_xdev,
418*0Sstevel@tonic-gate 		    pc_dbdaddr(fsp, pcp->pc_eblkno), fsp->pcfs_clsize);
419*0Sstevel@tonic-gate 	} else {
420*0Sstevel@tonic-gate 		*bpp = bread(fsp->pcfs_xdev,
421*0Sstevel@tonic-gate 		    pc_dbdaddr(fsp, pcp->pc_eblkno),
422*0Sstevel@tonic-gate 		    (int)(fsp->pcfs_datastart-pcp->pc_eblkno) *
423*0Sstevel@tonic-gate 		    fsp->pcfs_secsize);
424*0Sstevel@tonic-gate 	}
425*0Sstevel@tonic-gate 	if ((*bpp)->b_flags & B_ERROR) {
426*0Sstevel@tonic-gate 		PC_DPRINTF0(1, "pc_getentryblock: error ");
427*0Sstevel@tonic-gate 		brelse(*bpp);
428*0Sstevel@tonic-gate 		pc_mark_irrecov(fsp);
429*0Sstevel@tonic-gate 		return (EIO);
430*0Sstevel@tonic-gate 	}
431*0Sstevel@tonic-gate 	return (0);
432*0Sstevel@tonic-gate }
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate /*
435*0Sstevel@tonic-gate  * Sync all data associated with a file.
436*0Sstevel@tonic-gate  * Flush all the blocks in the buffer cache out to disk, sync the FAT and
437*0Sstevel@tonic-gate  * update the directory entry.
438*0Sstevel@tonic-gate  */
439*0Sstevel@tonic-gate int
440*0Sstevel@tonic-gate pc_nodesync(struct pcnode *pcp)
441*0Sstevel@tonic-gate {
442*0Sstevel@tonic-gate 	struct pcfs *fsp;
443*0Sstevel@tonic-gate 	int err;
444*0Sstevel@tonic-gate 	struct vnode *vp;
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 	PC_DPRINTF1(7, "pc_nodesync pcp=0x%p\n", (void *)pcp);
447*0Sstevel@tonic-gate 	vp = PCTOV(pcp);
448*0Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
449*0Sstevel@tonic-gate 	err = 0;
450*0Sstevel@tonic-gate 	if (pcp->pc_flags & PC_MOD) {
451*0Sstevel@tonic-gate 		/*
452*0Sstevel@tonic-gate 		 * Flush all data blocks from buffer cache and
453*0Sstevel@tonic-gate 		 * update the FAT which points to the data.
454*0Sstevel@tonic-gate 		 */
455*0Sstevel@tonic-gate 		if (err = syncpcp(pcp, 0)) { /* %% ?? how to handle error? */
456*0Sstevel@tonic-gate 			if (err == ENOMEM)
457*0Sstevel@tonic-gate 				return (err);
458*0Sstevel@tonic-gate 			else {
459*0Sstevel@tonic-gate 				pc_mark_irrecov(fsp);
460*0Sstevel@tonic-gate 				return (EIO);
461*0Sstevel@tonic-gate 			}
462*0Sstevel@tonic-gate 		}
463*0Sstevel@tonic-gate 		pcp->pc_flags &= ~PC_MOD;
464*0Sstevel@tonic-gate 	}
465*0Sstevel@tonic-gate 	/*
466*0Sstevel@tonic-gate 	 * update the directory entry
467*0Sstevel@tonic-gate 	 */
468*0Sstevel@tonic-gate 	if (pcp->pc_flags & PC_CHG)
469*0Sstevel@tonic-gate 		(void) pc_nodeupdate(pcp);
470*0Sstevel@tonic-gate 	return (err);
471*0Sstevel@tonic-gate }
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate /*
474*0Sstevel@tonic-gate  * Update the node's directory entry.
475*0Sstevel@tonic-gate  */
476*0Sstevel@tonic-gate int
477*0Sstevel@tonic-gate pc_nodeupdate(struct pcnode *pcp)
478*0Sstevel@tonic-gate {
479*0Sstevel@tonic-gate 	struct buf *bp;
480*0Sstevel@tonic-gate 	int error;
481*0Sstevel@tonic-gate 	struct vnode *vp;
482*0Sstevel@tonic-gate 	struct pcfs *fsp;
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 	vp = PCTOV(pcp);
485*0Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
486*0Sstevel@tonic-gate 	if (IS_FAT32(fsp) && (vp->v_flag & VROOT)) {
487*0Sstevel@tonic-gate 		/* no node to update */
488*0Sstevel@tonic-gate 		pcp->pc_flags &= ~(PC_CHG | PC_MOD | PC_ACC);
489*0Sstevel@tonic-gate 		return (0);
490*0Sstevel@tonic-gate 	}
491*0Sstevel@tonic-gate 	if (vp->v_flag & VROOT) {
492*0Sstevel@tonic-gate 		panic("pc_nodeupdate");
493*0Sstevel@tonic-gate 	}
494*0Sstevel@tonic-gate 	if (pcp->pc_flags & PC_INVAL)
495*0Sstevel@tonic-gate 		return (0);
496*0Sstevel@tonic-gate 	PC_DPRINTF3(7, "pc_nodeupdate pcp=0x%p, bn=%ld, off=%d\n", (void *)pcp,
497*0Sstevel@tonic-gate 	    pcp->pc_eblkno, pcp->pc_eoffset);
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 	if (error = pc_getentryblock(pcp, &bp)) {
500*0Sstevel@tonic-gate 		return (error);
501*0Sstevel@tonic-gate 	}
502*0Sstevel@tonic-gate 	if (vp->v_type == VREG) {
503*0Sstevel@tonic-gate 		if (pcp->pc_flags & PC_CHG)
504*0Sstevel@tonic-gate 			pcp->pc_entry.pcd_attr |= PCA_ARCH;
505*0Sstevel@tonic-gate 		pcp->pc_entry.pcd_size = htoli(pcp->pc_size);
506*0Sstevel@tonic-gate 	}
507*0Sstevel@tonic-gate 	pc_setstartcluster(fsp, &pcp->pc_entry, pcp->pc_scluster);
508*0Sstevel@tonic-gate 	*((struct pcdir *)(bp->b_un.b_addr + pcp->pc_eoffset)) = pcp->pc_entry;
509*0Sstevel@tonic-gate 	bwrite2(bp);
510*0Sstevel@tonic-gate 	error = geterror(bp);
511*0Sstevel@tonic-gate 	if (error)
512*0Sstevel@tonic-gate 		error = EIO;
513*0Sstevel@tonic-gate 	brelse(bp);
514*0Sstevel@tonic-gate 	if (error) {
515*0Sstevel@tonic-gate 		PC_DPRINTF0(1, "pc_nodeupdate ERROR\n");
516*0Sstevel@tonic-gate 		pc_mark_irrecov(VFSTOPCFS(vp->v_vfsp));
517*0Sstevel@tonic-gate 	}
518*0Sstevel@tonic-gate 	pcp->pc_flags &= ~(PC_CHG | PC_MOD | PC_ACC);
519*0Sstevel@tonic-gate 	return (error);
520*0Sstevel@tonic-gate }
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate /*
523*0Sstevel@tonic-gate  * Verify that the disk in the drive is the same one that we
524*0Sstevel@tonic-gate  * got the pcnode from.
525*0Sstevel@tonic-gate  * MUST be called with node unlocked.
526*0Sstevel@tonic-gate  */
527*0Sstevel@tonic-gate /* ARGSUSED */
528*0Sstevel@tonic-gate int
529*0Sstevel@tonic-gate pc_verify(struct pcfs *fsp)
530*0Sstevel@tonic-gate {
531*0Sstevel@tonic-gate 	int fdstatus = 0;
532*0Sstevel@tonic-gate 	int error = 0;
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	if (!fsp || fsp->pcfs_flags & PCFS_IRRECOV)
535*0Sstevel@tonic-gate 		return (EIO);
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 	if (!(fsp->pcfs_flags & PCFS_NOCHK) && fsp->pcfs_fatp) {
538*0Sstevel@tonic-gate 		PC_DPRINTF1(4, "pc_verify fsp=0x%p\n", (void *)fsp);
539*0Sstevel@tonic-gate 		error = cdev_ioctl(fsp->pcfs_vfs->vfs_dev,
540*0Sstevel@tonic-gate 		    FDGETCHANGE, (intptr_t)&fdstatus, FNATIVE|FKIOCTL,
541*0Sstevel@tonic-gate 		    NULL, NULL);
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate 		if (error) {
544*0Sstevel@tonic-gate 			if (error == ENOTTY || error == ENXIO) {
545*0Sstevel@tonic-gate 				error = 0;
546*0Sstevel@tonic-gate 			} else {
547*0Sstevel@tonic-gate 				PC_DPRINTF1(1,
548*0Sstevel@tonic-gate 				    "pc_verify: FDGETCHANGE ioctl failed: %d\n",
549*0Sstevel@tonic-gate 				    error);
550*0Sstevel@tonic-gate 				pc_mark_irrecov(fsp);
551*0Sstevel@tonic-gate 			}
552*0Sstevel@tonic-gate 		} else if (fsp->pcfs_fatjustread) {
553*0Sstevel@tonic-gate 			/*
554*0Sstevel@tonic-gate 			 * Ignore the results of the ioctl if we just
555*0Sstevel@tonic-gate 			 * read the FAT.  There is a good chance that
556*0Sstevel@tonic-gate 			 * the disk changed bit will be on, because
557*0Sstevel@tonic-gate 			 * we've just mounted and we don't want to
558*0Sstevel@tonic-gate 			 * give a false positive that the sky is falling.
559*0Sstevel@tonic-gate 			 */
560*0Sstevel@tonic-gate 			fsp->pcfs_fatjustread = 0;
561*0Sstevel@tonic-gate 		} else {
562*0Sstevel@tonic-gate 			/*
563*0Sstevel@tonic-gate 			 * Oddly enough we can't check just one flag here. The
564*0Sstevel@tonic-gate 			 * x86 floppy driver sets a different flag
565*0Sstevel@tonic-gate 			 * (FDGC_DETECTED) than the sparc driver does.
566*0Sstevel@tonic-gate 			 * I think this MAY be a bug, and I filed 4165938
567*0Sstevel@tonic-gate 			 * to get someone to look at the behavior
568*0Sstevel@tonic-gate 			 * a bit more closely.  In the meantime, my testing and
569*0Sstevel@tonic-gate 			 * code examination seem to indicate it is safe to
570*0Sstevel@tonic-gate 			 * check for either bit being set.
571*0Sstevel@tonic-gate 			 */
572*0Sstevel@tonic-gate 			if (fdstatus & (FDGC_HISTORY | FDGC_DETECTED)) {
573*0Sstevel@tonic-gate 				PC_DPRINTF0(1, "pc_verify: change detected\n");
574*0Sstevel@tonic-gate 				pc_mark_irrecov(fsp);
575*0Sstevel@tonic-gate 			}
576*0Sstevel@tonic-gate 		}
577*0Sstevel@tonic-gate 	}
578*0Sstevel@tonic-gate 	if (!(error || fsp->pcfs_fatp)) {
579*0Sstevel@tonic-gate 		error = pc_getfat(fsp);
580*0Sstevel@tonic-gate 	}
581*0Sstevel@tonic-gate 
582*0Sstevel@tonic-gate 	return (error);
583*0Sstevel@tonic-gate }
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate /*
586*0Sstevel@tonic-gate  * The disk has changed, pulling the rug out from beneath us.
587*0Sstevel@tonic-gate  * Mark the FS as being in an irrecoverable state.
588*0Sstevel@tonic-gate  * In a short while we'll clean up.
589*0Sstevel@tonic-gate  */
590*0Sstevel@tonic-gate void
591*0Sstevel@tonic-gate pc_mark_irrecov(struct pcfs *fsp)
592*0Sstevel@tonic-gate {
593*0Sstevel@tonic-gate 	if (!(fsp->pcfs_flags & PCFS_NOCHK)) {
594*0Sstevel@tonic-gate 		if (pc_lockfs(fsp, 1, 0)) {
595*0Sstevel@tonic-gate 			/*
596*0Sstevel@tonic-gate 			 * Locking failed, which currently would
597*0Sstevel@tonic-gate 			 * only happen if the FS were already
598*0Sstevel@tonic-gate 			 * marked as hosed.  If another reason for
599*0Sstevel@tonic-gate 			 * failure were to arise in the future, this
600*0Sstevel@tonic-gate 			 * routine would have to change.
601*0Sstevel@tonic-gate 			 */
602*0Sstevel@tonic-gate 			return;
603*0Sstevel@tonic-gate 		}
604*0Sstevel@tonic-gate 
605*0Sstevel@tonic-gate 		fsp->pcfs_flags |= PCFS_IRRECOV;
606*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
607*0Sstevel@tonic-gate 			"Disk was changed during an update or\n"
608*0Sstevel@tonic-gate 			"an irrecoverable error was encountered.\n"
609*0Sstevel@tonic-gate 			"File damage is possible.  To prevent further\n"
610*0Sstevel@tonic-gate 			"damage, this pcfs instance will now be frozen.\n"
611*0Sstevel@tonic-gate 			"Use umount(1M) to release the instance.\n");
612*0Sstevel@tonic-gate 		(void) pc_unlockfs(fsp);
613*0Sstevel@tonic-gate 	}
614*0Sstevel@tonic-gate }
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate /*
617*0Sstevel@tonic-gate  * The disk has been changed!
618*0Sstevel@tonic-gate  */
619*0Sstevel@tonic-gate void
620*0Sstevel@tonic-gate pc_diskchanged(struct pcfs *fsp)
621*0Sstevel@tonic-gate {
622*0Sstevel@tonic-gate 	struct pcnode *pcp, *npcp = NULL;
623*0Sstevel@tonic-gate 	struct pchead *hp;
624*0Sstevel@tonic-gate 	struct vnode  *vp;
625*0Sstevel@tonic-gate 	extern vfs_t    EIO_vfs;
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 	/*
628*0Sstevel@tonic-gate 	 * Eliminate all pcnodes (dir & file) associated with this fs.
629*0Sstevel@tonic-gate 	 * If the node is internal, ie, no references outside of
630*0Sstevel@tonic-gate 	 * pcfs itself, then release the associated vnode structure.
631*0Sstevel@tonic-gate 	 * Invalidate the in core FAT.
632*0Sstevel@tonic-gate 	 * Invalidate cached data blocks and blocks waiting for I/O.
633*0Sstevel@tonic-gate 	 */
634*0Sstevel@tonic-gate 	PC_DPRINTF1(1, "pc_diskchanged fsp=0x%p\n", (void *)fsp);
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 	for (hp = pcdhead; hp < &pcdhead[NPCHASH]; hp++) {
637*0Sstevel@tonic-gate 		for (pcp = hp->pch_forw;
638*0Sstevel@tonic-gate 		    pcp != (struct pcnode *)hp; pcp = npcp) {
639*0Sstevel@tonic-gate 			npcp = pcp -> pc_forw;
640*0Sstevel@tonic-gate 			vp = PCTOV(pcp);
641*0Sstevel@tonic-gate 			if (VFSTOPCFS(vp->v_vfsp) == fsp &&
642*0Sstevel@tonic-gate 			    !(pcp->pc_flags & PC_RELEHOLD)) {
643*0Sstevel@tonic-gate 				mutex_enter(&(vp)->v_lock);
644*0Sstevel@tonic-gate 				if (vp->v_count > 0) {
645*0Sstevel@tonic-gate 					mutex_exit(&(vp)->v_lock);
646*0Sstevel@tonic-gate 					continue;
647*0Sstevel@tonic-gate 				}
648*0Sstevel@tonic-gate 				mutex_exit(&(vp)->v_lock);
649*0Sstevel@tonic-gate 				VN_HOLD(vp);
650*0Sstevel@tonic-gate 				remque(pcp);
651*0Sstevel@tonic-gate 				vp->v_data = NULL;
652*0Sstevel@tonic-gate 				vp->v_vfsp = &EIO_vfs;
653*0Sstevel@tonic-gate 				vp->v_type = VBAD;
654*0Sstevel@tonic-gate 				VN_RELE(vp);
655*0Sstevel@tonic-gate 				if (!(pcp->pc_flags & PC_EXTERNAL))
656*0Sstevel@tonic-gate 					vn_free(vp);
657*0Sstevel@tonic-gate 				kmem_free(pcp, sizeof (struct pcnode));
658*0Sstevel@tonic-gate 				fsp->pcfs_nrefs --;
659*0Sstevel@tonic-gate 			}
660*0Sstevel@tonic-gate 		}
661*0Sstevel@tonic-gate 	}
662*0Sstevel@tonic-gate 	for (hp = pcfhead; fsp->pcfs_frefs && hp < &pcfhead[NPCHASH]; hp++) {
663*0Sstevel@tonic-gate 		for (pcp = hp->pch_forw; fsp->pcfs_frefs &&
664*0Sstevel@tonic-gate 		    pcp != (struct pcnode *)hp; pcp = npcp) {
665*0Sstevel@tonic-gate 			npcp = pcp -> pc_forw;
666*0Sstevel@tonic-gate 			vp = PCTOV(pcp);
667*0Sstevel@tonic-gate 			if (VFSTOPCFS(vp->v_vfsp) == fsp &&
668*0Sstevel@tonic-gate 			    !(pcp->pc_flags & PC_RELEHOLD)) {
669*0Sstevel@tonic-gate 				mutex_enter(&(vp)->v_lock);
670*0Sstevel@tonic-gate 				if (vp->v_count > 0) {
671*0Sstevel@tonic-gate 					mutex_exit(&(vp)->v_lock);
672*0Sstevel@tonic-gate 					continue;
673*0Sstevel@tonic-gate 				}
674*0Sstevel@tonic-gate 				mutex_exit(&(vp)->v_lock);
675*0Sstevel@tonic-gate 				VN_HOLD(vp);
676*0Sstevel@tonic-gate 				remque(pcp);
677*0Sstevel@tonic-gate 				vp->v_data = NULL;
678*0Sstevel@tonic-gate 				vp->v_vfsp = &EIO_vfs;
679*0Sstevel@tonic-gate 				vp->v_type = VBAD;
680*0Sstevel@tonic-gate 				VN_RELE(vp);
681*0Sstevel@tonic-gate 				if (!(pcp->pc_flags & PC_EXTERNAL))
682*0Sstevel@tonic-gate 					vn_free(vp);
683*0Sstevel@tonic-gate 				kmem_free(pcp, sizeof (struct pcnode));
684*0Sstevel@tonic-gate 				fsp->pcfs_frefs --;
685*0Sstevel@tonic-gate 				fsp->pcfs_nrefs --;
686*0Sstevel@tonic-gate 			}
687*0Sstevel@tonic-gate 		}
688*0Sstevel@tonic-gate 	}
689*0Sstevel@tonic-gate #ifdef undef
690*0Sstevel@tonic-gate 	if (fsp->pcfs_frefs) {
691*0Sstevel@tonic-gate 		rw_exit(&pcnodes_lock);
692*0Sstevel@tonic-gate 		panic("pc_diskchanged: frefs");
693*0Sstevel@tonic-gate 	}
694*0Sstevel@tonic-gate 	if (fsp->pcfs_nrefs) {
695*0Sstevel@tonic-gate 		rw_exit(&pcnodes_lock);
696*0Sstevel@tonic-gate 		panic("pc_diskchanged: nrefs");
697*0Sstevel@tonic-gate 	}
698*0Sstevel@tonic-gate #endif
699*0Sstevel@tonic-gate 	if (fsp->pcfs_fatp != (uchar_t *)0) {
700*0Sstevel@tonic-gate 		pc_invalfat(fsp);
701*0Sstevel@tonic-gate 	} else {
702*0Sstevel@tonic-gate 		binval(fsp->pcfs_xdev);
703*0Sstevel@tonic-gate 	}
704*0Sstevel@tonic-gate }
705