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 */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/param.h> 277c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 287c478bd9Sstevel@tonic-gate #include <sys/errno.h> 297c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 307c478bd9Sstevel@tonic-gate #include <sys/buf.h> 317c478bd9Sstevel@tonic-gate #include <sys/systm.h> 327c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 337c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 347c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 357c478bd9Sstevel@tonic-gate #include <sys/proc.h> 367c478bd9Sstevel@tonic-gate #include <sys/cred.h> 377c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 387c478bd9Sstevel@tonic-gate #include <sys/debug.h> 397c478bd9Sstevel@tonic-gate #include <vm/pvn.h> 407c478bd9Sstevel@tonic-gate #include <sys/fs/pc_label.h> 417c478bd9Sstevel@tonic-gate #include <sys/fs/pc_fs.h> 427c478bd9Sstevel@tonic-gate #include <sys/fs/pc_dir.h> 437c478bd9Sstevel@tonic-gate #include <sys/fs/pc_node.h> 447c478bd9Sstevel@tonic-gate #include <sys/dirent.h> 457c478bd9Sstevel@tonic-gate #include <sys/fdio.h> 467c478bd9Sstevel@tonic-gate #include <sys/file.h> 477c478bd9Sstevel@tonic-gate #include <sys/conf.h> 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate struct pchead pcfhead[NPCHASH]; 507c478bd9Sstevel@tonic-gate struct pchead pcdhead[NPCHASH]; 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate extern krwlock_t pcnodes_lock; 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate static int pc_getentryblock(struct pcnode *, struct buf **); 557c478bd9Sstevel@tonic-gate static int syncpcp(struct pcnode *, int); 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate /* 587c478bd9Sstevel@tonic-gate * fake entry for root directory, since this does not have a parent 597c478bd9Sstevel@tonic-gate * pointing to it. 607c478bd9Sstevel@tonic-gate */ 61264a6e74Sfrankho struct pcdir pcfs_rootdirentry = { 627c478bd9Sstevel@tonic-gate "", 637c478bd9Sstevel@tonic-gate "", 647c478bd9Sstevel@tonic-gate PCA_DIR 657c478bd9Sstevel@tonic-gate }; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate void 687c478bd9Sstevel@tonic-gate pc_init(void) 697c478bd9Sstevel@tonic-gate { 707c478bd9Sstevel@tonic-gate struct pchead *hdp, *hfp; 717c478bd9Sstevel@tonic-gate int i; 727c478bd9Sstevel@tonic-gate for (i = 0; i < NPCHASH; i++) { 737c478bd9Sstevel@tonic-gate hdp = &pcdhead[i]; 747c478bd9Sstevel@tonic-gate hfp = &pcfhead[i]; 757c478bd9Sstevel@tonic-gate hdp->pch_forw = (struct pcnode *)hdp; 767c478bd9Sstevel@tonic-gate hdp->pch_back = (struct pcnode *)hdp; 777c478bd9Sstevel@tonic-gate hfp->pch_forw = (struct pcnode *)hfp; 787c478bd9Sstevel@tonic-gate hfp->pch_back = (struct pcnode *)hfp; 797c478bd9Sstevel@tonic-gate } 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate struct pcnode * 837c478bd9Sstevel@tonic-gate pc_getnode( 847c478bd9Sstevel@tonic-gate struct pcfs *fsp, /* filsystem for node */ 857c478bd9Sstevel@tonic-gate daddr_t blkno, /* phys block no of dir entry */ 867c478bd9Sstevel@tonic-gate int offset, /* offset of dir entry in block */ 877c478bd9Sstevel@tonic-gate struct pcdir *ep) /* node dir entry */ 887c478bd9Sstevel@tonic-gate { 897c478bd9Sstevel@tonic-gate struct pcnode *pcp; 907c478bd9Sstevel@tonic-gate struct pchead *hp; 917c478bd9Sstevel@tonic-gate struct vnode *vp; 927c478bd9Sstevel@tonic-gate pc_cluster32_t scluster; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate ASSERT(fsp->pcfs_flags & PCFS_LOCKED); 957c478bd9Sstevel@tonic-gate if (ep == (struct pcdir *)0) { 96264a6e74Sfrankho ep = &pcfs_rootdirentry; 977c478bd9Sstevel@tonic-gate scluster = 0; 987c478bd9Sstevel@tonic-gate } else { 997c478bd9Sstevel@tonic-gate scluster = pc_getstartcluster(fsp, ep); 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * First look for active nodes. 1037c478bd9Sstevel@tonic-gate * File nodes are identified by the location (blkno, offset) of 1047c478bd9Sstevel@tonic-gate * its directory entry. 1057c478bd9Sstevel@tonic-gate * Directory nodes are identified by the starting cluster number 1067c478bd9Sstevel@tonic-gate * for the entries. 1077c478bd9Sstevel@tonic-gate */ 1087c478bd9Sstevel@tonic-gate if (ep->pcd_attr & PCA_DIR) { 1097c478bd9Sstevel@tonic-gate hp = &pcdhead[PCDHASH(fsp, scluster)]; 1107c478bd9Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_READER); 1117c478bd9Sstevel@tonic-gate for (pcp = hp->pch_forw; 1127c478bd9Sstevel@tonic-gate pcp != (struct pcnode *)hp; pcp = pcp->pc_forw) { 1137c478bd9Sstevel@tonic-gate if ((fsp == VFSTOPCFS(PCTOV(pcp)->v_vfsp)) && 1147c478bd9Sstevel@tonic-gate (scluster == pcp->pc_scluster)) { 1157c478bd9Sstevel@tonic-gate VN_HOLD(PCTOV(pcp)); 1167c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock); 1177c478bd9Sstevel@tonic-gate return (pcp); 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock); 1217c478bd9Sstevel@tonic-gate } else { 1227c478bd9Sstevel@tonic-gate hp = &pcfhead[PCFHASH(fsp, blkno, offset)]; 1237c478bd9Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_READER); 1247c478bd9Sstevel@tonic-gate for (pcp = hp->pch_forw; 1257c478bd9Sstevel@tonic-gate pcp != (struct pcnode *)hp; pcp = pcp->pc_forw) { 1267c478bd9Sstevel@tonic-gate if ((fsp == VFSTOPCFS(PCTOV(pcp)->v_vfsp)) && 1277c478bd9Sstevel@tonic-gate ((pcp->pc_flags & PC_INVAL) == 0) && 1287c478bd9Sstevel@tonic-gate (blkno == pcp->pc_eblkno) && 1297c478bd9Sstevel@tonic-gate (offset == pcp->pc_eoffset)) { 1307c478bd9Sstevel@tonic-gate VN_HOLD(PCTOV(pcp)); 1317c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock); 1327c478bd9Sstevel@tonic-gate return (pcp); 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock); 1367c478bd9Sstevel@tonic-gate } 1377c478bd9Sstevel@tonic-gate /* 1387c478bd9Sstevel@tonic-gate * Cannot find node in active list. Allocate memory for a new node 1397c478bd9Sstevel@tonic-gate * initialize it, and put it on the active list. 1407c478bd9Sstevel@tonic-gate */ 141*a0f9c00cSJosef 'Jeff' Sipek pcp = kmem_zalloc(sizeof (struct pcnode), KM_SLEEP); 1427c478bd9Sstevel@tonic-gate vp = vn_alloc(KM_SLEEP); 1437c478bd9Sstevel@tonic-gate pcp->pc_vn = vp; 1447c478bd9Sstevel@tonic-gate pcp->pc_entry = *ep; 1457c478bd9Sstevel@tonic-gate pcp->pc_eblkno = blkno; 1467c478bd9Sstevel@tonic-gate pcp->pc_eoffset = offset; 1477c478bd9Sstevel@tonic-gate pcp->pc_scluster = scluster; 1487c478bd9Sstevel@tonic-gate pcp->pc_lcluster = scluster; 1497c478bd9Sstevel@tonic-gate pcp->pc_lindex = 0; 1507c478bd9Sstevel@tonic-gate pcp->pc_flags = 0; 1517c478bd9Sstevel@tonic-gate if (ep->pcd_attr & PCA_DIR) { 1527c478bd9Sstevel@tonic-gate vn_setops(vp, pcfs_dvnodeops); 1537c478bd9Sstevel@tonic-gate vp->v_type = VDIR; 1547c478bd9Sstevel@tonic-gate if (scluster == 0) { 1557c478bd9Sstevel@tonic-gate vp->v_flag = VROOT; 1567c478bd9Sstevel@tonic-gate blkno = offset = 0; 1577c478bd9Sstevel@tonic-gate if (IS_FAT32(fsp)) { 1589bd42341Sfrankho pc_cluster32_t ncl = 0; 1599bd42341Sfrankho 1609bd42341Sfrankho scluster = fsp->pcfs_rdirstart; 1619bd42341Sfrankho if (pc_fileclsize(fsp, scluster, &ncl)) { 1629bd42341Sfrankho PC_DPRINTF1(2, "cluster chain " 1639bd42341Sfrankho "corruption, scluster=%d\n", 1649bd42341Sfrankho scluster); 1659bd42341Sfrankho pcp->pc_flags |= PC_INVAL; 1669bd42341Sfrankho } 1679bd42341Sfrankho pcp->pc_size = fsp->pcfs_clsize * ncl; 1687c478bd9Sstevel@tonic-gate } else { 1697c478bd9Sstevel@tonic-gate pcp->pc_size = 1707c478bd9Sstevel@tonic-gate fsp->pcfs_rdirsec * fsp->pcfs_secsize; 1717c478bd9Sstevel@tonic-gate } 1729bd42341Sfrankho } else { 1739bd42341Sfrankho pc_cluster32_t ncl = 0; 1749bd42341Sfrankho 1759bd42341Sfrankho if (pc_fileclsize(fsp, scluster, &ncl)) { 1769bd42341Sfrankho PC_DPRINTF1(2, "cluster chain corruption, " 1779bd42341Sfrankho "scluster=%d\n", scluster); 1789bd42341Sfrankho pcp->pc_flags |= PC_INVAL; 1799bd42341Sfrankho } 1809bd42341Sfrankho pcp->pc_size = fsp->pcfs_clsize * ncl; 1819bd42341Sfrankho } 1827c478bd9Sstevel@tonic-gate } else { 1837c478bd9Sstevel@tonic-gate vn_setops(vp, pcfs_fvnodeops); 1847c478bd9Sstevel@tonic-gate vp->v_type = VREG; 1857c478bd9Sstevel@tonic-gate vp->v_flag = VNOSWAP; 1867c478bd9Sstevel@tonic-gate fsp->pcfs_frefs++; 1877c478bd9Sstevel@tonic-gate pcp->pc_size = ltohi(ep->pcd_size); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate fsp->pcfs_nrefs++; 190264a6e74Sfrankho VFS_HOLD(PCFSTOVFS(fsp)); 1917c478bd9Sstevel@tonic-gate vp->v_data = (caddr_t)pcp; 1927c478bd9Sstevel@tonic-gate vp->v_vfsp = PCFSTOVFS(fsp); 1937c478bd9Sstevel@tonic-gate vn_exists(vp); 1947c478bd9Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_WRITER); 1957c478bd9Sstevel@tonic-gate insque(pcp, hp); 1967c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock); 1977c478bd9Sstevel@tonic-gate return (pcp); 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate int 2017c478bd9Sstevel@tonic-gate syncpcp(struct pcnode *pcp, int flags) 2027c478bd9Sstevel@tonic-gate { 2037c478bd9Sstevel@tonic-gate int err; 2047c478bd9Sstevel@tonic-gate if (!vn_has_cached_data(PCTOV(pcp))) 2057c478bd9Sstevel@tonic-gate err = 0; 2067c478bd9Sstevel@tonic-gate else 207da6c28aaSamw err = VOP_PUTPAGE(PCTOV(pcp), 0, 0, flags, 208da6c28aaSamw kcred, NULL); 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate return (err); 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate void 2147c478bd9Sstevel@tonic-gate pc_rele(struct pcnode *pcp) 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate struct pcfs *fsp; 2177c478bd9Sstevel@tonic-gate struct vnode *vp; 2187c478bd9Sstevel@tonic-gate int err; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate vp = PCTOV(pcp); 2217c478bd9Sstevel@tonic-gate PC_DPRINTF1(8, "pc_rele vp=0x%p\n", (void *)vp); 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 2247c478bd9Sstevel@tonic-gate ASSERT(fsp->pcfs_flags & PCFS_LOCKED); 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_WRITER); 2277c478bd9Sstevel@tonic-gate pcp->pc_flags |= PC_RELEHOLD; 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate retry: 2307c478bd9Sstevel@tonic-gate if (vp->v_type != VDIR && (pcp->pc_flags & PC_INVAL) == 0) { 2317c478bd9Sstevel@tonic-gate /* 2327c478bd9Sstevel@tonic-gate * If the file was removed while active it may be safely 2337c478bd9Sstevel@tonic-gate * truncated now. 2347c478bd9Sstevel@tonic-gate */ 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate if (pcp->pc_entry.pcd_filename[0] == PCD_ERASED) { 2377c478bd9Sstevel@tonic-gate (void) pc_truncate(pcp, 0); 2387c478bd9Sstevel@tonic-gate } else if (pcp->pc_flags & PC_CHG) { 2397c478bd9Sstevel@tonic-gate (void) pc_nodeupdate(pcp); 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate err = syncpcp(pcp, B_INVAL); 2427c478bd9Sstevel@tonic-gate if (err) { 2437c478bd9Sstevel@tonic-gate (void) syncpcp(pcp, B_INVAL | B_FORCE); 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate if (vn_has_cached_data(vp)) { 2477c478bd9Sstevel@tonic-gate /* 2487c478bd9Sstevel@tonic-gate * pvn_vplist_dirty will abort all old pages 2497c478bd9Sstevel@tonic-gate */ 2507c478bd9Sstevel@tonic-gate (void) pvn_vplist_dirty(vp, (u_offset_t)0, 2517c478bd9Sstevel@tonic-gate pcfs_putapage, B_INVAL, (struct cred *)NULL); 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate (void) pc_syncfat(fsp); 2557c478bd9Sstevel@tonic-gate mutex_enter(&vp->v_lock); 2567c478bd9Sstevel@tonic-gate if (vn_has_cached_data(vp)) { 2577c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock); 2587c478bd9Sstevel@tonic-gate goto retry; 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate ASSERT(!vn_has_cached_data(vp)); 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate vp->v_count--; /* release our hold from vn_rele */ 2637c478bd9Sstevel@tonic-gate if (vp->v_count > 0) { /* Is this check still needed? */ 2647c478bd9Sstevel@tonic-gate PC_DPRINTF1(3, "pc_rele: pcp=0x%p HELD AGAIN!\n", (void *)pcp); 2657c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock); 2667c478bd9Sstevel@tonic-gate pcp->pc_flags &= ~PC_RELEHOLD; 2677c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock); 2687c478bd9Sstevel@tonic-gate return; 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate remque(pcp); 2727c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock); 2739bd42341Sfrankho /* 2749bd42341Sfrankho * XXX - old code had a check for !(pcp->pc_flags & PC_INVAL) 2759bd42341Sfrankho * here. Seems superfluous/incorrect, but then earlier on PC_INVAL 2769bd42341Sfrankho * was never set anywhere in PCFS. Now it is, and we _have_ to drop 2779bd42341Sfrankho * the file reference here. Else, we'd screw up umount/modunload. 2789bd42341Sfrankho */ 2799bd42341Sfrankho if ((vp->v_type == VREG)) { 2807c478bd9Sstevel@tonic-gate fsp->pcfs_frefs--; 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate fsp->pcfs_nrefs--; 283264a6e74Sfrankho VFS_RELE(vp->v_vfsp); 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate if (fsp->pcfs_nrefs < 0) { 2867c478bd9Sstevel@tonic-gate panic("pc_rele: nrefs count"); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate if (fsp->pcfs_frefs < 0) { 2897c478bd9Sstevel@tonic-gate panic("pc_rele: frefs count"); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock); 2937c478bd9Sstevel@tonic-gate vn_invalid(vp); 2947c478bd9Sstevel@tonic-gate vn_free(vp); 2957c478bd9Sstevel@tonic-gate kmem_free(pcp, sizeof (struct pcnode)); 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate /* 2997c478bd9Sstevel@tonic-gate * Mark a pcnode as modified with the current time. 3007c478bd9Sstevel@tonic-gate */ 301f127cb91Sfrankho /* ARGSUSED */ 3027c478bd9Sstevel@tonic-gate void 303f127cb91Sfrankho pc_mark_mod(struct pcfs *fsp, struct pcnode *pcp) 3047c478bd9Sstevel@tonic-gate { 3057c478bd9Sstevel@tonic-gate timestruc_t now; 3067c478bd9Sstevel@tonic-gate 307f127cb91Sfrankho if (PCTOV(pcp)->v_type == VDIR) 308f127cb91Sfrankho return; 309f127cb91Sfrankho 310f127cb91Sfrankho ASSERT(PCTOV(pcp)->v_type == VREG); 311f127cb91Sfrankho 3127c478bd9Sstevel@tonic-gate gethrestime(&now); 313264a6e74Sfrankho if (pc_tvtopct(&now, &pcp->pc_entry.pcd_mtime)) 314264a6e74Sfrankho PC_DPRINTF1(2, "pc_mark_mod failed timestamp " 315264a6e74Sfrankho "conversion, curtime = %lld\n", 316264a6e74Sfrankho (long long)now.tv_sec); 317f127cb91Sfrankho 3187c478bd9Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate /* 3227c478bd9Sstevel@tonic-gate * Mark a pcnode as accessed with the current time. 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate void 325f127cb91Sfrankho pc_mark_acc(struct pcfs *fsp, struct pcnode *pcp) 3267c478bd9Sstevel@tonic-gate { 327264a6e74Sfrankho struct pctime pt = { 0, 0 }; 3287c478bd9Sstevel@tonic-gate timestruc_t now; 3297c478bd9Sstevel@tonic-gate 330f127cb91Sfrankho if (fsp->pcfs_flags & PCFS_NOATIME || PCTOV(pcp)->v_type == VDIR) 331f127cb91Sfrankho return; 332f127cb91Sfrankho 333f127cb91Sfrankho ASSERT(PCTOV(pcp)->v_type == VREG); 334f127cb91Sfrankho 3357c478bd9Sstevel@tonic-gate gethrestime(&now); 336f127cb91Sfrankho if (pc_tvtopct(&now, &pt)) { 337264a6e74Sfrankho PC_DPRINTF1(2, "pc_mark_acc failed timestamp " 338264a6e74Sfrankho "conversion, curtime = %lld\n", 339264a6e74Sfrankho (long long)now.tv_sec); 340f127cb91Sfrankho return; 341f127cb91Sfrankho } 342f127cb91Sfrankho 343f127cb91Sfrankho /* 344f127cb91Sfrankho * We don't really want to write the adate for every access 345f127cb91Sfrankho * on flash media; make sure it really changed ! 346f127cb91Sfrankho */ 347f127cb91Sfrankho if (pcp->pc_entry.pcd_ladate != pt.pct_date) { 3487c478bd9Sstevel@tonic-gate pcp->pc_entry.pcd_ladate = pt.pct_date; 349f127cb91Sfrankho pcp->pc_flags |= (PC_CHG | PC_ACC); 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /* 3547c478bd9Sstevel@tonic-gate * Truncate a file to a length. 3557c478bd9Sstevel@tonic-gate * Node must be locked. 3567c478bd9Sstevel@tonic-gate */ 3577c478bd9Sstevel@tonic-gate int 3587c478bd9Sstevel@tonic-gate pc_truncate(struct pcnode *pcp, uint_t length) 3597c478bd9Sstevel@tonic-gate { 3607c478bd9Sstevel@tonic-gate struct pcfs *fsp; 3617c478bd9Sstevel@tonic-gate struct vnode *vp; 3627c478bd9Sstevel@tonic-gate int error = 0; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate PC_DPRINTF3(4, "pc_truncate pcp=0x%p, len=%u, size=%u\n", 3657c478bd9Sstevel@tonic-gate (void *)pcp, length, pcp->pc_size); 3667c478bd9Sstevel@tonic-gate vp = PCTOV(pcp); 3677c478bd9Sstevel@tonic-gate if (pcp->pc_flags & PC_INVAL) 3687c478bd9Sstevel@tonic-gate return (EIO); 3697c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 3707c478bd9Sstevel@tonic-gate /* 3717c478bd9Sstevel@tonic-gate * directories are always truncated to zero and are not marked 3727c478bd9Sstevel@tonic-gate */ 3737c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 3747c478bd9Sstevel@tonic-gate error = pc_bfree(pcp, 0); 3757c478bd9Sstevel@tonic-gate return (error); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate /* 3787c478bd9Sstevel@tonic-gate * If length is the same as the current size 3797c478bd9Sstevel@tonic-gate * just mark the pcnode and return. 3807c478bd9Sstevel@tonic-gate */ 3817c478bd9Sstevel@tonic-gate if (length > pcp->pc_size) { 3827c478bd9Sstevel@tonic-gate daddr_t bno; 383f127cb91Sfrankho uint_t llcn = howmany((offset_t)length, fsp->pcfs_clsize); 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * We are extending a file. 3877c478bd9Sstevel@tonic-gate * Extend it with _one_ call to pc_balloc (no holes) 3887c478bd9Sstevel@tonic-gate * since we don't need to use the block number(s). 3897c478bd9Sstevel@tonic-gate */ 3907c478bd9Sstevel@tonic-gate if ((daddr_t)howmany((offset_t)pcp->pc_size, fsp->pcfs_clsize) < 391f127cb91Sfrankho (daddr_t)llcn) { 3927c478bd9Sstevel@tonic-gate error = pc_balloc(pcp, (daddr_t)(llcn - 1), 1, &bno); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate if (error) { 3959bd42341Sfrankho pc_cluster32_t ncl = 0; 3967c478bd9Sstevel@tonic-gate PC_DPRINTF1(2, "pc_truncate: error=%d\n", error); 3977c478bd9Sstevel@tonic-gate /* 3987c478bd9Sstevel@tonic-gate * probably ran out disk space; 3997c478bd9Sstevel@tonic-gate * determine current file size 4007c478bd9Sstevel@tonic-gate */ 4019bd42341Sfrankho if (pc_fileclsize(fsp, pcp->pc_scluster, &ncl)) { 4029bd42341Sfrankho PC_DPRINTF1(2, "cluster chain corruption, " 4039bd42341Sfrankho "scluster=%d\n", pcp->pc_scluster); 4049bd42341Sfrankho pcp->pc_flags |= PC_INVAL; 4059bd42341Sfrankho } 4069bd42341Sfrankho pcp->pc_size = fsp->pcfs_clsize * ncl; 4077c478bd9Sstevel@tonic-gate } else 4087c478bd9Sstevel@tonic-gate pcp->pc_size = length; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate } else if (length < pcp->pc_size) { 4117c478bd9Sstevel@tonic-gate /* 4127c478bd9Sstevel@tonic-gate * We are shrinking a file. 4137c478bd9Sstevel@tonic-gate * Free blocks after the block that length points to. 4147c478bd9Sstevel@tonic-gate */ 4157c478bd9Sstevel@tonic-gate if (pc_blkoff(fsp, length) == 0) { 4167c478bd9Sstevel@tonic-gate /* 4177c478bd9Sstevel@tonic-gate * Truncation to a block (cluster size) boundary only 4187c478bd9Sstevel@tonic-gate * requires us to invalidate everything after the new 4197c478bd9Sstevel@tonic-gate * end of the file. 4207c478bd9Sstevel@tonic-gate */ 4217c478bd9Sstevel@tonic-gate (void) pvn_vplist_dirty(PCTOV(pcp), (u_offset_t)length, 4227c478bd9Sstevel@tonic-gate pcfs_putapage, B_INVAL | B_TRUNC, CRED()); 4237c478bd9Sstevel@tonic-gate } else { 4247c478bd9Sstevel@tonic-gate /* 4257c478bd9Sstevel@tonic-gate * pvn_vpzero() cannot deal with more than MAXBSIZE 4267c478bd9Sstevel@tonic-gate * chunks. Since the FAT clustersize can get larger 4277c478bd9Sstevel@tonic-gate * than that, we'll zero from the new length to the 4287c478bd9Sstevel@tonic-gate * end of the cluster for clustersizes smaller than 4297c478bd9Sstevel@tonic-gate * MAXBSIZE - or the end of the MAXBSIZE block in 4307c478bd9Sstevel@tonic-gate * case we've got a large clustersize. 4317c478bd9Sstevel@tonic-gate */ 4327c478bd9Sstevel@tonic-gate size_t nbytes = 4337c478bd9Sstevel@tonic-gate roundup(length, MIN(fsp->pcfs_clsize, MAXBSIZE)) - 4347c478bd9Sstevel@tonic-gate length; 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate pvn_vpzero(PCTOV(pcp), (u_offset_t)length, nbytes); 4377c478bd9Sstevel@tonic-gate (void) pvn_vplist_dirty(PCTOV(pcp), 4387c478bd9Sstevel@tonic-gate (u_offset_t)length + nbytes, 4397c478bd9Sstevel@tonic-gate pcfs_putapage, B_INVAL | B_TRUNC, CRED()); 4407c478bd9Sstevel@tonic-gate } 441f127cb91Sfrankho error = pc_bfree(pcp, (pc_cluster32_t) 442f127cb91Sfrankho howmany((offset_t)length, fsp->pcfs_clsize)); 4437c478bd9Sstevel@tonic-gate pcp->pc_size = length; 4447c478bd9Sstevel@tonic-gate } 445f127cb91Sfrankho 446f127cb91Sfrankho /* 447f127cb91Sfrankho * This is the only place in PCFS code where pc_mark_mod() is called 448f127cb91Sfrankho * without setting PC_MOD. May be a historical artifact ... 449f127cb91Sfrankho */ 450f127cb91Sfrankho pc_mark_mod(fsp, pcp); 4517c478bd9Sstevel@tonic-gate return (error); 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* 4557c478bd9Sstevel@tonic-gate * Get block for entry. 4567c478bd9Sstevel@tonic-gate */ 4577c478bd9Sstevel@tonic-gate static int 4587c478bd9Sstevel@tonic-gate pc_getentryblock(struct pcnode *pcp, struct buf **bpp) 4597c478bd9Sstevel@tonic-gate { 4607c478bd9Sstevel@tonic-gate struct pcfs *fsp; 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(PCTOV(pcp)->v_vfsp); 4637c478bd9Sstevel@tonic-gate if (pcp->pc_eblkno >= fsp->pcfs_datastart || 4647c478bd9Sstevel@tonic-gate (pcp->pc_eblkno - fsp->pcfs_rdirstart) < 4657c478bd9Sstevel@tonic-gate (fsp->pcfs_rdirsec & ~(fsp->pcfs_spcl - 1))) { 4667c478bd9Sstevel@tonic-gate *bpp = bread(fsp->pcfs_xdev, 4677c478bd9Sstevel@tonic-gate pc_dbdaddr(fsp, pcp->pc_eblkno), fsp->pcfs_clsize); 4687c478bd9Sstevel@tonic-gate } else { 4697c478bd9Sstevel@tonic-gate *bpp = bread(fsp->pcfs_xdev, 4707c478bd9Sstevel@tonic-gate pc_dbdaddr(fsp, pcp->pc_eblkno), 4717c478bd9Sstevel@tonic-gate (int)(fsp->pcfs_datastart - pcp->pc_eblkno) * 4727c478bd9Sstevel@tonic-gate fsp->pcfs_secsize); 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate if ((*bpp)->b_flags & B_ERROR) { 4757c478bd9Sstevel@tonic-gate brelse(*bpp); 4767c478bd9Sstevel@tonic-gate pc_mark_irrecov(fsp); 4777c478bd9Sstevel@tonic-gate return (EIO); 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate return (0); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* 4837c478bd9Sstevel@tonic-gate * Sync all data associated with a file. 4847c478bd9Sstevel@tonic-gate * Flush all the blocks in the buffer cache out to disk, sync the FAT and 4857c478bd9Sstevel@tonic-gate * update the directory entry. 4867c478bd9Sstevel@tonic-gate */ 4877c478bd9Sstevel@tonic-gate int 4887c478bd9Sstevel@tonic-gate pc_nodesync(struct pcnode *pcp) 4897c478bd9Sstevel@tonic-gate { 4907c478bd9Sstevel@tonic-gate struct pcfs *fsp; 4917c478bd9Sstevel@tonic-gate int err; 4927c478bd9Sstevel@tonic-gate struct vnode *vp; 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate vp = PCTOV(pcp); 4957c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 4967c478bd9Sstevel@tonic-gate err = 0; 4977c478bd9Sstevel@tonic-gate if (pcp->pc_flags & PC_MOD) { 4987c478bd9Sstevel@tonic-gate /* 4997c478bd9Sstevel@tonic-gate * Flush all data blocks from buffer cache and 5007c478bd9Sstevel@tonic-gate * update the FAT which points to the data. 5017c478bd9Sstevel@tonic-gate */ 5027c478bd9Sstevel@tonic-gate if (err = syncpcp(pcp, 0)) { /* %% ?? how to handle error? */ 5037c478bd9Sstevel@tonic-gate if (err == ENOMEM) 5047c478bd9Sstevel@tonic-gate return (err); 5057c478bd9Sstevel@tonic-gate else { 5067c478bd9Sstevel@tonic-gate pc_mark_irrecov(fsp); 5077c478bd9Sstevel@tonic-gate return (EIO); 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate } 5107c478bd9Sstevel@tonic-gate pcp->pc_flags &= ~PC_MOD; 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate /* 5137c478bd9Sstevel@tonic-gate * update the directory entry 5147c478bd9Sstevel@tonic-gate */ 5157c478bd9Sstevel@tonic-gate if (pcp->pc_flags & PC_CHG) 5167c478bd9Sstevel@tonic-gate (void) pc_nodeupdate(pcp); 5177c478bd9Sstevel@tonic-gate return (err); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate /* 5217c478bd9Sstevel@tonic-gate * Update the node's directory entry. 5227c478bd9Sstevel@tonic-gate */ 5237c478bd9Sstevel@tonic-gate int 5247c478bd9Sstevel@tonic-gate pc_nodeupdate(struct pcnode *pcp) 5257c478bd9Sstevel@tonic-gate { 5267c478bd9Sstevel@tonic-gate struct buf *bp; 5277c478bd9Sstevel@tonic-gate int error; 5287c478bd9Sstevel@tonic-gate struct vnode *vp; 5297c478bd9Sstevel@tonic-gate struct pcfs *fsp; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate vp = PCTOV(pcp); 5327c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 5337c478bd9Sstevel@tonic-gate if (IS_FAT32(fsp) && (vp->v_flag & VROOT)) { 5347c478bd9Sstevel@tonic-gate /* no node to update */ 5357c478bd9Sstevel@tonic-gate pcp->pc_flags &= ~(PC_CHG | PC_MOD | PC_ACC); 5367c478bd9Sstevel@tonic-gate return (0); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate if (vp->v_flag & VROOT) { 5397c478bd9Sstevel@tonic-gate panic("pc_nodeupdate"); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate if (pcp->pc_flags & PC_INVAL) 5427c478bd9Sstevel@tonic-gate return (0); 5437c478bd9Sstevel@tonic-gate PC_DPRINTF3(7, "pc_nodeupdate pcp=0x%p, bn=%ld, off=%d\n", (void *)pcp, 5447c478bd9Sstevel@tonic-gate pcp->pc_eblkno, pcp->pc_eoffset); 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate if (error = pc_getentryblock(pcp, &bp)) { 5477c478bd9Sstevel@tonic-gate return (error); 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) { 5507c478bd9Sstevel@tonic-gate if (pcp->pc_flags & PC_CHG) 5517c478bd9Sstevel@tonic-gate pcp->pc_entry.pcd_attr |= PCA_ARCH; 5527c478bd9Sstevel@tonic-gate pcp->pc_entry.pcd_size = htoli(pcp->pc_size); 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate pc_setstartcluster(fsp, &pcp->pc_entry, pcp->pc_scluster); 5557c478bd9Sstevel@tonic-gate *((struct pcdir *)(bp->b_un.b_addr + pcp->pc_eoffset)) = pcp->pc_entry; 5567c478bd9Sstevel@tonic-gate bwrite2(bp); 5577c478bd9Sstevel@tonic-gate error = geterror(bp); 5587c478bd9Sstevel@tonic-gate brelse(bp); 5597c478bd9Sstevel@tonic-gate if (error) { 560f127cb91Sfrankho error = EIO; 5617c478bd9Sstevel@tonic-gate pc_mark_irrecov(VFSTOPCFS(vp->v_vfsp)); 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate pcp->pc_flags &= ~(PC_CHG | PC_MOD | PC_ACC); 5647c478bd9Sstevel@tonic-gate return (error); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate /* 5687c478bd9Sstevel@tonic-gate * Verify that the disk in the drive is the same one that we 5697c478bd9Sstevel@tonic-gate * got the pcnode from. 5707c478bd9Sstevel@tonic-gate * MUST be called with node unlocked. 5717c478bd9Sstevel@tonic-gate */ 5727c478bd9Sstevel@tonic-gate int 5737c478bd9Sstevel@tonic-gate pc_verify(struct pcfs *fsp) 5747c478bd9Sstevel@tonic-gate { 5757c478bd9Sstevel@tonic-gate int fdstatus = 0; 5767c478bd9Sstevel@tonic-gate int error = 0; 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate if (!fsp || fsp->pcfs_flags & PCFS_IRRECOV) 5797c478bd9Sstevel@tonic-gate return (EIO); 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate if (!(fsp->pcfs_flags & PCFS_NOCHK) && fsp->pcfs_fatp) { 582f127cb91Sfrankho /* 583f127cb91Sfrankho * This "has it been removed" check should better be 584f127cb91Sfrankho * modified for removeable media that are not floppies. 585f127cb91Sfrankho * dkio-managed devices such as USB/firewire external 586f127cb91Sfrankho * disks/memory sticks/floppies (gasp) do not understand 587f127cb91Sfrankho * this ioctl. 588f127cb91Sfrankho */ 5897c478bd9Sstevel@tonic-gate PC_DPRINTF1(4, "pc_verify fsp=0x%p\n", (void *)fsp); 5907c478bd9Sstevel@tonic-gate error = cdev_ioctl(fsp->pcfs_vfs->vfs_dev, 5917c478bd9Sstevel@tonic-gate FDGETCHANGE, (intptr_t)&fdstatus, FNATIVE | FKIOCTL, 5927c478bd9Sstevel@tonic-gate NULL, NULL); 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate if (error) { 5957c478bd9Sstevel@tonic-gate if (error == ENOTTY || error == ENXIO) { 596f127cb91Sfrankho /* 597f127cb91Sfrankho * See comment above. This is a workaround 598f127cb91Sfrankho * for removeable media that don't understand 599f127cb91Sfrankho * floppy ioctls. 600f127cb91Sfrankho */ 6017c478bd9Sstevel@tonic-gate error = 0; 6027c478bd9Sstevel@tonic-gate } else { 6037c478bd9Sstevel@tonic-gate PC_DPRINTF1(1, 6047c478bd9Sstevel@tonic-gate "pc_verify: FDGETCHANGE ioctl failed: %d\n", 6057c478bd9Sstevel@tonic-gate error); 6067c478bd9Sstevel@tonic-gate pc_mark_irrecov(fsp); 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate } else if (fsp->pcfs_fatjustread) { 6097c478bd9Sstevel@tonic-gate /* 6107c478bd9Sstevel@tonic-gate * Ignore the results of the ioctl if we just 6117c478bd9Sstevel@tonic-gate * read the FAT. There is a good chance that 6127c478bd9Sstevel@tonic-gate * the disk changed bit will be on, because 6137c478bd9Sstevel@tonic-gate * we've just mounted and we don't want to 6147c478bd9Sstevel@tonic-gate * give a false positive that the sky is falling. 6157c478bd9Sstevel@tonic-gate */ 6167c478bd9Sstevel@tonic-gate fsp->pcfs_fatjustread = 0; 6177c478bd9Sstevel@tonic-gate } else { 6187c478bd9Sstevel@tonic-gate /* 6197c478bd9Sstevel@tonic-gate * Oddly enough we can't check just one flag here. The 6207c478bd9Sstevel@tonic-gate * x86 floppy driver sets a different flag 6217c478bd9Sstevel@tonic-gate * (FDGC_DETECTED) than the sparc driver does. 6227c478bd9Sstevel@tonic-gate * I think this MAY be a bug, and I filed 4165938 6237c478bd9Sstevel@tonic-gate * to get someone to look at the behavior 6247c478bd9Sstevel@tonic-gate * a bit more closely. In the meantime, my testing and 6257c478bd9Sstevel@tonic-gate * code examination seem to indicate it is safe to 6267c478bd9Sstevel@tonic-gate * check for either bit being set. 6277c478bd9Sstevel@tonic-gate */ 6287c478bd9Sstevel@tonic-gate if (fdstatus & (FDGC_HISTORY | FDGC_DETECTED)) { 6297c478bd9Sstevel@tonic-gate PC_DPRINTF0(1, "pc_verify: change detected\n"); 6307c478bd9Sstevel@tonic-gate pc_mark_irrecov(fsp); 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate } 634f127cb91Sfrankho if (error == 0 && fsp->pcfs_fatp == NULL) { 6357c478bd9Sstevel@tonic-gate error = pc_getfat(fsp); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate return (error); 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate /* 6427c478bd9Sstevel@tonic-gate * The disk has changed, pulling the rug out from beneath us. 6437c478bd9Sstevel@tonic-gate * Mark the FS as being in an irrecoverable state. 6447c478bd9Sstevel@tonic-gate * In a short while we'll clean up. 6457c478bd9Sstevel@tonic-gate */ 6467c478bd9Sstevel@tonic-gate void 6477c478bd9Sstevel@tonic-gate pc_mark_irrecov(struct pcfs *fsp) 6487c478bd9Sstevel@tonic-gate { 6497c478bd9Sstevel@tonic-gate if (!(fsp->pcfs_flags & PCFS_NOCHK)) { 6507c478bd9Sstevel@tonic-gate if (pc_lockfs(fsp, 1, 0)) { 6517c478bd9Sstevel@tonic-gate /* 6527c478bd9Sstevel@tonic-gate * Locking failed, which currently would 6537c478bd9Sstevel@tonic-gate * only happen if the FS were already 6547c478bd9Sstevel@tonic-gate * marked as hosed. If another reason for 6557c478bd9Sstevel@tonic-gate * failure were to arise in the future, this 6567c478bd9Sstevel@tonic-gate * routine would have to change. 6577c478bd9Sstevel@tonic-gate */ 6587c478bd9Sstevel@tonic-gate return; 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate fsp->pcfs_flags |= PCFS_IRRECOV; 6627c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 6637c478bd9Sstevel@tonic-gate "Disk was changed during an update or\n" 6647c478bd9Sstevel@tonic-gate "an irrecoverable error was encountered.\n" 6657c478bd9Sstevel@tonic-gate "File damage is possible. To prevent further\n" 6667c478bd9Sstevel@tonic-gate "damage, this pcfs instance will now be frozen.\n" 6677c478bd9Sstevel@tonic-gate "Use umount(1M) to release the instance.\n"); 6687c478bd9Sstevel@tonic-gate (void) pc_unlockfs(fsp); 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate /* 6737c478bd9Sstevel@tonic-gate * The disk has been changed! 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate void 6767c478bd9Sstevel@tonic-gate pc_diskchanged(struct pcfs *fsp) 6777c478bd9Sstevel@tonic-gate { 6787c478bd9Sstevel@tonic-gate struct pcnode *pcp, *npcp = NULL; 6797c478bd9Sstevel@tonic-gate struct pchead *hp; 6807c478bd9Sstevel@tonic-gate struct vnode *vp; 6817c478bd9Sstevel@tonic-gate extern vfs_t EIO_vfs; 682264a6e74Sfrankho struct vfs *vfsp; 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate /* 6857c478bd9Sstevel@tonic-gate * Eliminate all pcnodes (dir & file) associated with this fs. 6867c478bd9Sstevel@tonic-gate * If the node is internal, ie, no references outside of 6877c478bd9Sstevel@tonic-gate * pcfs itself, then release the associated vnode structure. 6887c478bd9Sstevel@tonic-gate * Invalidate the in core FAT. 6897c478bd9Sstevel@tonic-gate * Invalidate cached data blocks and blocks waiting for I/O. 6907c478bd9Sstevel@tonic-gate */ 6917c478bd9Sstevel@tonic-gate PC_DPRINTF1(1, "pc_diskchanged fsp=0x%p\n", (void *)fsp); 6927c478bd9Sstevel@tonic-gate 693264a6e74Sfrankho vfsp = PCFSTOVFS(fsp); 694264a6e74Sfrankho 6957c478bd9Sstevel@tonic-gate for (hp = pcdhead; hp < &pcdhead[NPCHASH]; hp++) { 6967c478bd9Sstevel@tonic-gate for (pcp = hp->pch_forw; 6977c478bd9Sstevel@tonic-gate pcp != (struct pcnode *)hp; pcp = npcp) { 6987c478bd9Sstevel@tonic-gate npcp = pcp -> pc_forw; 6997c478bd9Sstevel@tonic-gate vp = PCTOV(pcp); 700264a6e74Sfrankho if ((vp->v_vfsp == vfsp) && 7017c478bd9Sstevel@tonic-gate !(pcp->pc_flags & PC_RELEHOLD)) { 7027c478bd9Sstevel@tonic-gate mutex_enter(&(vp)->v_lock); 7037c478bd9Sstevel@tonic-gate if (vp->v_count > 0) { 7047c478bd9Sstevel@tonic-gate mutex_exit(&(vp)->v_lock); 7057c478bd9Sstevel@tonic-gate continue; 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate mutex_exit(&(vp)->v_lock); 7087c478bd9Sstevel@tonic-gate VN_HOLD(vp); 7097c478bd9Sstevel@tonic-gate remque(pcp); 7107c478bd9Sstevel@tonic-gate vp->v_data = NULL; 7117c478bd9Sstevel@tonic-gate vp->v_vfsp = &EIO_vfs; 7127c478bd9Sstevel@tonic-gate vp->v_type = VBAD; 7137c478bd9Sstevel@tonic-gate VN_RELE(vp); 714264a6e74Sfrankho if (!(pcp->pc_flags & PC_EXTERNAL)) { 715264a6e74Sfrankho (void) pvn_vplist_dirty(vp, 716264a6e74Sfrankho (u_offset_t)0, pcfs_putapage, 717264a6e74Sfrankho B_INVAL | B_TRUNC, 718264a6e74Sfrankho (struct cred *)NULL); 7197c478bd9Sstevel@tonic-gate vn_free(vp); 720264a6e74Sfrankho } 7217c478bd9Sstevel@tonic-gate kmem_free(pcp, sizeof (struct pcnode)); 7227c478bd9Sstevel@tonic-gate fsp->pcfs_nrefs --; 723264a6e74Sfrankho VFS_RELE(vfsp); 7247c478bd9Sstevel@tonic-gate } 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate for (hp = pcfhead; fsp->pcfs_frefs && hp < &pcfhead[NPCHASH]; hp++) { 7287c478bd9Sstevel@tonic-gate for (pcp = hp->pch_forw; fsp->pcfs_frefs && 7297c478bd9Sstevel@tonic-gate pcp != (struct pcnode *)hp; pcp = npcp) { 7307c478bd9Sstevel@tonic-gate npcp = pcp -> pc_forw; 7317c478bd9Sstevel@tonic-gate vp = PCTOV(pcp); 732264a6e74Sfrankho if ((vp->v_vfsp == vfsp) && 7337c478bd9Sstevel@tonic-gate !(pcp->pc_flags & PC_RELEHOLD)) { 7347c478bd9Sstevel@tonic-gate mutex_enter(&(vp)->v_lock); 7357c478bd9Sstevel@tonic-gate if (vp->v_count > 0) { 7367c478bd9Sstevel@tonic-gate mutex_exit(&(vp)->v_lock); 7377c478bd9Sstevel@tonic-gate continue; 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate mutex_exit(&(vp)->v_lock); 7407c478bd9Sstevel@tonic-gate VN_HOLD(vp); 7417c478bd9Sstevel@tonic-gate remque(pcp); 7427c478bd9Sstevel@tonic-gate vp->v_data = NULL; 7437c478bd9Sstevel@tonic-gate vp->v_vfsp = &EIO_vfs; 7447c478bd9Sstevel@tonic-gate vp->v_type = VBAD; 7457c478bd9Sstevel@tonic-gate VN_RELE(vp); 746264a6e74Sfrankho if (!(pcp->pc_flags & PC_EXTERNAL)) { 747264a6e74Sfrankho (void) pvn_vplist_dirty(vp, 748264a6e74Sfrankho (u_offset_t)0, pcfs_putapage, 749264a6e74Sfrankho B_INVAL | B_TRUNC, 750264a6e74Sfrankho (struct cred *)NULL); 7517c478bd9Sstevel@tonic-gate vn_free(vp); 752264a6e74Sfrankho } 7537c478bd9Sstevel@tonic-gate kmem_free(pcp, sizeof (struct pcnode)); 7547c478bd9Sstevel@tonic-gate fsp->pcfs_frefs--; 7557c478bd9Sstevel@tonic-gate fsp->pcfs_nrefs--; 756264a6e74Sfrankho VFS_RELE(vfsp); 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate } 7607c478bd9Sstevel@tonic-gate #ifdef undef 7617c478bd9Sstevel@tonic-gate if (fsp->pcfs_frefs) { 7627c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock); 7637c478bd9Sstevel@tonic-gate panic("pc_diskchanged: frefs"); 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate if (fsp->pcfs_nrefs) { 7667c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock); 7677c478bd9Sstevel@tonic-gate panic("pc_diskchanged: nrefs"); 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate #endif 770264a6e74Sfrankho if (!(vfsp->vfs_flag & VFS_UNMOUNTED) && 771264a6e74Sfrankho fsp->pcfs_fatp != (uchar_t *)0) { 7727c478bd9Sstevel@tonic-gate pc_invalfat(fsp); 7737c478bd9Sstevel@tonic-gate } else { 7747c478bd9Sstevel@tonic-gate binval(fsp->pcfs_xdev); 7757c478bd9Sstevel@tonic-gate } 7767c478bd9Sstevel@tonic-gate } 777