17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5264a6e74Sfrankho * Common Development and Distribution License (the "License").
6264a6e74Sfrankho * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22a43c4dd1Scasper * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
25ade42b55SSebastien Roy /*
26ade42b55SSebastien Roy * Copyright (c) 2017 by Delphix. All rights reserved.
27ade42b55SSebastien Roy */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate #include <sys/param.h>
307c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
317c478bd9Sstevel@tonic-gate #include <sys/errno.h>
327c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
337c478bd9Sstevel@tonic-gate #include <sys/buf.h>
347c478bd9Sstevel@tonic-gate #include <sys/systm.h>
357c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
367c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
377c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
387c478bd9Sstevel@tonic-gate #include <sys/proc.h>
397c478bd9Sstevel@tonic-gate #include <sys/cred.h>
407c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
417c478bd9Sstevel@tonic-gate #include <sys/debug.h>
427c478bd9Sstevel@tonic-gate #include <vm/pvn.h>
437c478bd9Sstevel@tonic-gate #include <sys/fs/pc_label.h>
447c478bd9Sstevel@tonic-gate #include <sys/fs/pc_fs.h>
457c478bd9Sstevel@tonic-gate #include <sys/fs/pc_dir.h>
467c478bd9Sstevel@tonic-gate #include <sys/fs/pc_node.h>
477c478bd9Sstevel@tonic-gate #include <sys/dirent.h>
487c478bd9Sstevel@tonic-gate #include <sys/fdio.h>
497c478bd9Sstevel@tonic-gate #include <sys/file.h>
507c478bd9Sstevel@tonic-gate #include <sys/conf.h>
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate struct pchead pcfhead[NPCHASH];
537c478bd9Sstevel@tonic-gate struct pchead pcdhead[NPCHASH];
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate extern krwlock_t pcnodes_lock;
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate static int pc_getentryblock(struct pcnode *, struct buf **);
587c478bd9Sstevel@tonic-gate static int syncpcp(struct pcnode *, int);
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gate /*
617c478bd9Sstevel@tonic-gate * fake entry for root directory, since this does not have a parent
627c478bd9Sstevel@tonic-gate * pointing to it.
637c478bd9Sstevel@tonic-gate */
64264a6e74Sfrankho struct pcdir pcfs_rootdirentry = {
657c478bd9Sstevel@tonic-gate "",
667c478bd9Sstevel@tonic-gate "",
677c478bd9Sstevel@tonic-gate PCA_DIR
687c478bd9Sstevel@tonic-gate };
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate void
pc_init(void)717c478bd9Sstevel@tonic-gate pc_init(void)
727c478bd9Sstevel@tonic-gate {
737c478bd9Sstevel@tonic-gate struct pchead *hdp, *hfp;
747c478bd9Sstevel@tonic-gate int i;
757c478bd9Sstevel@tonic-gate for (i = 0; i < NPCHASH; i++) {
767c478bd9Sstevel@tonic-gate hdp = &pcdhead[i];
777c478bd9Sstevel@tonic-gate hfp = &pcfhead[i];
787c478bd9Sstevel@tonic-gate hdp->pch_forw = (struct pcnode *)hdp;
797c478bd9Sstevel@tonic-gate hdp->pch_back = (struct pcnode *)hdp;
807c478bd9Sstevel@tonic-gate hfp->pch_forw = (struct pcnode *)hfp;
817c478bd9Sstevel@tonic-gate hfp->pch_back = (struct pcnode *)hfp;
827c478bd9Sstevel@tonic-gate }
837c478bd9Sstevel@tonic-gate }
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate struct pcnode *
pc_getnode(struct pcfs * fsp,daddr_t blkno,int offset,struct pcdir * ep)867c478bd9Sstevel@tonic-gate pc_getnode(
877c478bd9Sstevel@tonic-gate struct pcfs *fsp, /* filsystem for node */
887c478bd9Sstevel@tonic-gate daddr_t blkno, /* phys block no of dir entry */
897c478bd9Sstevel@tonic-gate int offset, /* offset of dir entry in block */
907c478bd9Sstevel@tonic-gate struct pcdir *ep) /* node dir entry */
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate struct pcnode *pcp;
937c478bd9Sstevel@tonic-gate struct pchead *hp;
947c478bd9Sstevel@tonic-gate struct vnode *vp;
957c478bd9Sstevel@tonic-gate pc_cluster32_t scluster;
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate ASSERT(fsp->pcfs_flags & PCFS_LOCKED);
987c478bd9Sstevel@tonic-gate if (ep == (struct pcdir *)0) {
99264a6e74Sfrankho ep = &pcfs_rootdirentry;
1007c478bd9Sstevel@tonic-gate scluster = 0;
1017c478bd9Sstevel@tonic-gate } else {
1027c478bd9Sstevel@tonic-gate scluster = pc_getstartcluster(fsp, ep);
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate * First look for active nodes.
1067c478bd9Sstevel@tonic-gate * File nodes are identified by the location (blkno, offset) of
1077c478bd9Sstevel@tonic-gate * its directory entry.
1087c478bd9Sstevel@tonic-gate * Directory nodes are identified by the starting cluster number
1097c478bd9Sstevel@tonic-gate * for the entries.
1107c478bd9Sstevel@tonic-gate */
1117c478bd9Sstevel@tonic-gate if (ep->pcd_attr & PCA_DIR) {
1127c478bd9Sstevel@tonic-gate hp = &pcdhead[PCDHASH(fsp, scluster)];
1137c478bd9Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_READER);
1147c478bd9Sstevel@tonic-gate for (pcp = hp->pch_forw;
1157c478bd9Sstevel@tonic-gate pcp != (struct pcnode *)hp; pcp = pcp->pc_forw) {
1167c478bd9Sstevel@tonic-gate if ((fsp == VFSTOPCFS(PCTOV(pcp)->v_vfsp)) &&
1177c478bd9Sstevel@tonic-gate (scluster == pcp->pc_scluster)) {
1187c478bd9Sstevel@tonic-gate VN_HOLD(PCTOV(pcp));
1197c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock);
1207c478bd9Sstevel@tonic-gate return (pcp);
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock);
1247c478bd9Sstevel@tonic-gate } else {
1257c478bd9Sstevel@tonic-gate hp = &pcfhead[PCFHASH(fsp, blkno, offset)];
1267c478bd9Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_READER);
1277c478bd9Sstevel@tonic-gate for (pcp = hp->pch_forw;
1287c478bd9Sstevel@tonic-gate pcp != (struct pcnode *)hp; pcp = pcp->pc_forw) {
1297c478bd9Sstevel@tonic-gate if ((fsp == VFSTOPCFS(PCTOV(pcp)->v_vfsp)) &&
1307c478bd9Sstevel@tonic-gate ((pcp->pc_flags & PC_INVAL) == 0) &&
1317c478bd9Sstevel@tonic-gate (blkno == pcp->pc_eblkno) &&
1327c478bd9Sstevel@tonic-gate (offset == pcp->pc_eoffset)) {
1337c478bd9Sstevel@tonic-gate VN_HOLD(PCTOV(pcp));
1347c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock);
1357c478bd9Sstevel@tonic-gate return (pcp);
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock);
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate /*
1417c478bd9Sstevel@tonic-gate * Cannot find node in active list. Allocate memory for a new node
1427c478bd9Sstevel@tonic-gate * initialize it, and put it on the active list.
1437c478bd9Sstevel@tonic-gate */
144a0f9c00cSJosef 'Jeff' Sipek pcp = kmem_zalloc(sizeof (struct pcnode), KM_SLEEP);
1457c478bd9Sstevel@tonic-gate vp = vn_alloc(KM_SLEEP);
1467c478bd9Sstevel@tonic-gate pcp->pc_vn = vp;
1477c478bd9Sstevel@tonic-gate pcp->pc_entry = *ep;
1487c478bd9Sstevel@tonic-gate pcp->pc_eblkno = blkno;
1497c478bd9Sstevel@tonic-gate pcp->pc_eoffset = offset;
1507c478bd9Sstevel@tonic-gate pcp->pc_scluster = scluster;
1517c478bd9Sstevel@tonic-gate pcp->pc_lcluster = scluster;
1527c478bd9Sstevel@tonic-gate pcp->pc_lindex = 0;
1537c478bd9Sstevel@tonic-gate pcp->pc_flags = 0;
1547c478bd9Sstevel@tonic-gate if (ep->pcd_attr & PCA_DIR) {
1557c478bd9Sstevel@tonic-gate vn_setops(vp, pcfs_dvnodeops);
1567c478bd9Sstevel@tonic-gate vp->v_type = VDIR;
1577c478bd9Sstevel@tonic-gate if (scluster == 0) {
1587c478bd9Sstevel@tonic-gate vp->v_flag = VROOT;
1597c478bd9Sstevel@tonic-gate blkno = offset = 0;
1607c478bd9Sstevel@tonic-gate if (IS_FAT32(fsp)) {
1619bd42341Sfrankho pc_cluster32_t ncl = 0;
1629bd42341Sfrankho
1639bd42341Sfrankho scluster = fsp->pcfs_rdirstart;
1649bd42341Sfrankho if (pc_fileclsize(fsp, scluster, &ncl)) {
1659bd42341Sfrankho PC_DPRINTF1(2, "cluster chain "
1669bd42341Sfrankho "corruption, scluster=%d\n",
1679bd42341Sfrankho scluster);
1689bd42341Sfrankho pcp->pc_flags |= PC_INVAL;
1699bd42341Sfrankho }
1709bd42341Sfrankho pcp->pc_size = fsp->pcfs_clsize * ncl;
1717c478bd9Sstevel@tonic-gate } else {
1727c478bd9Sstevel@tonic-gate pcp->pc_size =
1737c478bd9Sstevel@tonic-gate fsp->pcfs_rdirsec * fsp->pcfs_secsize;
1747c478bd9Sstevel@tonic-gate }
1759bd42341Sfrankho } else {
1769bd42341Sfrankho pc_cluster32_t ncl = 0;
1779bd42341Sfrankho
1789bd42341Sfrankho if (pc_fileclsize(fsp, scluster, &ncl)) {
1799bd42341Sfrankho PC_DPRINTF1(2, "cluster chain corruption, "
1809bd42341Sfrankho "scluster=%d\n", scluster);
1819bd42341Sfrankho pcp->pc_flags |= PC_INVAL;
1829bd42341Sfrankho }
1839bd42341Sfrankho pcp->pc_size = fsp->pcfs_clsize * ncl;
1849bd42341Sfrankho }
1857c478bd9Sstevel@tonic-gate } else {
1867c478bd9Sstevel@tonic-gate vn_setops(vp, pcfs_fvnodeops);
1877c478bd9Sstevel@tonic-gate vp->v_type = VREG;
1887c478bd9Sstevel@tonic-gate vp->v_flag = VNOSWAP;
1897c478bd9Sstevel@tonic-gate fsp->pcfs_frefs++;
1907c478bd9Sstevel@tonic-gate pcp->pc_size = ltohi(ep->pcd_size);
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate fsp->pcfs_nrefs++;
193264a6e74Sfrankho VFS_HOLD(PCFSTOVFS(fsp));
1947c478bd9Sstevel@tonic-gate vp->v_data = (caddr_t)pcp;
1957c478bd9Sstevel@tonic-gate vp->v_vfsp = PCFSTOVFS(fsp);
1967c478bd9Sstevel@tonic-gate vn_exists(vp);
1977c478bd9Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_WRITER);
1987c478bd9Sstevel@tonic-gate insque(pcp, hp);
1997c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock);
2007c478bd9Sstevel@tonic-gate return (pcp);
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate int
syncpcp(struct pcnode * pcp,int flags)2047c478bd9Sstevel@tonic-gate syncpcp(struct pcnode *pcp, int flags)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate int err;
2077c478bd9Sstevel@tonic-gate if (!vn_has_cached_data(PCTOV(pcp)))
2087c478bd9Sstevel@tonic-gate err = 0;
2097c478bd9Sstevel@tonic-gate else
210da6c28aaSamw err = VOP_PUTPAGE(PCTOV(pcp), 0, 0, flags,
211da6c28aaSamw kcred, NULL);
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate return (err);
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate void
pc_rele(struct pcnode * pcp)2177c478bd9Sstevel@tonic-gate pc_rele(struct pcnode *pcp)
2187c478bd9Sstevel@tonic-gate {
2197c478bd9Sstevel@tonic-gate struct pcfs *fsp;
2207c478bd9Sstevel@tonic-gate struct vnode *vp;
2217c478bd9Sstevel@tonic-gate int err;
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate vp = PCTOV(pcp);
2247c478bd9Sstevel@tonic-gate PC_DPRINTF1(8, "pc_rele vp=0x%p\n", (void *)vp);
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
2277c478bd9Sstevel@tonic-gate ASSERT(fsp->pcfs_flags & PCFS_LOCKED);
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_WRITER);
2307c478bd9Sstevel@tonic-gate pcp->pc_flags |= PC_RELEHOLD;
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate retry:
2337c478bd9Sstevel@tonic-gate if (vp->v_type != VDIR && (pcp->pc_flags & PC_INVAL) == 0) {
2347c478bd9Sstevel@tonic-gate /*
2357c478bd9Sstevel@tonic-gate * If the file was removed while active it may be safely
2367c478bd9Sstevel@tonic-gate * truncated now.
2377c478bd9Sstevel@tonic-gate */
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate if (pcp->pc_entry.pcd_filename[0] == PCD_ERASED) {
2407c478bd9Sstevel@tonic-gate (void) pc_truncate(pcp, 0);
2417c478bd9Sstevel@tonic-gate } else if (pcp->pc_flags & PC_CHG) {
2427c478bd9Sstevel@tonic-gate (void) pc_nodeupdate(pcp);
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate err = syncpcp(pcp, B_INVAL);
2457c478bd9Sstevel@tonic-gate if (err) {
246f127cb91Sfrankho (void) syncpcp(pcp, B_INVAL | B_FORCE);
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate if (vn_has_cached_data(vp)) {
2507c478bd9Sstevel@tonic-gate /*
2517c478bd9Sstevel@tonic-gate * pvn_vplist_dirty will abort all old pages
2527c478bd9Sstevel@tonic-gate */
2537c478bd9Sstevel@tonic-gate (void) pvn_vplist_dirty(vp, (u_offset_t)0,
2547c478bd9Sstevel@tonic-gate pcfs_putapage, B_INVAL, (struct cred *)NULL);
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate (void) pc_syncfat(fsp);
2587c478bd9Sstevel@tonic-gate mutex_enter(&vp->v_lock);
2597c478bd9Sstevel@tonic-gate if (vn_has_cached_data(vp)) {
2607c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock);
2617c478bd9Sstevel@tonic-gate goto retry;
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate ASSERT(!vn_has_cached_data(vp));
2647c478bd9Sstevel@tonic-gate
265ade42b55SSebastien Roy VN_RELE_LOCKED(vp);
2667c478bd9Sstevel@tonic-gate if (vp->v_count > 0) { /* Is this check still needed? */
2677c478bd9Sstevel@tonic-gate PC_DPRINTF1(3, "pc_rele: pcp=0x%p HELD AGAIN!\n", (void *)pcp);
2687c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock);
2697c478bd9Sstevel@tonic-gate pcp->pc_flags &= ~PC_RELEHOLD;
2707c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock);
2717c478bd9Sstevel@tonic-gate return;
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate remque(pcp);
2757c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock);
2769bd42341Sfrankho /*
2779bd42341Sfrankho * XXX - old code had a check for !(pcp->pc_flags & PC_INVAL)
2789bd42341Sfrankho * here. Seems superfluous/incorrect, but then earlier on PC_INVAL
2799bd42341Sfrankho * was never set anywhere in PCFS. Now it is, and we _have_ to drop
2809bd42341Sfrankho * the file reference here. Else, we'd screw up umount/modunload.
2819bd42341Sfrankho */
2829bd42341Sfrankho if ((vp->v_type == VREG)) {
2837c478bd9Sstevel@tonic-gate fsp->pcfs_frefs--;
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate fsp->pcfs_nrefs--;
286264a6e74Sfrankho VFS_RELE(vp->v_vfsp);
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate if (fsp->pcfs_nrefs < 0) {
2897c478bd9Sstevel@tonic-gate panic("pc_rele: nrefs count");
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate if (fsp->pcfs_frefs < 0) {
2927c478bd9Sstevel@tonic-gate panic("pc_rele: frefs count");
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock);
2967c478bd9Sstevel@tonic-gate vn_invalid(vp);
2977c478bd9Sstevel@tonic-gate vn_free(vp);
2987c478bd9Sstevel@tonic-gate kmem_free(pcp, sizeof (struct pcnode));
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate /*
3027c478bd9Sstevel@tonic-gate * Mark a pcnode as modified with the current time.
3037c478bd9Sstevel@tonic-gate */
304f127cb91Sfrankho /* ARGSUSED */
3057c478bd9Sstevel@tonic-gate void
pc_mark_mod(struct pcfs * fsp,struct pcnode * pcp)306f127cb91Sfrankho pc_mark_mod(struct pcfs *fsp, struct pcnode *pcp)
3077c478bd9Sstevel@tonic-gate {
3087c478bd9Sstevel@tonic-gate timestruc_t now;
3097c478bd9Sstevel@tonic-gate
310f127cb91Sfrankho if (PCTOV(pcp)->v_type == VDIR)
311f127cb91Sfrankho return;
312f127cb91Sfrankho
313f127cb91Sfrankho ASSERT(PCTOV(pcp)->v_type == VREG);
314f127cb91Sfrankho
315f127cb91Sfrankho gethrestime(&now);
316f127cb91Sfrankho if (pc_tvtopct(&now, &pcp->pc_entry.pcd_mtime))
317f127cb91Sfrankho PC_DPRINTF1(2, "pc_mark_mod failed timestamp "
318f127cb91Sfrankho "conversion, curtime = %lld\n",
319f127cb91Sfrankho (long long)now.tv_sec);
320f127cb91Sfrankho
321f127cb91Sfrankho pcp->pc_flags |= PC_CHG;
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate /*
3257c478bd9Sstevel@tonic-gate * Mark a pcnode as accessed with the current time.
3267c478bd9Sstevel@tonic-gate */
3277c478bd9Sstevel@tonic-gate void
pc_mark_acc(struct pcfs * fsp,struct pcnode * pcp)328f127cb91Sfrankho pc_mark_acc(struct pcfs *fsp, struct pcnode *pcp)
3297c478bd9Sstevel@tonic-gate {
330264a6e74Sfrankho struct pctime pt = { 0, 0 };
3317c478bd9Sstevel@tonic-gate timestruc_t now;
3327c478bd9Sstevel@tonic-gate
333f127cb91Sfrankho if (fsp->pcfs_flags & PCFS_NOATIME || PCTOV(pcp)->v_type == VDIR)
334f127cb91Sfrankho return;
335f127cb91Sfrankho
336f127cb91Sfrankho ASSERT(PCTOV(pcp)->v_type == VREG);
337f127cb91Sfrankho
338f127cb91Sfrankho gethrestime(&now);
339f127cb91Sfrankho if (pc_tvtopct(&now, &pt)) {
340f127cb91Sfrankho PC_DPRINTF1(2, "pc_mark_acc failed timestamp "
341f127cb91Sfrankho "conversion, curtime = %lld\n",
342f127cb91Sfrankho (long long)now.tv_sec);
343f127cb91Sfrankho return;
344f127cb91Sfrankho }
345f127cb91Sfrankho
346f127cb91Sfrankho /*
347f127cb91Sfrankho * We don't really want to write the adate for every access
348f127cb91Sfrankho * on flash media; make sure it really changed !
349f127cb91Sfrankho */
350f127cb91Sfrankho if (pcp->pc_entry.pcd_ladate != pt.pct_date) {
3517c478bd9Sstevel@tonic-gate pcp->pc_entry.pcd_ladate = pt.pct_date;
352f127cb91Sfrankho pcp->pc_flags |= (PC_CHG | PC_ACC);
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate /*
3577c478bd9Sstevel@tonic-gate * Truncate a file to a length.
3587c478bd9Sstevel@tonic-gate * Node must be locked.
3597c478bd9Sstevel@tonic-gate */
3607c478bd9Sstevel@tonic-gate int
pc_truncate(struct pcnode * pcp,uint_t length)3617c478bd9Sstevel@tonic-gate pc_truncate(struct pcnode *pcp, uint_t length)
3627c478bd9Sstevel@tonic-gate {
3637c478bd9Sstevel@tonic-gate struct pcfs *fsp;
3647c478bd9Sstevel@tonic-gate struct vnode *vp;
3657c478bd9Sstevel@tonic-gate int error = 0;
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate PC_DPRINTF3(4, "pc_truncate pcp=0x%p, len=%u, size=%u\n",
3687c478bd9Sstevel@tonic-gate (void *)pcp, length, pcp->pc_size);
3697c478bd9Sstevel@tonic-gate vp = PCTOV(pcp);
3707c478bd9Sstevel@tonic-gate if (pcp->pc_flags & PC_INVAL)
3717c478bd9Sstevel@tonic-gate return (EIO);
3727c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
3737c478bd9Sstevel@tonic-gate /*
3747c478bd9Sstevel@tonic-gate * directories are always truncated to zero and are not marked
3757c478bd9Sstevel@tonic-gate */
3767c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) {
3777c478bd9Sstevel@tonic-gate error = pc_bfree(pcp, 0);
3787c478bd9Sstevel@tonic-gate return (error);
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate /*
3817c478bd9Sstevel@tonic-gate * If length is the same as the current size
3827c478bd9Sstevel@tonic-gate * just mark the pcnode and return.
3837c478bd9Sstevel@tonic-gate */
3847c478bd9Sstevel@tonic-gate if (length > pcp->pc_size) {
3857c478bd9Sstevel@tonic-gate daddr_t bno;
386f127cb91Sfrankho uint_t llcn = howmany((offset_t)length, fsp->pcfs_clsize);
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate /*
3897c478bd9Sstevel@tonic-gate * We are extending a file.
3907c478bd9Sstevel@tonic-gate * Extend it with _one_ call to pc_balloc (no holes)
3917c478bd9Sstevel@tonic-gate * since we don't need to use the block number(s).
3927c478bd9Sstevel@tonic-gate */
3937c478bd9Sstevel@tonic-gate if ((daddr_t)howmany((offset_t)pcp->pc_size, fsp->pcfs_clsize) <
394f127cb91Sfrankho (daddr_t)llcn) {
3957c478bd9Sstevel@tonic-gate error = pc_balloc(pcp, (daddr_t)(llcn - 1), 1, &bno);
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate if (error) {
3989bd42341Sfrankho pc_cluster32_t ncl = 0;
3997c478bd9Sstevel@tonic-gate PC_DPRINTF1(2, "pc_truncate: error=%d\n", error);
4007c478bd9Sstevel@tonic-gate /*
4017c478bd9Sstevel@tonic-gate * probably ran out disk space;
4027c478bd9Sstevel@tonic-gate * determine current file size
4037c478bd9Sstevel@tonic-gate */
4049bd42341Sfrankho if (pc_fileclsize(fsp, pcp->pc_scluster, &ncl)) {
4059bd42341Sfrankho PC_DPRINTF1(2, "cluster chain corruption, "
4069bd42341Sfrankho "scluster=%d\n", pcp->pc_scluster);
4079bd42341Sfrankho pcp->pc_flags |= PC_INVAL;
4089bd42341Sfrankho }
4099bd42341Sfrankho pcp->pc_size = fsp->pcfs_clsize * ncl;
4107c478bd9Sstevel@tonic-gate } else
4117c478bd9Sstevel@tonic-gate pcp->pc_size = length;
4127c478bd9Sstevel@tonic-gate
4137c478bd9Sstevel@tonic-gate } else if (length < pcp->pc_size) {
4147c478bd9Sstevel@tonic-gate /*
4157c478bd9Sstevel@tonic-gate * We are shrinking a file.
4167c478bd9Sstevel@tonic-gate * Free blocks after the block that length points to.
4177c478bd9Sstevel@tonic-gate */
4187c478bd9Sstevel@tonic-gate if (pc_blkoff(fsp, length) == 0) {
4197c478bd9Sstevel@tonic-gate /*
4207c478bd9Sstevel@tonic-gate * Truncation to a block (cluster size) boundary only
4217c478bd9Sstevel@tonic-gate * requires us to invalidate everything after the new
4227c478bd9Sstevel@tonic-gate * end of the file.
4237c478bd9Sstevel@tonic-gate */
4247c478bd9Sstevel@tonic-gate (void) pvn_vplist_dirty(PCTOV(pcp), (u_offset_t)length,
425f127cb91Sfrankho pcfs_putapage, B_INVAL | B_TRUNC, CRED());
4267c478bd9Sstevel@tonic-gate } else {
4277c478bd9Sstevel@tonic-gate /*
4287c478bd9Sstevel@tonic-gate * pvn_vpzero() cannot deal with more than MAXBSIZE
4297c478bd9Sstevel@tonic-gate * chunks. Since the FAT clustersize can get larger
4307c478bd9Sstevel@tonic-gate * than that, we'll zero from the new length to the
4317c478bd9Sstevel@tonic-gate * end of the cluster for clustersizes smaller than
4327c478bd9Sstevel@tonic-gate * MAXBSIZE - or the end of the MAXBSIZE block in
4337c478bd9Sstevel@tonic-gate * case we've got a large clustersize.
4347c478bd9Sstevel@tonic-gate */
4357c478bd9Sstevel@tonic-gate size_t nbytes =
4367c478bd9Sstevel@tonic-gate roundup(length, MIN(fsp->pcfs_clsize, MAXBSIZE)) -
4377c478bd9Sstevel@tonic-gate length;
4387c478bd9Sstevel@tonic-gate
4397c478bd9Sstevel@tonic-gate pvn_vpzero(PCTOV(pcp), (u_offset_t)length, nbytes);
4407c478bd9Sstevel@tonic-gate (void) pvn_vplist_dirty(PCTOV(pcp),
4417c478bd9Sstevel@tonic-gate (u_offset_t)length + nbytes,
4427c478bd9Sstevel@tonic-gate pcfs_putapage, B_INVAL | B_TRUNC, CRED());
4437c478bd9Sstevel@tonic-gate }
444f127cb91Sfrankho error = pc_bfree(pcp, (pc_cluster32_t)
445f127cb91Sfrankho howmany((offset_t)length, fsp->pcfs_clsize));
4467c478bd9Sstevel@tonic-gate pcp->pc_size = length;
4477c478bd9Sstevel@tonic-gate }
448f127cb91Sfrankho
449f127cb91Sfrankho /*
450f127cb91Sfrankho * This is the only place in PCFS code where pc_mark_mod() is called
451f127cb91Sfrankho * without setting PC_MOD. May be a historical artifact ...
452f127cb91Sfrankho */
453f127cb91Sfrankho pc_mark_mod(fsp, pcp);
4547c478bd9Sstevel@tonic-gate return (error);
4557c478bd9Sstevel@tonic-gate }
4567c478bd9Sstevel@tonic-gate
4577c478bd9Sstevel@tonic-gate /*
4587c478bd9Sstevel@tonic-gate * Get block for entry.
4597c478bd9Sstevel@tonic-gate */
4607c478bd9Sstevel@tonic-gate static int
pc_getentryblock(struct pcnode * pcp,struct buf ** bpp)4617c478bd9Sstevel@tonic-gate pc_getentryblock(struct pcnode *pcp, struct buf **bpp)
4627c478bd9Sstevel@tonic-gate {
4637c478bd9Sstevel@tonic-gate struct pcfs *fsp;
4647c478bd9Sstevel@tonic-gate
4657c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(PCTOV(pcp)->v_vfsp);
4667c478bd9Sstevel@tonic-gate if (pcp->pc_eblkno >= fsp->pcfs_datastart ||
4677c478bd9Sstevel@tonic-gate (pcp->pc_eblkno - fsp->pcfs_rdirstart) <
4687c478bd9Sstevel@tonic-gate (fsp->pcfs_rdirsec & ~(fsp->pcfs_spcl - 1))) {
4697c478bd9Sstevel@tonic-gate *bpp = bread(fsp->pcfs_xdev,
4707c478bd9Sstevel@tonic-gate pc_dbdaddr(fsp, pcp->pc_eblkno), fsp->pcfs_clsize);
4717c478bd9Sstevel@tonic-gate } else {
4727c478bd9Sstevel@tonic-gate *bpp = bread(fsp->pcfs_xdev,
4737c478bd9Sstevel@tonic-gate pc_dbdaddr(fsp, pcp->pc_eblkno),
474f127cb91Sfrankho (int)(fsp->pcfs_datastart - pcp->pc_eblkno) *
4757c478bd9Sstevel@tonic-gate fsp->pcfs_secsize);
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate if ((*bpp)->b_flags & B_ERROR) {
4787c478bd9Sstevel@tonic-gate brelse(*bpp);
4797c478bd9Sstevel@tonic-gate pc_mark_irrecov(fsp);
4807c478bd9Sstevel@tonic-gate return (EIO);
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate return (0);
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate
4857c478bd9Sstevel@tonic-gate /*
4867c478bd9Sstevel@tonic-gate * Sync all data associated with a file.
4877c478bd9Sstevel@tonic-gate * Flush all the blocks in the buffer cache out to disk, sync the FAT and
4887c478bd9Sstevel@tonic-gate * update the directory entry.
4897c478bd9Sstevel@tonic-gate */
4907c478bd9Sstevel@tonic-gate int
pc_nodesync(struct pcnode * pcp)4917c478bd9Sstevel@tonic-gate pc_nodesync(struct pcnode *pcp)
4927c478bd9Sstevel@tonic-gate {
4937c478bd9Sstevel@tonic-gate struct pcfs *fsp;
4947c478bd9Sstevel@tonic-gate int err;
4957c478bd9Sstevel@tonic-gate struct vnode *vp;
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate vp = PCTOV(pcp);
4987c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
4997c478bd9Sstevel@tonic-gate err = 0;
5007c478bd9Sstevel@tonic-gate if (pcp->pc_flags & PC_MOD) {
5017c478bd9Sstevel@tonic-gate /*
5027c478bd9Sstevel@tonic-gate * Flush all data blocks from buffer cache and
5037c478bd9Sstevel@tonic-gate * update the FAT which points to the data.
5047c478bd9Sstevel@tonic-gate */
5057c478bd9Sstevel@tonic-gate if (err = syncpcp(pcp, 0)) { /* %% ?? how to handle error? */
5067c478bd9Sstevel@tonic-gate if (err == ENOMEM)
5077c478bd9Sstevel@tonic-gate return (err);
5087c478bd9Sstevel@tonic-gate else {
5097c478bd9Sstevel@tonic-gate pc_mark_irrecov(fsp);
5107c478bd9Sstevel@tonic-gate return (EIO);
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate pcp->pc_flags &= ~PC_MOD;
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate /*
5167c478bd9Sstevel@tonic-gate * update the directory entry
5177c478bd9Sstevel@tonic-gate */
5187c478bd9Sstevel@tonic-gate if (pcp->pc_flags & PC_CHG)
5197c478bd9Sstevel@tonic-gate (void) pc_nodeupdate(pcp);
5207c478bd9Sstevel@tonic-gate return (err);
5217c478bd9Sstevel@tonic-gate }
5227c478bd9Sstevel@tonic-gate
5237c478bd9Sstevel@tonic-gate /*
5247c478bd9Sstevel@tonic-gate * Update the node's directory entry.
5257c478bd9Sstevel@tonic-gate */
5267c478bd9Sstevel@tonic-gate int
pc_nodeupdate(struct pcnode * pcp)5277c478bd9Sstevel@tonic-gate pc_nodeupdate(struct pcnode *pcp)
5287c478bd9Sstevel@tonic-gate {
5297c478bd9Sstevel@tonic-gate struct buf *bp;
5307c478bd9Sstevel@tonic-gate int error;
5317c478bd9Sstevel@tonic-gate struct vnode *vp;
5327c478bd9Sstevel@tonic-gate struct pcfs *fsp;
5337c478bd9Sstevel@tonic-gate
5347c478bd9Sstevel@tonic-gate vp = PCTOV(pcp);
5357c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
5367c478bd9Sstevel@tonic-gate if (IS_FAT32(fsp) && (vp->v_flag & VROOT)) {
5377c478bd9Sstevel@tonic-gate /* no node to update */
5387c478bd9Sstevel@tonic-gate pcp->pc_flags &= ~(PC_CHG | PC_MOD | PC_ACC);
5397c478bd9Sstevel@tonic-gate return (0);
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate if (vp->v_flag & VROOT) {
5427c478bd9Sstevel@tonic-gate panic("pc_nodeupdate");
5437c478bd9Sstevel@tonic-gate }
5447c478bd9Sstevel@tonic-gate if (pcp->pc_flags & PC_INVAL)
5457c478bd9Sstevel@tonic-gate return (0);
5467c478bd9Sstevel@tonic-gate PC_DPRINTF3(7, "pc_nodeupdate pcp=0x%p, bn=%ld, off=%d\n", (void *)pcp,
5477c478bd9Sstevel@tonic-gate pcp->pc_eblkno, pcp->pc_eoffset);
5487c478bd9Sstevel@tonic-gate
5497c478bd9Sstevel@tonic-gate if (error = pc_getentryblock(pcp, &bp)) {
5507c478bd9Sstevel@tonic-gate return (error);
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) {
5537c478bd9Sstevel@tonic-gate if (pcp->pc_flags & PC_CHG)
5547c478bd9Sstevel@tonic-gate pcp->pc_entry.pcd_attr |= PCA_ARCH;
5557c478bd9Sstevel@tonic-gate pcp->pc_entry.pcd_size = htoli(pcp->pc_size);
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate pc_setstartcluster(fsp, &pcp->pc_entry, pcp->pc_scluster);
5587c478bd9Sstevel@tonic-gate *((struct pcdir *)(bp->b_un.b_addr + pcp->pc_eoffset)) = pcp->pc_entry;
5597c478bd9Sstevel@tonic-gate bwrite2(bp);
5607c478bd9Sstevel@tonic-gate error = geterror(bp);
5617c478bd9Sstevel@tonic-gate brelse(bp);
5627c478bd9Sstevel@tonic-gate if (error) {
563f127cb91Sfrankho error = EIO;
5647c478bd9Sstevel@tonic-gate pc_mark_irrecov(VFSTOPCFS(vp->v_vfsp));
5657c478bd9Sstevel@tonic-gate }
5667c478bd9Sstevel@tonic-gate pcp->pc_flags &= ~(PC_CHG | PC_MOD | PC_ACC);
5677c478bd9Sstevel@tonic-gate return (error);
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate
5707c478bd9Sstevel@tonic-gate /*
5717c478bd9Sstevel@tonic-gate * Verify that the disk in the drive is the same one that we
5727c478bd9Sstevel@tonic-gate * got the pcnode from.
5737c478bd9Sstevel@tonic-gate * MUST be called with node unlocked.
5747c478bd9Sstevel@tonic-gate */
5757c478bd9Sstevel@tonic-gate int
pc_verify(struct pcfs * fsp)5767c478bd9Sstevel@tonic-gate pc_verify(struct pcfs *fsp)
5777c478bd9Sstevel@tonic-gate {
5787c478bd9Sstevel@tonic-gate int fdstatus = 0;
5797c478bd9Sstevel@tonic-gate int error = 0;
5807c478bd9Sstevel@tonic-gate
5817c478bd9Sstevel@tonic-gate if (!fsp || fsp->pcfs_flags & PCFS_IRRECOV)
5827c478bd9Sstevel@tonic-gate return (EIO);
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate if (!(fsp->pcfs_flags & PCFS_NOCHK) && fsp->pcfs_fatp) {
585f127cb91Sfrankho /*
586f127cb91Sfrankho * This "has it been removed" check should better be
587f127cb91Sfrankho * modified for removeable media that are not floppies.
588f127cb91Sfrankho * dkio-managed devices such as USB/firewire external
589f127cb91Sfrankho * disks/memory sticks/floppies (gasp) do not understand
590f127cb91Sfrankho * this ioctl.
591f127cb91Sfrankho */
5927c478bd9Sstevel@tonic-gate PC_DPRINTF1(4, "pc_verify fsp=0x%p\n", (void *)fsp);
5937c478bd9Sstevel@tonic-gate error = cdev_ioctl(fsp->pcfs_vfs->vfs_dev,
594f127cb91Sfrankho FDGETCHANGE, (intptr_t)&fdstatus, FNATIVE | FKIOCTL,
5957c478bd9Sstevel@tonic-gate NULL, NULL);
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate if (error) {
5987c478bd9Sstevel@tonic-gate if (error == ENOTTY || error == ENXIO) {
599f127cb91Sfrankho /*
600f127cb91Sfrankho * See comment above. This is a workaround
601f127cb91Sfrankho * for removeable media that don't understand
602f127cb91Sfrankho * floppy ioctls.
603f127cb91Sfrankho */
6047c478bd9Sstevel@tonic-gate error = 0;
6057c478bd9Sstevel@tonic-gate } else {
6067c478bd9Sstevel@tonic-gate PC_DPRINTF1(1,
6077c478bd9Sstevel@tonic-gate "pc_verify: FDGETCHANGE ioctl failed: %d\n",
6087c478bd9Sstevel@tonic-gate error);
6097c478bd9Sstevel@tonic-gate pc_mark_irrecov(fsp);
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate } else if (fsp->pcfs_fatjustread) {
6127c478bd9Sstevel@tonic-gate /*
6137c478bd9Sstevel@tonic-gate * Ignore the results of the ioctl if we just
6147c478bd9Sstevel@tonic-gate * read the FAT. There is a good chance that
6157c478bd9Sstevel@tonic-gate * the disk changed bit will be on, because
6167c478bd9Sstevel@tonic-gate * we've just mounted and we don't want to
6177c478bd9Sstevel@tonic-gate * give a false positive that the sky is falling.
6187c478bd9Sstevel@tonic-gate */
6197c478bd9Sstevel@tonic-gate fsp->pcfs_fatjustread = 0;
6207c478bd9Sstevel@tonic-gate } else {
6217c478bd9Sstevel@tonic-gate /*
6227c478bd9Sstevel@tonic-gate * Oddly enough we can't check just one flag here. The
6237c478bd9Sstevel@tonic-gate * x86 floppy driver sets a different flag
6247c478bd9Sstevel@tonic-gate * (FDGC_DETECTED) than the sparc driver does.
6257c478bd9Sstevel@tonic-gate * I think this MAY be a bug, and I filed 4165938
6267c478bd9Sstevel@tonic-gate * to get someone to look at the behavior
6277c478bd9Sstevel@tonic-gate * a bit more closely. In the meantime, my testing and
6287c478bd9Sstevel@tonic-gate * code examination seem to indicate it is safe to
6297c478bd9Sstevel@tonic-gate * check for either bit being set.
6307c478bd9Sstevel@tonic-gate */
6317c478bd9Sstevel@tonic-gate if (fdstatus & (FDGC_HISTORY | FDGC_DETECTED)) {
6327c478bd9Sstevel@tonic-gate PC_DPRINTF0(1, "pc_verify: change detected\n");
6337c478bd9Sstevel@tonic-gate pc_mark_irrecov(fsp);
6347c478bd9Sstevel@tonic-gate }
6357c478bd9Sstevel@tonic-gate }
6367c478bd9Sstevel@tonic-gate }
637f127cb91Sfrankho if (error == 0 && fsp->pcfs_fatp == NULL) {
6387c478bd9Sstevel@tonic-gate error = pc_getfat(fsp);
6397c478bd9Sstevel@tonic-gate }
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate return (error);
6427c478bd9Sstevel@tonic-gate }
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate /*
6457c478bd9Sstevel@tonic-gate * The disk has changed, pulling the rug out from beneath us.
6467c478bd9Sstevel@tonic-gate * Mark the FS as being in an irrecoverable state.
6477c478bd9Sstevel@tonic-gate * In a short while we'll clean up.
6487c478bd9Sstevel@tonic-gate */
6497c478bd9Sstevel@tonic-gate void
pc_mark_irrecov(struct pcfs * fsp)6507c478bd9Sstevel@tonic-gate pc_mark_irrecov(struct pcfs *fsp)
6517c478bd9Sstevel@tonic-gate {
6527c478bd9Sstevel@tonic-gate if (!(fsp->pcfs_flags & PCFS_NOCHK)) {
6537c478bd9Sstevel@tonic-gate if (pc_lockfs(fsp, 1, 0)) {
6547c478bd9Sstevel@tonic-gate /*
6557c478bd9Sstevel@tonic-gate * Locking failed, which currently would
6567c478bd9Sstevel@tonic-gate * only happen if the FS were already
6577c478bd9Sstevel@tonic-gate * marked as hosed. If another reason for
6587c478bd9Sstevel@tonic-gate * failure were to arise in the future, this
6597c478bd9Sstevel@tonic-gate * routine would have to change.
6607c478bd9Sstevel@tonic-gate */
6617c478bd9Sstevel@tonic-gate return;
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate fsp->pcfs_flags |= PCFS_IRRECOV;
6657c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
666f127cb91Sfrankho "Disk was changed during an update or\n"
667f127cb91Sfrankho "an irrecoverable error was encountered.\n"
668f127cb91Sfrankho "File damage is possible. To prevent further\n"
669f127cb91Sfrankho "damage, this pcfs instance will now be frozen.\n"
670*bbf21555SRichard Lowe "Use umount(8) to release the instance.\n");
6717c478bd9Sstevel@tonic-gate (void) pc_unlockfs(fsp);
6727c478bd9Sstevel@tonic-gate }
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate
6757c478bd9Sstevel@tonic-gate /*
6767c478bd9Sstevel@tonic-gate * The disk has been changed!
6777c478bd9Sstevel@tonic-gate */
6787c478bd9Sstevel@tonic-gate void
pc_diskchanged(struct pcfs * fsp)6797c478bd9Sstevel@tonic-gate pc_diskchanged(struct pcfs *fsp)
6807c478bd9Sstevel@tonic-gate {
681264a6e74Sfrankho struct pcnode *pcp, *npcp = NULL;
682264a6e74Sfrankho struct pchead *hp;
683264a6e74Sfrankho struct vnode *vp;
684264a6e74Sfrankho extern vfs_t EIO_vfs;
685264a6e74Sfrankho struct vfs *vfsp;
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate /*
6887c478bd9Sstevel@tonic-gate * Eliminate all pcnodes (dir & file) associated with this fs.
6897c478bd9Sstevel@tonic-gate * If the node is internal, ie, no references outside of
6907c478bd9Sstevel@tonic-gate * pcfs itself, then release the associated vnode structure.
6917c478bd9Sstevel@tonic-gate * Invalidate the in core FAT.
6927c478bd9Sstevel@tonic-gate * Invalidate cached data blocks and blocks waiting for I/O.
6937c478bd9Sstevel@tonic-gate */
6947c478bd9Sstevel@tonic-gate PC_DPRINTF1(1, "pc_diskchanged fsp=0x%p\n", (void *)fsp);
6957c478bd9Sstevel@tonic-gate
696264a6e74Sfrankho vfsp = PCFSTOVFS(fsp);
697264a6e74Sfrankho
6987c478bd9Sstevel@tonic-gate for (hp = pcdhead; hp < &pcdhead[NPCHASH]; hp++) {
6997c478bd9Sstevel@tonic-gate for (pcp = hp->pch_forw;
7007c478bd9Sstevel@tonic-gate pcp != (struct pcnode *)hp; pcp = npcp) {
7017c478bd9Sstevel@tonic-gate npcp = pcp -> pc_forw;
7027c478bd9Sstevel@tonic-gate vp = PCTOV(pcp);
703264a6e74Sfrankho if ((vp->v_vfsp == vfsp) &&
7047c478bd9Sstevel@tonic-gate !(pcp->pc_flags & PC_RELEHOLD)) {
7057c478bd9Sstevel@tonic-gate mutex_enter(&(vp)->v_lock);
7067c478bd9Sstevel@tonic-gate if (vp->v_count > 0) {
7077c478bd9Sstevel@tonic-gate mutex_exit(&(vp)->v_lock);
7087c478bd9Sstevel@tonic-gate continue;
7097c478bd9Sstevel@tonic-gate }
7107c478bd9Sstevel@tonic-gate mutex_exit(&(vp)->v_lock);
7117c478bd9Sstevel@tonic-gate VN_HOLD(vp);
7127c478bd9Sstevel@tonic-gate remque(pcp);
7137c478bd9Sstevel@tonic-gate vp->v_data = NULL;
7147c478bd9Sstevel@tonic-gate vp->v_vfsp = &EIO_vfs;
7157c478bd9Sstevel@tonic-gate vp->v_type = VBAD;
7167c478bd9Sstevel@tonic-gate VN_RELE(vp);
717264a6e74Sfrankho if (!(pcp->pc_flags & PC_EXTERNAL)) {
718264a6e74Sfrankho (void) pvn_vplist_dirty(vp,
719264a6e74Sfrankho (u_offset_t)0, pcfs_putapage,
720264a6e74Sfrankho B_INVAL | B_TRUNC,
721264a6e74Sfrankho (struct cred *)NULL);
7227c478bd9Sstevel@tonic-gate vn_free(vp);
723264a6e74Sfrankho }
7247c478bd9Sstevel@tonic-gate kmem_free(pcp, sizeof (struct pcnode));
7257c478bd9Sstevel@tonic-gate fsp->pcfs_nrefs --;
726264a6e74Sfrankho VFS_RELE(vfsp);
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate }
7297c478bd9Sstevel@tonic-gate }
7307c478bd9Sstevel@tonic-gate for (hp = pcfhead; fsp->pcfs_frefs && hp < &pcfhead[NPCHASH]; hp++) {
7317c478bd9Sstevel@tonic-gate for (pcp = hp->pch_forw; fsp->pcfs_frefs &&
7327c478bd9Sstevel@tonic-gate pcp != (struct pcnode *)hp; pcp = npcp) {
7337c478bd9Sstevel@tonic-gate npcp = pcp -> pc_forw;
7347c478bd9Sstevel@tonic-gate vp = PCTOV(pcp);
735264a6e74Sfrankho if ((vp->v_vfsp == vfsp) &&
7367c478bd9Sstevel@tonic-gate !(pcp->pc_flags & PC_RELEHOLD)) {
7377c478bd9Sstevel@tonic-gate mutex_enter(&(vp)->v_lock);
7387c478bd9Sstevel@tonic-gate if (vp->v_count > 0) {
7397c478bd9Sstevel@tonic-gate mutex_exit(&(vp)->v_lock);
7407c478bd9Sstevel@tonic-gate continue;
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate mutex_exit(&(vp)->v_lock);
7437c478bd9Sstevel@tonic-gate VN_HOLD(vp);
7447c478bd9Sstevel@tonic-gate remque(pcp);
7457c478bd9Sstevel@tonic-gate vp->v_data = NULL;
7467c478bd9Sstevel@tonic-gate vp->v_vfsp = &EIO_vfs;
7477c478bd9Sstevel@tonic-gate vp->v_type = VBAD;
7487c478bd9Sstevel@tonic-gate VN_RELE(vp);
749264a6e74Sfrankho if (!(pcp->pc_flags & PC_EXTERNAL)) {
750264a6e74Sfrankho (void) pvn_vplist_dirty(vp,
751264a6e74Sfrankho (u_offset_t)0, pcfs_putapage,
752264a6e74Sfrankho B_INVAL | B_TRUNC,
753264a6e74Sfrankho (struct cred *)NULL);
7547c478bd9Sstevel@tonic-gate vn_free(vp);
755264a6e74Sfrankho }
7567c478bd9Sstevel@tonic-gate kmem_free(pcp, sizeof (struct pcnode));
7579bd42341Sfrankho fsp->pcfs_frefs--;
7589bd42341Sfrankho fsp->pcfs_nrefs--;
759264a6e74Sfrankho VFS_RELE(vfsp);
7607c478bd9Sstevel@tonic-gate }
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate #ifdef undef
7647c478bd9Sstevel@tonic-gate if (fsp->pcfs_frefs) {
7657c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock);
7667c478bd9Sstevel@tonic-gate panic("pc_diskchanged: frefs");
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate if (fsp->pcfs_nrefs) {
7697c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock);
7707c478bd9Sstevel@tonic-gate panic("pc_diskchanged: nrefs");
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate #endif
773264a6e74Sfrankho if (!(vfsp->vfs_flag & VFS_UNMOUNTED) &&
774264a6e74Sfrankho fsp->pcfs_fatp != (uchar_t *)0) {
7757c478bd9Sstevel@tonic-gate pc_invalfat(fsp);
7767c478bd9Sstevel@tonic-gate } else {
7777c478bd9Sstevel@tonic-gate binval(fsp->pcfs_xdev);
7787c478bd9Sstevel@tonic-gate }
7797c478bd9Sstevel@tonic-gate }
780