10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52720Sfrankho * Common Development and Distribution License (the "License"). 62720Sfrankho * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 222720Sfrankho * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/param.h> 290Sstevel@tonic-gate #include <sys/t_lock.h> 300Sstevel@tonic-gate #include <sys/systm.h> 310Sstevel@tonic-gate #include <sys/sysmacros.h> 320Sstevel@tonic-gate #include <sys/user.h> 330Sstevel@tonic-gate #include <sys/buf.h> 340Sstevel@tonic-gate #include <sys/stat.h> 350Sstevel@tonic-gate #include <sys/vfs.h> 360Sstevel@tonic-gate #include <sys/dirent.h> 370Sstevel@tonic-gate #include <sys/vnode.h> 380Sstevel@tonic-gate #include <sys/proc.h> 390Sstevel@tonic-gate #include <sys/file.h> 400Sstevel@tonic-gate #include <sys/fcntl.h> 410Sstevel@tonic-gate #include <sys/uio.h> 420Sstevel@tonic-gate #include <sys/fs/pc_label.h> 430Sstevel@tonic-gate #include <sys/fs/pc_fs.h> 440Sstevel@tonic-gate #include <sys/fs/pc_dir.h> 450Sstevel@tonic-gate #include <sys/fs/pc_node.h> 460Sstevel@tonic-gate #include <sys/mman.h> 470Sstevel@tonic-gate #include <sys/pathname.h> 480Sstevel@tonic-gate #include <sys/vmsystm.h> 490Sstevel@tonic-gate #include <sys/cmn_err.h> 500Sstevel@tonic-gate #include <sys/debug.h> 510Sstevel@tonic-gate #include <sys/statvfs.h> 520Sstevel@tonic-gate #include <sys/unistd.h> 530Sstevel@tonic-gate #include <sys/kmem.h> 540Sstevel@tonic-gate #include <sys/conf.h> 550Sstevel@tonic-gate #include <sys/flock.h> 560Sstevel@tonic-gate #include <sys/policy.h> 572720Sfrankho #include <sys/sdt.h> 580Sstevel@tonic-gate 590Sstevel@tonic-gate #include <vm/seg.h> 600Sstevel@tonic-gate #include <vm/page.h> 610Sstevel@tonic-gate #include <vm/pvn.h> 620Sstevel@tonic-gate #include <vm/seg_map.h> 630Sstevel@tonic-gate #include <vm/seg_vn.h> 640Sstevel@tonic-gate #include <vm/hat.h> 650Sstevel@tonic-gate #include <vm/as.h> 660Sstevel@tonic-gate #include <vm/seg_kmem.h> 670Sstevel@tonic-gate 680Sstevel@tonic-gate #include <fs/fs_subr.h> 690Sstevel@tonic-gate 700Sstevel@tonic-gate static int pcfs_open(struct vnode **, int, struct cred *); 710Sstevel@tonic-gate static int pcfs_close(struct vnode *, int, int, offset_t, struct cred *); 720Sstevel@tonic-gate static int pcfs_read(struct vnode *, struct uio *, int, struct cred *, 730Sstevel@tonic-gate struct caller_context *); 740Sstevel@tonic-gate static int pcfs_write(struct vnode *, struct uio *, int, struct cred *, 750Sstevel@tonic-gate struct caller_context *); 760Sstevel@tonic-gate static int pcfs_getattr(struct vnode *, struct vattr *, int, struct cred *); 770Sstevel@tonic-gate static int pcfs_setattr(struct vnode *, struct vattr *, int, struct cred *, 780Sstevel@tonic-gate caller_context_t *); 790Sstevel@tonic-gate static int pcfs_access(struct vnode *, int, int, struct cred *); 800Sstevel@tonic-gate static int pcfs_lookup(struct vnode *, char *, struct vnode **, 810Sstevel@tonic-gate struct pathname *, int, struct vnode *, struct cred *); 820Sstevel@tonic-gate static int pcfs_create(struct vnode *, char *, struct vattr *, 830Sstevel@tonic-gate enum vcexcl, int mode, struct vnode **, struct cred *, int); 840Sstevel@tonic-gate static int pcfs_remove(struct vnode *, char *, struct cred *); 850Sstevel@tonic-gate static int pcfs_rename(struct vnode *, char *, struct vnode *, char *, 860Sstevel@tonic-gate struct cred *); 870Sstevel@tonic-gate static int pcfs_mkdir(struct vnode *, char *, struct vattr *, struct vnode **, 880Sstevel@tonic-gate struct cred *); 890Sstevel@tonic-gate static int pcfs_rmdir(struct vnode *, char *, struct vnode *, struct cred *); 900Sstevel@tonic-gate static int pcfs_readdir(struct vnode *, struct uio *, struct cred *, int *); 910Sstevel@tonic-gate static int pcfs_fsync(struct vnode *, int, struct cred *); 920Sstevel@tonic-gate static void pcfs_inactive(struct vnode *, struct cred *); 930Sstevel@tonic-gate static int pcfs_fid(struct vnode *vp, struct fid *fidp); 940Sstevel@tonic-gate static int pcfs_space(struct vnode *, int, struct flock64 *, int, 950Sstevel@tonic-gate offset_t, cred_t *, caller_context_t *); 960Sstevel@tonic-gate static int pcfs_getpage(struct vnode *, offset_t, size_t, uint_t *, page_t *[], 970Sstevel@tonic-gate size_t, struct seg *, caddr_t, enum seg_rw, struct cred *); 980Sstevel@tonic-gate static int pcfs_getapage(struct vnode *, u_offset_t, size_t, uint_t *, 990Sstevel@tonic-gate page_t *[], size_t, struct seg *, caddr_t, enum seg_rw, struct cred *); 1000Sstevel@tonic-gate static int pcfs_putpage(struct vnode *, offset_t, size_t, int, struct cred *); 1010Sstevel@tonic-gate static int pcfs_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t, 1020Sstevel@tonic-gate uchar_t, uchar_t, uint_t, struct cred *); 1030Sstevel@tonic-gate static int pcfs_addmap(struct vnode *, offset_t, struct as *, caddr_t, 1040Sstevel@tonic-gate size_t, uchar_t, uchar_t, uint_t, struct cred *); 1050Sstevel@tonic-gate static int pcfs_delmap(struct vnode *, offset_t, struct as *, caddr_t, 1060Sstevel@tonic-gate size_t, uint_t, uint_t, uint_t, struct cred *); 1070Sstevel@tonic-gate static int pcfs_seek(struct vnode *, offset_t, offset_t *); 1080Sstevel@tonic-gate static int pcfs_pathconf(struct vnode *, int, ulong_t *, struct cred *); 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate int pcfs_putapage(struct vnode *, page_t *, u_offset_t *, size_t *, int, 1110Sstevel@tonic-gate struct cred *); 1120Sstevel@tonic-gate static int rwpcp(struct pcnode *, struct uio *, enum uio_rw, int); 1130Sstevel@tonic-gate static int get_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int foldcase); 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate extern krwlock_t pcnodes_lock; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate #define lround(r) (((r)+sizeof (long long)-1)&(~(sizeof (long long)-1))) 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate /* 1200Sstevel@tonic-gate * vnode op vectors for files and directories. 1210Sstevel@tonic-gate */ 1220Sstevel@tonic-gate struct vnodeops *pcfs_fvnodeops; 1230Sstevel@tonic-gate struct vnodeops *pcfs_dvnodeops; 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate const fs_operation_def_t pcfs_fvnodeops_template[] = { 1260Sstevel@tonic-gate VOPNAME_OPEN, pcfs_open, 1270Sstevel@tonic-gate VOPNAME_CLOSE, pcfs_close, 1280Sstevel@tonic-gate VOPNAME_READ, pcfs_read, 1290Sstevel@tonic-gate VOPNAME_WRITE, pcfs_write, 1300Sstevel@tonic-gate VOPNAME_GETATTR, pcfs_getattr, 1310Sstevel@tonic-gate VOPNAME_SETATTR, pcfs_setattr, 1320Sstevel@tonic-gate VOPNAME_ACCESS, pcfs_access, 1330Sstevel@tonic-gate VOPNAME_FSYNC, pcfs_fsync, 1340Sstevel@tonic-gate VOPNAME_INACTIVE, (fs_generic_func_p) pcfs_inactive, 1350Sstevel@tonic-gate VOPNAME_FID, pcfs_fid, 1360Sstevel@tonic-gate VOPNAME_SEEK, pcfs_seek, 1370Sstevel@tonic-gate VOPNAME_SPACE, pcfs_space, 1380Sstevel@tonic-gate VOPNAME_GETPAGE, pcfs_getpage, 1390Sstevel@tonic-gate VOPNAME_PUTPAGE, pcfs_putpage, 1400Sstevel@tonic-gate VOPNAME_MAP, (fs_generic_func_p) pcfs_map, 1410Sstevel@tonic-gate VOPNAME_ADDMAP, (fs_generic_func_p) pcfs_addmap, 1420Sstevel@tonic-gate VOPNAME_DELMAP, pcfs_delmap, 1430Sstevel@tonic-gate VOPNAME_PATHCONF, pcfs_pathconf, 1440Sstevel@tonic-gate VOPNAME_VNEVENT, fs_vnevent_support, 1450Sstevel@tonic-gate NULL, NULL 1460Sstevel@tonic-gate }; 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate const fs_operation_def_t pcfs_dvnodeops_template[] = { 1490Sstevel@tonic-gate VOPNAME_OPEN, pcfs_open, 1500Sstevel@tonic-gate VOPNAME_CLOSE, pcfs_close, 1510Sstevel@tonic-gate VOPNAME_GETATTR, pcfs_getattr, 1520Sstevel@tonic-gate VOPNAME_SETATTR, pcfs_setattr, 1530Sstevel@tonic-gate VOPNAME_ACCESS, pcfs_access, 1540Sstevel@tonic-gate VOPNAME_LOOKUP, pcfs_lookup, 1550Sstevel@tonic-gate VOPNAME_CREATE, pcfs_create, 1560Sstevel@tonic-gate VOPNAME_REMOVE, pcfs_remove, 1570Sstevel@tonic-gate VOPNAME_RENAME, pcfs_rename, 1580Sstevel@tonic-gate VOPNAME_MKDIR, pcfs_mkdir, 1590Sstevel@tonic-gate VOPNAME_RMDIR, pcfs_rmdir, 1600Sstevel@tonic-gate VOPNAME_READDIR, pcfs_readdir, 1610Sstevel@tonic-gate VOPNAME_FSYNC, pcfs_fsync, 1620Sstevel@tonic-gate VOPNAME_INACTIVE, (fs_generic_func_p) pcfs_inactive, 1630Sstevel@tonic-gate VOPNAME_FID, pcfs_fid, 1640Sstevel@tonic-gate VOPNAME_SEEK, pcfs_seek, 1650Sstevel@tonic-gate VOPNAME_PATHCONF, pcfs_pathconf, 1660Sstevel@tonic-gate VOPNAME_VNEVENT, fs_vnevent_support, 1670Sstevel@tonic-gate NULL, NULL 1680Sstevel@tonic-gate }; 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate /*ARGSUSED*/ 1720Sstevel@tonic-gate static int 1730Sstevel@tonic-gate pcfs_open( 1740Sstevel@tonic-gate struct vnode **vpp, 1750Sstevel@tonic-gate int flag, 1760Sstevel@tonic-gate struct cred *cr) 1770Sstevel@tonic-gate { 1780Sstevel@tonic-gate return (0); 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate /* 1820Sstevel@tonic-gate * files are sync'ed on close to keep floppy up to date 1830Sstevel@tonic-gate */ 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate /*ARGSUSED*/ 1860Sstevel@tonic-gate static int 1870Sstevel@tonic-gate pcfs_close( 1880Sstevel@tonic-gate struct vnode *vp, 1890Sstevel@tonic-gate int flag, 1900Sstevel@tonic-gate int count, 1910Sstevel@tonic-gate offset_t offset, 1920Sstevel@tonic-gate struct cred *cr) 1930Sstevel@tonic-gate { 1940Sstevel@tonic-gate return (0); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate /*ARGSUSED*/ 1980Sstevel@tonic-gate static int 1990Sstevel@tonic-gate pcfs_read( 2000Sstevel@tonic-gate struct vnode *vp, 2010Sstevel@tonic-gate struct uio *uiop, 2020Sstevel@tonic-gate int ioflag, 2030Sstevel@tonic-gate struct cred *cr, 2040Sstevel@tonic-gate struct caller_context *ct) 2050Sstevel@tonic-gate { 2060Sstevel@tonic-gate struct pcfs *fsp; 2070Sstevel@tonic-gate struct pcnode *pcp; 2080Sstevel@tonic-gate int error; 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 2110Sstevel@tonic-gate if (error = pc_verify(fsp)) 2120Sstevel@tonic-gate return (error); 2130Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 2140Sstevel@tonic-gate if (error) 2150Sstevel@tonic-gate return (error); 216*2972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 2170Sstevel@tonic-gate pc_unlockfs(fsp); 2180Sstevel@tonic-gate return (EIO); 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate error = rwpcp(pcp, uiop, UIO_READ, ioflag); 2210Sstevel@tonic-gate if ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0) { 2220Sstevel@tonic-gate pcp->pc_flags |= PC_ACC; 2230Sstevel@tonic-gate pc_mark_acc(pcp); 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate pc_unlockfs(fsp); 2260Sstevel@tonic-gate if (error) { 2270Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_read: io error = %d\n", error); 2280Sstevel@tonic-gate } 2290Sstevel@tonic-gate return (error); 2300Sstevel@tonic-gate } 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate /*ARGSUSED*/ 2330Sstevel@tonic-gate static int 2340Sstevel@tonic-gate pcfs_write( 2350Sstevel@tonic-gate struct vnode *vp, 2360Sstevel@tonic-gate struct uio *uiop, 2370Sstevel@tonic-gate int ioflag, 2380Sstevel@tonic-gate struct cred *cr, 2390Sstevel@tonic-gate struct caller_context *ct) 2400Sstevel@tonic-gate { 2410Sstevel@tonic-gate struct pcfs *fsp; 2420Sstevel@tonic-gate struct pcnode *pcp; 2430Sstevel@tonic-gate int error; 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 2460Sstevel@tonic-gate if (error = pc_verify(fsp)) 2470Sstevel@tonic-gate return (error); 2480Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 2490Sstevel@tonic-gate if (error) 2500Sstevel@tonic-gate return (error); 251*2972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 2520Sstevel@tonic-gate pc_unlockfs(fsp); 2530Sstevel@tonic-gate return (EIO); 2540Sstevel@tonic-gate } 2550Sstevel@tonic-gate if (ioflag & FAPPEND) { 2560Sstevel@tonic-gate /* 2570Sstevel@tonic-gate * in append mode start at end of file. 2580Sstevel@tonic-gate */ 2590Sstevel@tonic-gate uiop->uio_loffset = pcp->pc_size; 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate error = rwpcp(pcp, uiop, UIO_WRITE, ioflag); 2620Sstevel@tonic-gate pcp->pc_flags |= PC_MOD; 2630Sstevel@tonic-gate pc_mark_mod(pcp); 2640Sstevel@tonic-gate if (ioflag & (FSYNC|FDSYNC)) 2650Sstevel@tonic-gate (void) pc_nodeupdate(pcp); 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate pc_unlockfs(fsp); 2680Sstevel@tonic-gate if (error) { 2690Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_write: io error = %d\n", error); 2700Sstevel@tonic-gate } 2710Sstevel@tonic-gate return (error); 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate /* 2750Sstevel@tonic-gate * read or write a vnode 2760Sstevel@tonic-gate */ 2770Sstevel@tonic-gate static int 2780Sstevel@tonic-gate rwpcp( 2790Sstevel@tonic-gate struct pcnode *pcp, 2800Sstevel@tonic-gate struct uio *uio, 2810Sstevel@tonic-gate enum uio_rw rw, 2820Sstevel@tonic-gate int ioflag) 2830Sstevel@tonic-gate { 2840Sstevel@tonic-gate struct vnode *vp = PCTOV(pcp); 2850Sstevel@tonic-gate struct pcfs *fsp; 2860Sstevel@tonic-gate daddr_t bn; /* phys block number */ 2870Sstevel@tonic-gate int n; 2880Sstevel@tonic-gate offset_t off; 2890Sstevel@tonic-gate caddr_t base; 2900Sstevel@tonic-gate int mapon, pagecreate; 2910Sstevel@tonic-gate int newpage; 2920Sstevel@tonic-gate int error = 0; 2930Sstevel@tonic-gate rlim64_t limit = uio->uio_llimit; 2940Sstevel@tonic-gate int oresid = uio->uio_resid; 2950Sstevel@tonic-gate 2962720Sfrankho /* 2972720Sfrankho * If the filesystem was umounted by force, return immediately. 2982720Sfrankho */ 2992720Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 3002720Sfrankho return (EIO); 3012720Sfrankho 3020Sstevel@tonic-gate PC_DPRINTF4(5, "rwpcp pcp=%p off=%lld resid=%ld size=%u\n", (void *)pcp, 3030Sstevel@tonic-gate uio->uio_loffset, uio->uio_resid, pcp->pc_size); 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate ASSERT(rw == UIO_READ || rw == UIO_WRITE); 3060Sstevel@tonic-gate ASSERT(vp->v_type == VREG); 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate if (uio->uio_loffset >= UINT32_MAX && rw == UIO_READ) { 3090Sstevel@tonic-gate return (0); 3100Sstevel@tonic-gate } 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate if (uio->uio_loffset < 0) 3130Sstevel@tonic-gate return (EINVAL); 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T) 3160Sstevel@tonic-gate limit = MAXOFFSET_T; 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate if (uio->uio_loffset >= limit && rw == UIO_WRITE) { 3190Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate mutex_enter(&p->p_lock); 3220Sstevel@tonic-gate (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], p->p_rctls, 3230Sstevel@tonic-gate p, RCA_UNSAFE_SIGINFO); 3240Sstevel@tonic-gate mutex_exit(&p->p_lock); 3250Sstevel@tonic-gate return (EFBIG); 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate /* the following condition will occur only for write */ 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate if (uio->uio_loffset >= UINT32_MAX) 3310Sstevel@tonic-gate return (EFBIG); 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate if (uio->uio_resid == 0) 3340Sstevel@tonic-gate return (0); 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate if (limit > UINT32_MAX) 3370Sstevel@tonic-gate limit = UINT32_MAX; 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 3400Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_IRRECOV) 3410Sstevel@tonic-gate return (EIO); 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate do { 3440Sstevel@tonic-gate /* 3450Sstevel@tonic-gate * Assignments to "n" in this block may appear 3460Sstevel@tonic-gate * to overflow in some cases. However, after careful 3470Sstevel@tonic-gate * analysis it was determined that all assignments to 3480Sstevel@tonic-gate * "n" serve only to make "n" smaller. Since "n" 3490Sstevel@tonic-gate * starts out as no larger than MAXBSIZE, "int" is 3500Sstevel@tonic-gate * safe. 3510Sstevel@tonic-gate */ 3520Sstevel@tonic-gate off = uio->uio_loffset & MAXBMASK; 3530Sstevel@tonic-gate mapon = (int)(uio->uio_loffset & MAXBOFFSET); 3540Sstevel@tonic-gate n = MIN(MAXBSIZE - mapon, uio->uio_resid); 3550Sstevel@tonic-gate if (rw == UIO_READ) { 3560Sstevel@tonic-gate offset_t diff; 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate diff = pcp->pc_size - uio->uio_loffset; 3590Sstevel@tonic-gate if (diff <= 0) 3600Sstevel@tonic-gate return (0); 3610Sstevel@tonic-gate if (diff < n) 3620Sstevel@tonic-gate n = (int)diff; 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate /* 3650Sstevel@tonic-gate * Compare limit with the actual offset + n, not the 3660Sstevel@tonic-gate * rounded down offset "off" or we will overflow 3670Sstevel@tonic-gate * the maximum file size after all. 3680Sstevel@tonic-gate */ 3690Sstevel@tonic-gate if (rw == UIO_WRITE && uio->uio_loffset + n >= limit) { 3700Sstevel@tonic-gate if (uio->uio_loffset >= limit) { 3710Sstevel@tonic-gate error = EFBIG; 3720Sstevel@tonic-gate break; 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate n = (int)(limit - uio->uio_loffset); 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate base = segmap_getmap(segkmap, vp, (u_offset_t)off); 3770Sstevel@tonic-gate pagecreate = 0; 3780Sstevel@tonic-gate newpage = 0; 3790Sstevel@tonic-gate if (rw == UIO_WRITE) { 3800Sstevel@tonic-gate /* 3810Sstevel@tonic-gate * If PAGESIZE < MAXBSIZE, perhaps we ought to deal 3820Sstevel@tonic-gate * with one page at a time, instead of one MAXBSIZE 3830Sstevel@tonic-gate * at a time, so we can fully explore pagecreate 3840Sstevel@tonic-gate * optimization?? 3850Sstevel@tonic-gate */ 3860Sstevel@tonic-gate if (uio->uio_loffset + n > pcp->pc_size) { 3870Sstevel@tonic-gate uint_t ncl, lcn; 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate ncl = (uint_t)howmany((offset_t)pcp->pc_size, 3900Sstevel@tonic-gate fsp->pcfs_clsize); 3910Sstevel@tonic-gate if (uio->uio_loffset > pcp->pc_size && 3920Sstevel@tonic-gate ncl < (uint_t)howmany(uio->uio_loffset, 3930Sstevel@tonic-gate fsp->pcfs_clsize)) { 3940Sstevel@tonic-gate /* 3950Sstevel@tonic-gate * Allocate and zerofill skipped 3960Sstevel@tonic-gate * clusters. This may not be worth the 3970Sstevel@tonic-gate * effort since a small lseek beyond 3980Sstevel@tonic-gate * eof but still within the cluster 3990Sstevel@tonic-gate * will not be zeroed out. 4000Sstevel@tonic-gate */ 4010Sstevel@tonic-gate lcn = pc_lblkno(fsp, uio->uio_loffset); 4020Sstevel@tonic-gate error = pc_balloc(pcp, (daddr_t)lcn, 4030Sstevel@tonic-gate 1, &bn); 4040Sstevel@tonic-gate ncl = lcn + 1; 4050Sstevel@tonic-gate } 4060Sstevel@tonic-gate if (!error && 4070Sstevel@tonic-gate ncl < (uint_t)howmany(uio->uio_loffset + n, 4080Sstevel@tonic-gate fsp->pcfs_clsize)) 4090Sstevel@tonic-gate /* 4100Sstevel@tonic-gate * allocate clusters w/o zerofill 4110Sstevel@tonic-gate */ 4120Sstevel@tonic-gate error = pc_balloc(pcp, 4130Sstevel@tonic-gate (daddr_t)pc_lblkno(fsp, 4140Sstevel@tonic-gate uio->uio_loffset + n - 1), 4150Sstevel@tonic-gate 0, &bn); 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate if (error) { 420*2972Sfrankho pc_cluster32_t ncl; 421*2972Sfrankho int nerror; 422*2972Sfrankho 423*2972Sfrankho /* 424*2972Sfrankho * figure out new file size from 425*2972Sfrankho * cluster chain length. If this 426*2972Sfrankho * is detected to loop, the chain 427*2972Sfrankho * is corrupted and we'd better 428*2972Sfrankho * keep our fingers off that file. 429*2972Sfrankho */ 430*2972Sfrankho nerror = pc_fileclsize(fsp, 431*2972Sfrankho pcp->pc_scluster, &ncl); 432*2972Sfrankho if (nerror) { 433*2972Sfrankho PC_DPRINTF1(2, 434*2972Sfrankho "cluster chain " 435*2972Sfrankho "corruption, " 436*2972Sfrankho "scluster=%d\n", 437*2972Sfrankho pcp->pc_scluster); 438*2972Sfrankho pcp->pc_size = 0; 439*2972Sfrankho pcp->pc_flags |= PC_INVAL; 440*2972Sfrankho error = nerror; 441*2972Sfrankho (void) segmap_release(segkmap, 442*2972Sfrankho base, 0); 443*2972Sfrankho break; 444*2972Sfrankho } 445*2972Sfrankho pcp->pc_size = fsp->pcfs_clsize * ncl; 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate if (error == ENOSPC && 4480Sstevel@tonic-gate (pcp->pc_size - uio->uio_loffset) 4490Sstevel@tonic-gate > 0) { 4500Sstevel@tonic-gate PC_DPRINTF3(2, "rwpcp ENOSPC " 4510Sstevel@tonic-gate "off=%lld n=%d size=%d\n", 4520Sstevel@tonic-gate uio->uio_loffset, 4530Sstevel@tonic-gate n, pcp->pc_size); 4540Sstevel@tonic-gate n = (int)(pcp->pc_size - 4550Sstevel@tonic-gate uio->uio_loffset); 4560Sstevel@tonic-gate } else { 4570Sstevel@tonic-gate PC_DPRINTF1(1, 4580Sstevel@tonic-gate "rwpcp error1=%d\n", error); 4590Sstevel@tonic-gate (void) segmap_release(segkmap, 4600Sstevel@tonic-gate base, 0); 4610Sstevel@tonic-gate break; 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate } else { 4640Sstevel@tonic-gate pcp->pc_size = 4650Sstevel@tonic-gate (uint_t)(uio->uio_loffset + n); 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate if (mapon == 0) { 4680Sstevel@tonic-gate newpage = segmap_pagecreate(segkmap, 4690Sstevel@tonic-gate base, (size_t)n, 0); 4700Sstevel@tonic-gate pagecreate = 1; 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate } else if (n == MAXBSIZE) { 4730Sstevel@tonic-gate newpage = segmap_pagecreate(segkmap, base, 4740Sstevel@tonic-gate (size_t)n, 0); 4750Sstevel@tonic-gate pagecreate = 1; 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate error = uiomove(base + mapon, (size_t)n, rw, uio); 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate if (pagecreate && uio->uio_loffset < 4810Sstevel@tonic-gate roundup(off + mapon + n, PAGESIZE)) { 4820Sstevel@tonic-gate offset_t nzero, nmoved; 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate nmoved = uio->uio_loffset - (off + mapon); 4850Sstevel@tonic-gate nzero = roundup(mapon + n, PAGESIZE) - nmoved; 4860Sstevel@tonic-gate (void) kzero(base + mapon + nmoved, (size_t)nzero); 4870Sstevel@tonic-gate } 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate /* 4900Sstevel@tonic-gate * Unlock the pages which have been allocated by 4910Sstevel@tonic-gate * page_create_va() in segmap_pagecreate(). 4920Sstevel@tonic-gate */ 4930Sstevel@tonic-gate if (newpage) 4940Sstevel@tonic-gate segmap_pageunlock(segkmap, base, (size_t)n, 4950Sstevel@tonic-gate rw == UIO_WRITE ? S_WRITE : S_READ); 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate if (error) { 4980Sstevel@tonic-gate PC_DPRINTF1(1, "rwpcp error2=%d\n", error); 4990Sstevel@tonic-gate /* 5000Sstevel@tonic-gate * If we failed on a write, we may have already 5010Sstevel@tonic-gate * allocated file blocks as well as pages. It's hard 5020Sstevel@tonic-gate * to undo the block allocation, but we must be sure 5030Sstevel@tonic-gate * to invalidate any pages that may have been 5040Sstevel@tonic-gate * allocated. 5050Sstevel@tonic-gate */ 5060Sstevel@tonic-gate if (rw == UIO_WRITE) 5070Sstevel@tonic-gate (void) segmap_release(segkmap, base, SM_INVAL); 5080Sstevel@tonic-gate else 5090Sstevel@tonic-gate (void) segmap_release(segkmap, base, 0); 5100Sstevel@tonic-gate } else { 5110Sstevel@tonic-gate uint_t flags = 0; 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate if (rw == UIO_READ) { 5140Sstevel@tonic-gate if (n + mapon == MAXBSIZE || 5150Sstevel@tonic-gate uio->uio_loffset == pcp->pc_size) 5160Sstevel@tonic-gate flags = SM_DONTNEED; 5170Sstevel@tonic-gate } else if (ioflag & (FSYNC|FDSYNC)) { 5180Sstevel@tonic-gate flags = SM_WRITE; 5190Sstevel@tonic-gate } else if (n + mapon == MAXBSIZE) { 5200Sstevel@tonic-gate flags = SM_WRITE|SM_ASYNC|SM_DONTNEED; 5210Sstevel@tonic-gate } 5220Sstevel@tonic-gate error = segmap_release(segkmap, base, flags); 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate } while (error == 0 && uio->uio_resid > 0 && n != 0); 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate if (oresid != uio->uio_resid) 5280Sstevel@tonic-gate error = 0; 5290Sstevel@tonic-gate return (error); 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate /*ARGSUSED*/ 5330Sstevel@tonic-gate static int 5340Sstevel@tonic-gate pcfs_getattr( 5350Sstevel@tonic-gate struct vnode *vp, 5360Sstevel@tonic-gate struct vattr *vap, 5370Sstevel@tonic-gate int flags, 5380Sstevel@tonic-gate struct cred *cr) 5390Sstevel@tonic-gate { 5400Sstevel@tonic-gate struct pcnode *pcp; 5410Sstevel@tonic-gate struct pcfs *fsp; 5420Sstevel@tonic-gate int error; 5430Sstevel@tonic-gate char attr; 5440Sstevel@tonic-gate struct pctime atime; 5452720Sfrankho int64_t unixtime; 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate PC_DPRINTF1(8, "pcfs_getattr: vp=%p\n", (void *)vp); 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 5500Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 5510Sstevel@tonic-gate if (error) 5520Sstevel@tonic-gate return (error); 553*2972Sfrankho 554*2972Sfrankho /* 555*2972Sfrankho * Note that we don't check for "invalid node" (PC_INVAL) here 556*2972Sfrankho * only in order to make stat() succeed. We allow no I/O on such 557*2972Sfrankho * a node, but do allow to check for its existance. 558*2972Sfrankho */ 5590Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) { 5600Sstevel@tonic-gate pc_unlockfs(fsp); 5610Sstevel@tonic-gate return (EIO); 5620Sstevel@tonic-gate } 5630Sstevel@tonic-gate /* 5640Sstevel@tonic-gate * Copy from pcnode. 5650Sstevel@tonic-gate */ 5660Sstevel@tonic-gate vap->va_type = vp->v_type; 5670Sstevel@tonic-gate attr = pcp->pc_entry.pcd_attr; 5680Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, attr)) 5690Sstevel@tonic-gate vap->va_mode = 0; 5700Sstevel@tonic-gate else if (attr & PCA_LABEL) 5710Sstevel@tonic-gate vap->va_mode = 0444; 5720Sstevel@tonic-gate else if (attr & PCA_RDONLY) 5730Sstevel@tonic-gate vap->va_mode = 0555; 5740Sstevel@tonic-gate else if (fsp->pcfs_flags & PCFS_BOOTPART) { 5750Sstevel@tonic-gate vap->va_mode = 0755; 5760Sstevel@tonic-gate } else { 5770Sstevel@tonic-gate vap->va_mode = 0777; 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate if (attr & PCA_DIR) 5810Sstevel@tonic-gate vap->va_mode |= S_IFDIR; 5820Sstevel@tonic-gate else 5830Sstevel@tonic-gate vap->va_mode |= S_IFREG; 5840Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 5850Sstevel@tonic-gate vap->va_uid = 0; 5860Sstevel@tonic-gate vap->va_gid = 0; 5870Sstevel@tonic-gate } else { 5880Sstevel@tonic-gate vap->va_uid = crgetuid(cr); 5890Sstevel@tonic-gate vap->va_gid = crgetgid(cr); 5900Sstevel@tonic-gate } 5910Sstevel@tonic-gate vap->va_fsid = vp->v_vfsp->vfs_dev; 5920Sstevel@tonic-gate vap->va_nodeid = (ino64_t)pc_makenodeid(pcp->pc_eblkno, 5930Sstevel@tonic-gate pcp->pc_eoffset, pcp->pc_entry.pcd_attr, 5940Sstevel@tonic-gate pc_getstartcluster(fsp, &pcp->pc_entry), fsp->pcfs_entps); 5950Sstevel@tonic-gate vap->va_nlink = 1; 5960Sstevel@tonic-gate vap->va_size = (u_offset_t)pcp->pc_size; 5972720Sfrankho 5982720Sfrankho pc_pcttotv(&pcp->pc_entry.pcd_mtime, &unixtime); 5992720Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) { 6002720Sfrankho if (unixtime > INT32_MAX) 6012720Sfrankho DTRACE_PROBE1(pcfs__mtimeclamped, int64_t, unixtime); 6022720Sfrankho unixtime = MIN(unixtime, INT32_MAX); 6032720Sfrankho } else if (unixtime > INT32_MAX && 6042720Sfrankho get_udatamodel() == DATAMODEL_ILP32) { 6052720Sfrankho pc_unlockfs(fsp); 6062720Sfrankho DTRACE_PROBE1(pcfs__mtimeoverflowed, int64_t, unixtime); 6072720Sfrankho return (EOVERFLOW); 6082720Sfrankho } 6092720Sfrankho 6102720Sfrankho vap->va_mtime.tv_sec = (time_t)unixtime; 6112720Sfrankho vap->va_mtime.tv_nsec = 0; 6122720Sfrankho 6132720Sfrankho /* 6142720Sfrankho * FAT doesn't know about POSIX ctime. 6152720Sfrankho * Best approximation is to always set it to mtime. 6162720Sfrankho */ 6170Sstevel@tonic-gate vap->va_ctime = vap->va_mtime; 6182720Sfrankho 6192720Sfrankho /* 6202720Sfrankho * FAT only stores "last access date". If that's the 6212720Sfrankho * same as the date of last modification then the time 6222720Sfrankho * of last access is known. Otherwise, use midnight. 6232720Sfrankho */ 6240Sstevel@tonic-gate atime.pct_date = pcp->pc_entry.pcd_ladate; 6252720Sfrankho if (atime.pct_date == pcp->pc_entry.pcd_mtime.pct_date) 6262720Sfrankho atime.pct_time = pcp->pc_entry.pcd_mtime.pct_time; 6272720Sfrankho else 6282720Sfrankho atime.pct_time = 0; 6292720Sfrankho pc_pcttotv(&atime, &unixtime); 6302720Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) { 6312720Sfrankho if (unixtime > INT32_MAX) 6322720Sfrankho DTRACE_PROBE1(pcfs__atimeclamped, int64_t, unixtime); 6332720Sfrankho unixtime = MIN(unixtime, INT32_MAX); 6342720Sfrankho } else if (unixtime > INT32_MAX && 6352720Sfrankho get_udatamodel() == DATAMODEL_ILP32) { 6362720Sfrankho pc_unlockfs(fsp); 6372720Sfrankho DTRACE_PROBE1(pcfs__atimeoverflowed, int64_t, unixtime); 6382720Sfrankho return (EOVERFLOW); 6392720Sfrankho } 6402720Sfrankho 6412720Sfrankho vap->va_atime.tv_sec = (time_t)unixtime; 6422720Sfrankho vap->va_atime.tv_nsec = 0; 6432720Sfrankho 6440Sstevel@tonic-gate vap->va_rdev = 0; 6450Sstevel@tonic-gate vap->va_nblocks = (fsblkcnt64_t)howmany((offset_t)pcp->pc_size, 6460Sstevel@tonic-gate DEV_BSIZE); 6470Sstevel@tonic-gate vap->va_blksize = fsp->pcfs_clsize; 6480Sstevel@tonic-gate pc_unlockfs(fsp); 6490Sstevel@tonic-gate return (0); 6500Sstevel@tonic-gate } 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate /*ARGSUSED*/ 6540Sstevel@tonic-gate static int 6550Sstevel@tonic-gate pcfs_setattr( 6560Sstevel@tonic-gate struct vnode *vp, 6570Sstevel@tonic-gate struct vattr *vap, 6580Sstevel@tonic-gate int flags, 6590Sstevel@tonic-gate struct cred *cr, 6600Sstevel@tonic-gate caller_context_t *ct) 6610Sstevel@tonic-gate { 6620Sstevel@tonic-gate struct pcnode *pcp; 6630Sstevel@tonic-gate mode_t mask = vap->va_mask; 6640Sstevel@tonic-gate int error; 6650Sstevel@tonic-gate struct pcfs *fsp; 6662720Sfrankho timestruc_t now, *timep; 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate PC_DPRINTF2(6, "pcfs_setattr: vp=%p mask=%x\n", (void *)vp, (int)mask); 6690Sstevel@tonic-gate /* 6700Sstevel@tonic-gate * cannot set these attributes 6710Sstevel@tonic-gate */ 6720Sstevel@tonic-gate if (mask & (AT_NOSET | AT_UID | AT_GID)) { 6730Sstevel@tonic-gate return (EINVAL); 6740Sstevel@tonic-gate } 6750Sstevel@tonic-gate /* 6762720Sfrankho * pcfs_setattr is now allowed on directories to avoid silly warnings 6770Sstevel@tonic-gate * from 'tar' when it tries to set times on a directory, and console 6780Sstevel@tonic-gate * printf's on the NFS server when it gets EINVAL back on such a 6790Sstevel@tonic-gate * request. One possible problem with that since a directory entry 6800Sstevel@tonic-gate * identifies a file, '.' and all the '..' entries in subdirectories 6810Sstevel@tonic-gate * may get out of sync when the directory is updated since they're 6820Sstevel@tonic-gate * treated like separate files. We could fix that by looking for 6830Sstevel@tonic-gate * '.' and giving it the same attributes, and then looking for 6840Sstevel@tonic-gate * all the subdirectories and updating '..', but that's pretty 6850Sstevel@tonic-gate * expensive for something that doesn't seem likely to matter. 6860Sstevel@tonic-gate */ 6870Sstevel@tonic-gate /* can't do some ops on directories anyway */ 6880Sstevel@tonic-gate if ((vp->v_type == VDIR) && 6890Sstevel@tonic-gate (mask & AT_SIZE)) { 6900Sstevel@tonic-gate return (EINVAL); 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate 6930Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 6940Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 6950Sstevel@tonic-gate if (error) 6960Sstevel@tonic-gate return (error); 697*2972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 6980Sstevel@tonic-gate pc_unlockfs(fsp); 6990Sstevel@tonic-gate return (EIO); 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 7030Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 7040Sstevel@tonic-gate pc_unlockfs(fsp); 7050Sstevel@tonic-gate return (EACCES); 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate } 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate /* 7100Sstevel@tonic-gate * Change file access modes. 7110Sstevel@tonic-gate * If nobody has write permission, file is marked readonly. 7120Sstevel@tonic-gate * Otherwise file is writable by anyone. 7130Sstevel@tonic-gate */ 7140Sstevel@tonic-gate if ((mask & AT_MODE) && (vap->va_mode != (mode_t)-1)) { 7150Sstevel@tonic-gate if ((vap->va_mode & 0222) == 0) 7160Sstevel@tonic-gate pcp->pc_entry.pcd_attr |= PCA_RDONLY; 7170Sstevel@tonic-gate else 7180Sstevel@tonic-gate pcp->pc_entry.pcd_attr &= ~PCA_RDONLY; 7190Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate /* 7220Sstevel@tonic-gate * Truncate file. Must have write permission. 7230Sstevel@tonic-gate */ 7240Sstevel@tonic-gate if ((mask & AT_SIZE) && (vap->va_size != (u_offset_t)-1)) { 7250Sstevel@tonic-gate if (pcp->pc_entry.pcd_attr & PCA_RDONLY) { 7260Sstevel@tonic-gate error = EACCES; 7270Sstevel@tonic-gate goto out; 7280Sstevel@tonic-gate } 7290Sstevel@tonic-gate if (vap->va_size > UINT32_MAX) { 7300Sstevel@tonic-gate error = EFBIG; 7310Sstevel@tonic-gate goto out; 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate error = pc_truncate(pcp, (uint_t)vap->va_size); 7340Sstevel@tonic-gate if (error) 7350Sstevel@tonic-gate goto out; 7360Sstevel@tonic-gate } 7370Sstevel@tonic-gate /* 7380Sstevel@tonic-gate * Change file modified times. 7390Sstevel@tonic-gate */ 7402720Sfrankho if (mask & (AT_MTIME | AT_CTIME)) { 7410Sstevel@tonic-gate /* 7420Sstevel@tonic-gate * If SysV-compatible option to set access and 7430Sstevel@tonic-gate * modified times if privileged, owner, or write access, 7440Sstevel@tonic-gate * use current time rather than va_mtime. 7450Sstevel@tonic-gate * 7460Sstevel@tonic-gate * XXX - va_mtime.tv_sec == -1 flags this. 7470Sstevel@tonic-gate */ 7482720Sfrankho timep = &vap->va_mtime; 7490Sstevel@tonic-gate if (vap->va_mtime.tv_sec == -1) { 7500Sstevel@tonic-gate gethrestime(&now); 7512720Sfrankho timep = &now; 7520Sstevel@tonic-gate } 7532720Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 && 7542720Sfrankho timep->tv_sec > INT32_MAX) { 7552720Sfrankho error = EOVERFLOW; 7562720Sfrankho goto out; 7572720Sfrankho } 7582720Sfrankho error = pc_tvtopct(timep, &pcp->pc_entry.pcd_mtime); 7592720Sfrankho if (error) 7602720Sfrankho goto out; 7610Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 7620Sstevel@tonic-gate } 7630Sstevel@tonic-gate /* 7640Sstevel@tonic-gate * Change file access times. 7650Sstevel@tonic-gate */ 7662720Sfrankho if (mask & AT_ATIME) { 7670Sstevel@tonic-gate /* 7680Sstevel@tonic-gate * If SysV-compatible option to set access and 7690Sstevel@tonic-gate * modified times if privileged, owner, or write access, 7700Sstevel@tonic-gate * use current time rather than va_mtime. 7710Sstevel@tonic-gate * 7720Sstevel@tonic-gate * XXX - va_atime.tv_sec == -1 flags this. 7730Sstevel@tonic-gate */ 7740Sstevel@tonic-gate struct pctime atime; 7750Sstevel@tonic-gate 7762720Sfrankho timep = &vap->va_atime; 7770Sstevel@tonic-gate if (vap->va_atime.tv_sec == -1) { 7780Sstevel@tonic-gate gethrestime(&now); 7792720Sfrankho timep = &now; 7800Sstevel@tonic-gate } 7812720Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 && 7822720Sfrankho timep->tv_sec > INT32_MAX) { 7832720Sfrankho error = EOVERFLOW; 7842720Sfrankho goto out; 7852720Sfrankho } 7862720Sfrankho error = pc_tvtopct(timep, &atime); 7872720Sfrankho if (error) 7882720Sfrankho goto out; 7890Sstevel@tonic-gate pcp->pc_entry.pcd_ladate = atime.pct_date; 7900Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 7910Sstevel@tonic-gate } 7920Sstevel@tonic-gate out: 7930Sstevel@tonic-gate pc_unlockfs(fsp); 7940Sstevel@tonic-gate return (error); 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate /*ARGSUSED*/ 7990Sstevel@tonic-gate static int 8000Sstevel@tonic-gate pcfs_access( 8010Sstevel@tonic-gate struct vnode *vp, 8020Sstevel@tonic-gate int mode, 8030Sstevel@tonic-gate int flags, 8040Sstevel@tonic-gate struct cred *cr) 8050Sstevel@tonic-gate { 8060Sstevel@tonic-gate struct pcnode *pcp; 8070Sstevel@tonic-gate struct pcfs *fsp; 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 8110Sstevel@tonic-gate 812*2972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) 8130Sstevel@tonic-gate return (EIO); 8140Sstevel@tonic-gate if ((mode & VWRITE) && (pcp->pc_entry.pcd_attr & PCA_RDONLY)) 8150Sstevel@tonic-gate return (EACCES); 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate /* 8180Sstevel@tonic-gate * If this is a boot partition, privileged users have full access while 8190Sstevel@tonic-gate * others have read-only access. 8200Sstevel@tonic-gate */ 8210Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 8220Sstevel@tonic-gate if ((mode & VWRITE) && 8230Sstevel@tonic-gate secpolicy_pcfs_modify_bootpartition(cr) != 0) 8240Sstevel@tonic-gate return (EACCES); 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate return (0); 8270Sstevel@tonic-gate } 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate /*ARGSUSED*/ 8310Sstevel@tonic-gate static int 8320Sstevel@tonic-gate pcfs_fsync( 8330Sstevel@tonic-gate struct vnode *vp, 8340Sstevel@tonic-gate int syncflag, 8350Sstevel@tonic-gate struct cred *cr) 8360Sstevel@tonic-gate { 8370Sstevel@tonic-gate struct pcfs *fsp; 8380Sstevel@tonic-gate struct pcnode *pcp; 8390Sstevel@tonic-gate int error; 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 8420Sstevel@tonic-gate if (error = pc_verify(fsp)) 8430Sstevel@tonic-gate return (error); 8440Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 8450Sstevel@tonic-gate if (error) 8460Sstevel@tonic-gate return (error); 847*2972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 8480Sstevel@tonic-gate pc_unlockfs(fsp); 8490Sstevel@tonic-gate return (EIO); 8500Sstevel@tonic-gate } 8510Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_WRITER); 8520Sstevel@tonic-gate error = pc_nodesync(pcp); 8530Sstevel@tonic-gate rw_exit(&pcnodes_lock); 8540Sstevel@tonic-gate pc_unlockfs(fsp); 8550Sstevel@tonic-gate return (error); 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate /*ARGSUSED*/ 8600Sstevel@tonic-gate static void 8610Sstevel@tonic-gate pcfs_inactive( 8620Sstevel@tonic-gate struct vnode *vp, 8630Sstevel@tonic-gate struct cred *cr) 8640Sstevel@tonic-gate { 8650Sstevel@tonic-gate struct pcnode *pcp; 8660Sstevel@tonic-gate struct pcfs *fsp; 8670Sstevel@tonic-gate int error; 8680Sstevel@tonic-gate 8690Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 8700Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 1); 8710Sstevel@tonic-gate 8722720Sfrankho /* 8732720Sfrankho * If the filesystem was umounted by force, all dirty 8742720Sfrankho * pages associated with this vnode are invalidated 8752720Sfrankho * and then the vnode will be freed. 8762720Sfrankho */ 8772720Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) { 8782720Sfrankho pcp = VTOPC(vp); 8792720Sfrankho if (vn_has_cached_data(vp)) { 8802720Sfrankho (void) pvn_vplist_dirty(vp, (u_offset_t)0, 8812720Sfrankho pcfs_putapage, B_INVAL, (struct cred *)NULL); 8822720Sfrankho } 8832720Sfrankho remque(pcp); 8842720Sfrankho if (error == 0) 8852720Sfrankho pc_unlockfs(fsp); 8862720Sfrankho vn_free(vp); 8872720Sfrankho kmem_free(pcp, sizeof (struct pcnode)); 8882720Sfrankho VFS_RELE(PCFSTOVFS(fsp)); 8892720Sfrankho return; 8902720Sfrankho } 8912720Sfrankho 8920Sstevel@tonic-gate mutex_enter(&vp->v_lock); 8930Sstevel@tonic-gate ASSERT(vp->v_count >= 1); 8940Sstevel@tonic-gate if (vp->v_count > 1) { 8950Sstevel@tonic-gate vp->v_count--; /* release our hold from vn_rele */ 8960Sstevel@tonic-gate mutex_exit(&vp->v_lock); 8970Sstevel@tonic-gate pc_unlockfs(fsp); 8980Sstevel@tonic-gate return; 8990Sstevel@tonic-gate } 9000Sstevel@tonic-gate mutex_exit(&vp->v_lock); 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate /* 9030Sstevel@tonic-gate * Check again to confirm that no intervening I/O error 9040Sstevel@tonic-gate * with a subsequent pc_diskchanged() call has released 905*2972Sfrankho * the pcnode. If it has then release the vnode as above. 9060Sstevel@tonic-gate */ 907*2972Sfrankho pcp = VTOPC(vp); 908*2972Sfrankho if (pcp == NULL || pcp->pc_flags & PC_INVAL) { 9092720Sfrankho if (vn_has_cached_data(vp)) 9102720Sfrankho (void) pvn_vplist_dirty(vp, (u_offset_t)0, 9112720Sfrankho pcfs_putapage, B_INVAL | B_TRUNC, 9122720Sfrankho (struct cred *)NULL); 913*2972Sfrankho } 914*2972Sfrankho 915*2972Sfrankho if (pcp == NULL) { 9160Sstevel@tonic-gate vn_free(vp); 9172720Sfrankho } else { 9180Sstevel@tonic-gate pc_rele(pcp); 9192720Sfrankho } 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate if (!error) 9220Sstevel@tonic-gate pc_unlockfs(fsp); 9230Sstevel@tonic-gate } 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate /*ARGSUSED*/ 9260Sstevel@tonic-gate static int 9270Sstevel@tonic-gate pcfs_lookup( 9280Sstevel@tonic-gate struct vnode *dvp, 9290Sstevel@tonic-gate char *nm, 9300Sstevel@tonic-gate struct vnode **vpp, 9310Sstevel@tonic-gate struct pathname *pnp, 9320Sstevel@tonic-gate int flags, 9330Sstevel@tonic-gate struct vnode *rdir, 9340Sstevel@tonic-gate struct cred *cr) 9350Sstevel@tonic-gate { 9360Sstevel@tonic-gate struct pcfs *fsp; 9370Sstevel@tonic-gate struct pcnode *pcp; 9380Sstevel@tonic-gate int error; 9390Sstevel@tonic-gate 9400Sstevel@tonic-gate /* 9412720Sfrankho * If the filesystem was umounted by force, return immediately. 9422720Sfrankho */ 9432720Sfrankho if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 9442720Sfrankho return (EIO); 9452720Sfrankho 9462720Sfrankho /* 9470Sstevel@tonic-gate * verify that the dvp is still valid on the disk 9480Sstevel@tonic-gate */ 9490Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 9500Sstevel@tonic-gate if (error = pc_verify(fsp)) 9510Sstevel@tonic-gate return (error); 9520Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 9530Sstevel@tonic-gate if (error) 9540Sstevel@tonic-gate return (error); 955*2972Sfrankho if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) { 9560Sstevel@tonic-gate pc_unlockfs(fsp); 9570Sstevel@tonic-gate return (EIO); 9580Sstevel@tonic-gate } 9590Sstevel@tonic-gate /* 9600Sstevel@tonic-gate * Null component name is a synonym for directory being searched. 9610Sstevel@tonic-gate */ 9620Sstevel@tonic-gate if (*nm == '\0') { 9630Sstevel@tonic-gate VN_HOLD(dvp); 9640Sstevel@tonic-gate *vpp = dvp; 9650Sstevel@tonic-gate pc_unlockfs(fsp); 9660Sstevel@tonic-gate return (0); 9670Sstevel@tonic-gate } 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate error = pc_dirlook(VTOPC(dvp), nm, &pcp); 9700Sstevel@tonic-gate if (!error) { 9710Sstevel@tonic-gate *vpp = PCTOV(pcp); 9720Sstevel@tonic-gate pcp->pc_flags |= PC_EXTERNAL; 9730Sstevel@tonic-gate } 9740Sstevel@tonic-gate pc_unlockfs(fsp); 9750Sstevel@tonic-gate return (error); 9760Sstevel@tonic-gate } 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate /*ARGSUSED*/ 9800Sstevel@tonic-gate static int 9810Sstevel@tonic-gate pcfs_create( 9820Sstevel@tonic-gate struct vnode *dvp, 9830Sstevel@tonic-gate char *nm, 9840Sstevel@tonic-gate struct vattr *vap, 9850Sstevel@tonic-gate enum vcexcl exclusive, 9860Sstevel@tonic-gate int mode, 9870Sstevel@tonic-gate struct vnode **vpp, 9880Sstevel@tonic-gate struct cred *cr, 9890Sstevel@tonic-gate int flag) 9900Sstevel@tonic-gate { 9910Sstevel@tonic-gate int error; 9920Sstevel@tonic-gate struct pcnode *pcp; 9930Sstevel@tonic-gate struct vnode *vp; 9940Sstevel@tonic-gate struct pcfs *fsp; 9950Sstevel@tonic-gate 9960Sstevel@tonic-gate /* 9970Sstevel@tonic-gate * can't create directories. use pcfs_mkdir. 9980Sstevel@tonic-gate * can't create anything other than files. 9990Sstevel@tonic-gate */ 10000Sstevel@tonic-gate if (vap->va_type == VDIR) 10010Sstevel@tonic-gate return (EISDIR); 10020Sstevel@tonic-gate else if (vap->va_type != VREG) 10030Sstevel@tonic-gate return (EINVAL); 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate pcp = NULL; 10060Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 10070Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 10080Sstevel@tonic-gate if (error) 10090Sstevel@tonic-gate return (error); 1010*2972Sfrankho if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) { 10110Sstevel@tonic-gate pc_unlockfs(fsp); 10120Sstevel@tonic-gate return (EIO); 10130Sstevel@tonic-gate } 10140Sstevel@tonic-gate 10150Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 10160Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 10170Sstevel@tonic-gate pc_unlockfs(fsp); 10180Sstevel@tonic-gate return (EACCES); 10190Sstevel@tonic-gate } 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate if (*nm == '\0') { 10230Sstevel@tonic-gate /* 10240Sstevel@tonic-gate * Null component name refers to the directory itself. 10250Sstevel@tonic-gate */ 10260Sstevel@tonic-gate VN_HOLD(dvp); 10270Sstevel@tonic-gate pcp = VTOPC(dvp); 10280Sstevel@tonic-gate error = EEXIST; 10290Sstevel@tonic-gate } else { 10300Sstevel@tonic-gate error = pc_direnter(VTOPC(dvp), nm, vap, &pcp); 10310Sstevel@tonic-gate } 10320Sstevel@tonic-gate /* 10330Sstevel@tonic-gate * if file exists and this is a nonexclusive create, 10340Sstevel@tonic-gate * check for access permissions 10350Sstevel@tonic-gate */ 10360Sstevel@tonic-gate if (error == EEXIST) { 10370Sstevel@tonic-gate vp = PCTOV(pcp); 10380Sstevel@tonic-gate if (exclusive == NONEXCL) { 10390Sstevel@tonic-gate if (vp->v_type == VDIR) { 10400Sstevel@tonic-gate error = EISDIR; 10410Sstevel@tonic-gate } else if (mode) { 10420Sstevel@tonic-gate error = pcfs_access(PCTOV(pcp), mode, 0, 10430Sstevel@tonic-gate cr); 10440Sstevel@tonic-gate } else { 10450Sstevel@tonic-gate error = 0; 10460Sstevel@tonic-gate } 10470Sstevel@tonic-gate } 10480Sstevel@tonic-gate if (error) { 10490Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 10500Sstevel@tonic-gate } else if ((vp->v_type == VREG) && (vap->va_mask & AT_SIZE) && 10510Sstevel@tonic-gate (vap->va_size == 0)) { 10520Sstevel@tonic-gate error = pc_truncate(pcp, 0L); 10530Sstevel@tonic-gate if (error) 10540Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 10550Sstevel@tonic-gate } 10560Sstevel@tonic-gate } 10570Sstevel@tonic-gate if (error) { 10580Sstevel@tonic-gate pc_unlockfs(fsp); 10590Sstevel@tonic-gate return (error); 10600Sstevel@tonic-gate } 10610Sstevel@tonic-gate *vpp = PCTOV(pcp); 10620Sstevel@tonic-gate pcp->pc_flags |= PC_EXTERNAL; 10630Sstevel@tonic-gate pc_unlockfs(fsp); 10640Sstevel@tonic-gate return (error); 10650Sstevel@tonic-gate } 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate /*ARGSUSED*/ 10680Sstevel@tonic-gate static int 10690Sstevel@tonic-gate pcfs_remove( 10700Sstevel@tonic-gate struct vnode *vp, 10710Sstevel@tonic-gate char *nm, 10720Sstevel@tonic-gate struct cred *cr) 10730Sstevel@tonic-gate { 10740Sstevel@tonic-gate struct pcfs *fsp; 10750Sstevel@tonic-gate struct pcnode *pcp; 10760Sstevel@tonic-gate int error; 10770Sstevel@tonic-gate 10780Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 10790Sstevel@tonic-gate if (error = pc_verify(fsp)) 10800Sstevel@tonic-gate return (error); 10810Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 10820Sstevel@tonic-gate if (error) 10830Sstevel@tonic-gate return (error); 1084*2972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 10850Sstevel@tonic-gate pc_unlockfs(fsp); 10860Sstevel@tonic-gate return (EIO); 10870Sstevel@tonic-gate } 10880Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 10890Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 10900Sstevel@tonic-gate pc_unlockfs(fsp); 10910Sstevel@tonic-gate return (EACCES); 10920Sstevel@tonic-gate } 10930Sstevel@tonic-gate } 10940Sstevel@tonic-gate error = pc_dirremove(pcp, nm, (struct vnode *)0, VREG); 10950Sstevel@tonic-gate pc_unlockfs(fsp); 10960Sstevel@tonic-gate return (error); 10970Sstevel@tonic-gate } 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate /* 11000Sstevel@tonic-gate * Rename a file or directory 11010Sstevel@tonic-gate * This rename is restricted to only rename files within a directory. 11020Sstevel@tonic-gate * XX should make rename more general 11030Sstevel@tonic-gate */ 11040Sstevel@tonic-gate /*ARGSUSED*/ 11050Sstevel@tonic-gate static int 11060Sstevel@tonic-gate pcfs_rename( 11070Sstevel@tonic-gate struct vnode *sdvp, /* old (source) parent vnode */ 11080Sstevel@tonic-gate char *snm, /* old (source) entry name */ 11090Sstevel@tonic-gate struct vnode *tdvp, /* new (target) parent vnode */ 11100Sstevel@tonic-gate char *tnm, /* new (target) entry name */ 11110Sstevel@tonic-gate struct cred *cr) 11120Sstevel@tonic-gate { 11130Sstevel@tonic-gate struct pcfs *fsp; 11140Sstevel@tonic-gate struct pcnode *dp; /* parent pcnode */ 11150Sstevel@tonic-gate struct pcnode *tdp; 11160Sstevel@tonic-gate int error; 11170Sstevel@tonic-gate 11180Sstevel@tonic-gate fsp = VFSTOPCFS(sdvp->v_vfsp); 11190Sstevel@tonic-gate if (error = pc_verify(fsp)) 11200Sstevel@tonic-gate return (error); 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate /* 11230Sstevel@tonic-gate * make sure we can muck with this directory. 11240Sstevel@tonic-gate */ 11250Sstevel@tonic-gate error = pcfs_access(sdvp, VWRITE, 0, cr); 11260Sstevel@tonic-gate if (error) { 11270Sstevel@tonic-gate return (error); 11280Sstevel@tonic-gate } 11290Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 11300Sstevel@tonic-gate if (error) 11310Sstevel@tonic-gate return (error); 1132*2972Sfrankho if (((dp = VTOPC(sdvp)) == NULL) || ((tdp = VTOPC(tdvp)) == NULL) || 1133*2972Sfrankho (dp->pc_flags & PC_INVAL) || (tdp->pc_flags & PC_INVAL)) { 11340Sstevel@tonic-gate pc_unlockfs(fsp); 11350Sstevel@tonic-gate return (EIO); 11360Sstevel@tonic-gate } 11370Sstevel@tonic-gate error = pc_rename(dp, tdp, snm, tnm); 11380Sstevel@tonic-gate pc_unlockfs(fsp); 11390Sstevel@tonic-gate return (error); 11400Sstevel@tonic-gate } 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate /*ARGSUSED*/ 11430Sstevel@tonic-gate static int 11440Sstevel@tonic-gate pcfs_mkdir( 11450Sstevel@tonic-gate struct vnode *dvp, 11460Sstevel@tonic-gate char *nm, 11470Sstevel@tonic-gate struct vattr *vap, 11480Sstevel@tonic-gate struct vnode **vpp, 11490Sstevel@tonic-gate struct cred *cr) 11500Sstevel@tonic-gate { 11510Sstevel@tonic-gate struct pcfs *fsp; 11520Sstevel@tonic-gate struct pcnode *pcp; 11530Sstevel@tonic-gate int error; 11540Sstevel@tonic-gate 11550Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 11560Sstevel@tonic-gate if (error = pc_verify(fsp)) 11570Sstevel@tonic-gate return (error); 11580Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 11590Sstevel@tonic-gate if (error) 11600Sstevel@tonic-gate return (error); 1161*2972Sfrankho if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) { 11620Sstevel@tonic-gate pc_unlockfs(fsp); 11630Sstevel@tonic-gate return (EIO); 11640Sstevel@tonic-gate } 11650Sstevel@tonic-gate 11660Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 11670Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 11680Sstevel@tonic-gate pc_unlockfs(fsp); 11690Sstevel@tonic-gate return (EACCES); 11700Sstevel@tonic-gate } 11710Sstevel@tonic-gate } 11720Sstevel@tonic-gate 11730Sstevel@tonic-gate error = pc_direnter(VTOPC(dvp), nm, vap, &pcp); 11740Sstevel@tonic-gate 11750Sstevel@tonic-gate if (!error) { 11760Sstevel@tonic-gate pcp -> pc_flags |= PC_EXTERNAL; 11770Sstevel@tonic-gate *vpp = PCTOV(pcp); 11780Sstevel@tonic-gate } else if (error == EEXIST) { 11790Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 11800Sstevel@tonic-gate } 11810Sstevel@tonic-gate pc_unlockfs(fsp); 11820Sstevel@tonic-gate return (error); 11830Sstevel@tonic-gate } 11840Sstevel@tonic-gate 11850Sstevel@tonic-gate /*ARGSUSED*/ 11860Sstevel@tonic-gate static int 11870Sstevel@tonic-gate pcfs_rmdir( 11880Sstevel@tonic-gate struct vnode *dvp, 11890Sstevel@tonic-gate char *nm, 11900Sstevel@tonic-gate struct vnode *cdir, 11910Sstevel@tonic-gate struct cred *cr) 11920Sstevel@tonic-gate { 11930Sstevel@tonic-gate struct pcfs *fsp; 11940Sstevel@tonic-gate struct pcnode *pcp; 11950Sstevel@tonic-gate int error; 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate fsp = VFSTOPCFS(dvp -> v_vfsp); 11980Sstevel@tonic-gate if (error = pc_verify(fsp)) 11990Sstevel@tonic-gate return (error); 12000Sstevel@tonic-gate if (error = pc_lockfs(fsp, 0, 0)) 12010Sstevel@tonic-gate return (error); 12020Sstevel@tonic-gate 1203*2972Sfrankho if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) { 12040Sstevel@tonic-gate pc_unlockfs(fsp); 12050Sstevel@tonic-gate return (EIO); 12060Sstevel@tonic-gate } 12070Sstevel@tonic-gate 12080Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 12090Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 12100Sstevel@tonic-gate pc_unlockfs(fsp); 12110Sstevel@tonic-gate return (EACCES); 12120Sstevel@tonic-gate } 12130Sstevel@tonic-gate } 12140Sstevel@tonic-gate 12150Sstevel@tonic-gate error = pc_dirremove(pcp, nm, cdir, VDIR); 12160Sstevel@tonic-gate pc_unlockfs(fsp); 12170Sstevel@tonic-gate return (error); 12180Sstevel@tonic-gate } 12190Sstevel@tonic-gate 12200Sstevel@tonic-gate /* 12210Sstevel@tonic-gate * read entries in a directory. 12220Sstevel@tonic-gate * we must convert pc format to unix format 12230Sstevel@tonic-gate */ 12240Sstevel@tonic-gate 12250Sstevel@tonic-gate /*ARGSUSED*/ 12260Sstevel@tonic-gate static int 12270Sstevel@tonic-gate pcfs_readdir( 12280Sstevel@tonic-gate struct vnode *dvp, 12290Sstevel@tonic-gate struct uio *uiop, 12300Sstevel@tonic-gate struct cred *cr, 12310Sstevel@tonic-gate int *eofp) 12320Sstevel@tonic-gate { 12330Sstevel@tonic-gate struct pcnode *pcp; 12340Sstevel@tonic-gate struct pcfs *fsp; 12350Sstevel@tonic-gate struct pcdir *ep; 12360Sstevel@tonic-gate struct buf *bp = NULL; 12370Sstevel@tonic-gate offset_t offset; 12380Sstevel@tonic-gate int boff; 12390Sstevel@tonic-gate struct pc_dirent lbp; 12400Sstevel@tonic-gate struct pc_dirent *ld = &lbp; 12410Sstevel@tonic-gate int error; 12420Sstevel@tonic-gate 12432720Sfrankho /* 12442720Sfrankho * If the filesystem was umounted by force, return immediately. 12452720Sfrankho */ 12462720Sfrankho if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 12472720Sfrankho return (EIO); 12482720Sfrankho 12490Sstevel@tonic-gate if ((uiop->uio_iovcnt != 1) || 12500Sstevel@tonic-gate (uiop->uio_loffset % sizeof (struct pcdir)) != 0) { 12510Sstevel@tonic-gate return (EINVAL); 12520Sstevel@tonic-gate } 12530Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 12540Sstevel@tonic-gate /* 12550Sstevel@tonic-gate * verify that the dp is still valid on the disk 12560Sstevel@tonic-gate */ 12570Sstevel@tonic-gate if (error = pc_verify(fsp)) { 12580Sstevel@tonic-gate return (error); 12590Sstevel@tonic-gate } 12600Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 12610Sstevel@tonic-gate if (error) 12620Sstevel@tonic-gate return (error); 1263*2972Sfrankho if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) { 12640Sstevel@tonic-gate pc_unlockfs(fsp); 12650Sstevel@tonic-gate return (EIO); 12660Sstevel@tonic-gate } 12670Sstevel@tonic-gate 12680Sstevel@tonic-gate bzero(ld, sizeof (*ld)); 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate if (eofp != NULL) 12710Sstevel@tonic-gate *eofp = 0; 12720Sstevel@tonic-gate offset = uiop->uio_loffset; 12730Sstevel@tonic-gate 12740Sstevel@tonic-gate if (dvp->v_flag & VROOT) { 12750Sstevel@tonic-gate /* 12760Sstevel@tonic-gate * kludge up entries for "." and ".." in the root. 12770Sstevel@tonic-gate */ 12780Sstevel@tonic-gate if (offset == 0) { 12790Sstevel@tonic-gate (void) strcpy(ld->d_name, "."); 12800Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(1); 12810Sstevel@tonic-gate ld->d_off = (off64_t)sizeof (struct pcdir); 12820Sstevel@tonic-gate ld->d_ino = (ino64_t)UINT_MAX; 12830Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 12840Sstevel@tonic-gate pc_unlockfs(fsp); 12850Sstevel@tonic-gate return (ENOSPC); 12860Sstevel@tonic-gate } 12870Sstevel@tonic-gate (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop); 12880Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 12890Sstevel@tonic-gate offset = uiop->uio_loffset; 12900Sstevel@tonic-gate } 12910Sstevel@tonic-gate if (offset == sizeof (struct pcdir)) { 12920Sstevel@tonic-gate (void) strcpy(ld->d_name, ".."); 12930Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(2); 12940Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 12950Sstevel@tonic-gate pc_unlockfs(fsp); 12960Sstevel@tonic-gate return (ENOSPC); 12970Sstevel@tonic-gate } 12980Sstevel@tonic-gate ld->d_off = (off64_t)(uiop->uio_loffset + 12990Sstevel@tonic-gate sizeof (struct pcdir)); 13000Sstevel@tonic-gate ld->d_ino = (ino64_t)UINT_MAX; 13010Sstevel@tonic-gate (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop); 13020Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 13030Sstevel@tonic-gate offset = uiop->uio_loffset; 13040Sstevel@tonic-gate } 13050Sstevel@tonic-gate offset -= 2 * sizeof (struct pcdir); 13060Sstevel@tonic-gate /* offset now has the real offset value into directory file */ 13070Sstevel@tonic-gate } 13080Sstevel@tonic-gate 13090Sstevel@tonic-gate for (;;) { 13100Sstevel@tonic-gate boff = pc_blkoff(fsp, offset); 13110Sstevel@tonic-gate if (boff == 0 || bp == NULL || boff >= bp->b_bcount) { 13120Sstevel@tonic-gate if (bp != NULL) { 13130Sstevel@tonic-gate brelse(bp); 13140Sstevel@tonic-gate bp = NULL; 13150Sstevel@tonic-gate } 13160Sstevel@tonic-gate error = pc_blkatoff(pcp, offset, &bp, &ep); 13170Sstevel@tonic-gate if (error) { 13180Sstevel@tonic-gate if (error == ENOENT) { 13190Sstevel@tonic-gate error = 0; 13200Sstevel@tonic-gate if (eofp) 13210Sstevel@tonic-gate *eofp = 1; 13220Sstevel@tonic-gate } 13230Sstevel@tonic-gate break; 13240Sstevel@tonic-gate } 13250Sstevel@tonic-gate } 13260Sstevel@tonic-gate if (ep->pcd_filename[0] == PCD_UNUSED) { 13270Sstevel@tonic-gate if (eofp) 13280Sstevel@tonic-gate *eofp = 1; 13290Sstevel@tonic-gate break; 13300Sstevel@tonic-gate } 13310Sstevel@tonic-gate /* 13320Sstevel@tonic-gate * Don't display label because it may contain funny characters. 13330Sstevel@tonic-gate */ 13340Sstevel@tonic-gate if (ep->pcd_filename[0] == PCD_ERASED) { 13350Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir); 13360Sstevel@tonic-gate offset += sizeof (struct pcdir); 13370Sstevel@tonic-gate ep++; 13380Sstevel@tonic-gate continue; 13390Sstevel@tonic-gate } 13400Sstevel@tonic-gate if (PCDL_IS_LFN(ep)) { 13410Sstevel@tonic-gate if (pc_read_long_fn(dvp, uiop, ld, &ep, &offset, &bp) != 13420Sstevel@tonic-gate 0) 13430Sstevel@tonic-gate break; 13440Sstevel@tonic-gate continue; 13450Sstevel@tonic-gate } 13460Sstevel@tonic-gate 13470Sstevel@tonic-gate if (pc_read_short_fn(dvp, uiop, ld, &ep, &offset, &bp) != 0) 13480Sstevel@tonic-gate break; 13490Sstevel@tonic-gate } 13500Sstevel@tonic-gate if (bp) 13510Sstevel@tonic-gate brelse(bp); 13520Sstevel@tonic-gate pc_unlockfs(fsp); 13530Sstevel@tonic-gate return (error); 13540Sstevel@tonic-gate } 13550Sstevel@tonic-gate 13560Sstevel@tonic-gate 13570Sstevel@tonic-gate /* 13580Sstevel@tonic-gate * Called from pvn_getpages or pcfs_getpage to get a particular page. 13590Sstevel@tonic-gate * When we are called the pcfs is already locked. 13600Sstevel@tonic-gate */ 13610Sstevel@tonic-gate /*ARGSUSED*/ 13620Sstevel@tonic-gate static int 13630Sstevel@tonic-gate pcfs_getapage( 13640Sstevel@tonic-gate struct vnode *vp, 13650Sstevel@tonic-gate u_offset_t off, 13660Sstevel@tonic-gate size_t len, 13670Sstevel@tonic-gate uint_t *protp, 13680Sstevel@tonic-gate page_t *pl[], /* NULL if async IO is requested */ 13690Sstevel@tonic-gate size_t plsz, 13700Sstevel@tonic-gate struct seg *seg, 13710Sstevel@tonic-gate caddr_t addr, 13720Sstevel@tonic-gate enum seg_rw rw, 13730Sstevel@tonic-gate struct cred *cr) 13740Sstevel@tonic-gate { 13750Sstevel@tonic-gate struct pcnode *pcp; 13760Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 13770Sstevel@tonic-gate struct vnode *devvp; 13780Sstevel@tonic-gate page_t *pp; 13790Sstevel@tonic-gate page_t *pagefound; 13800Sstevel@tonic-gate int err; 13810Sstevel@tonic-gate 13822720Sfrankho /* 13832720Sfrankho * If the filesystem was umounted by force, return immediately. 13842720Sfrankho */ 13852720Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 13862720Sfrankho return (EIO); 13872720Sfrankho 13880Sstevel@tonic-gate PC_DPRINTF3(5, "pcfs_getapage: vp=%p off=%lld len=%lu\n", 13890Sstevel@tonic-gate (void *)vp, off, len); 13900Sstevel@tonic-gate 1391*2972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) 13920Sstevel@tonic-gate return (EIO); 13930Sstevel@tonic-gate devvp = fsp->pcfs_devvp; 13940Sstevel@tonic-gate 13950Sstevel@tonic-gate /* pcfs doesn't do readaheads */ 13960Sstevel@tonic-gate if (pl == NULL) 13970Sstevel@tonic-gate return (0); 13980Sstevel@tonic-gate 13990Sstevel@tonic-gate pl[0] = NULL; 14000Sstevel@tonic-gate err = 0; 14010Sstevel@tonic-gate /* 14020Sstevel@tonic-gate * If the accessed time on the pcnode has not already been 14030Sstevel@tonic-gate * set elsewhere (e.g. for read/setattr) we set the time now. 14040Sstevel@tonic-gate * This gives us approximate modified times for mmap'ed files 14050Sstevel@tonic-gate * which are accessed via loads in the user address space. 14060Sstevel@tonic-gate */ 14070Sstevel@tonic-gate if ((pcp->pc_flags & PC_ACC) == 0 && 14080Sstevel@tonic-gate ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0)) { 14090Sstevel@tonic-gate pcp->pc_flags |= PC_ACC; 14100Sstevel@tonic-gate pc_mark_acc(pcp); 14110Sstevel@tonic-gate } 14120Sstevel@tonic-gate reread: 14130Sstevel@tonic-gate if ((pagefound = page_exists(vp, off)) == NULL) { 14140Sstevel@tonic-gate /* 14150Sstevel@tonic-gate * Need to really do disk IO to get the page(s). 14160Sstevel@tonic-gate */ 14170Sstevel@tonic-gate struct buf *bp; 14180Sstevel@tonic-gate daddr_t lbn, bn; 14190Sstevel@tonic-gate u_offset_t io_off; 14200Sstevel@tonic-gate size_t io_len; 14210Sstevel@tonic-gate u_offset_t lbnoff, xferoffset; 14220Sstevel@tonic-gate u_offset_t pgoff; 14230Sstevel@tonic-gate uint_t xfersize; 14240Sstevel@tonic-gate int err1; 14250Sstevel@tonic-gate 14260Sstevel@tonic-gate lbn = pc_lblkno(fsp, off); 14270Sstevel@tonic-gate lbnoff = off & ~(fsp->pcfs_clsize - 1); 14280Sstevel@tonic-gate xferoffset = off & ~(fsp->pcfs_secsize - 1); 14290Sstevel@tonic-gate 14300Sstevel@tonic-gate pp = pvn_read_kluster(vp, off, seg, addr, &io_off, &io_len, 14310Sstevel@tonic-gate off, (size_t)MIN(pc_blksize(fsp, pcp, off), PAGESIZE), 0); 14320Sstevel@tonic-gate if (pp == NULL) 14330Sstevel@tonic-gate /* 14340Sstevel@tonic-gate * XXX - If pcfs is made MT-hot, this should go 14350Sstevel@tonic-gate * back to reread. 14360Sstevel@tonic-gate */ 14370Sstevel@tonic-gate panic("pcfs_getapage pvn_read_kluster"); 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate for (pgoff = 0; pgoff < PAGESIZE && xferoffset < pcp->pc_size; 14400Sstevel@tonic-gate pgoff += xfersize, 14410Sstevel@tonic-gate lbn += howmany(xfersize, fsp->pcfs_clsize), 14420Sstevel@tonic-gate lbnoff += xfersize, xferoffset += xfersize) { 14430Sstevel@tonic-gate /* 14440Sstevel@tonic-gate * read as many contiguous blocks as possible to 14450Sstevel@tonic-gate * fill this page 14460Sstevel@tonic-gate */ 14470Sstevel@tonic-gate xfersize = PAGESIZE - pgoff; 14480Sstevel@tonic-gate err1 = pc_bmap(pcp, lbn, &bn, &xfersize); 14490Sstevel@tonic-gate if (err1) { 14500Sstevel@tonic-gate PC_DPRINTF1(1, "pc_getapage err=%d", err1); 14510Sstevel@tonic-gate err = err1; 14520Sstevel@tonic-gate goto out; 14530Sstevel@tonic-gate } 14540Sstevel@tonic-gate bp = pageio_setup(pp, xfersize, devvp, B_READ); 14550Sstevel@tonic-gate bp->b_edev = devvp->v_rdev; 14560Sstevel@tonic-gate bp->b_dev = cmpdev(devvp->v_rdev); 14570Sstevel@tonic-gate bp->b_blkno = bn + 14580Sstevel@tonic-gate /* add a sector offset within the cluster */ 14590Sstevel@tonic-gate /* when the clustersize > PAGESIZE */ 14600Sstevel@tonic-gate (xferoffset - lbnoff) / fsp->pcfs_secsize; 1461973Selowe bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff; 14620Sstevel@tonic-gate bp->b_file = vp; 14630Sstevel@tonic-gate bp->b_offset = (offset_t)(off + pgoff); 14640Sstevel@tonic-gate 14650Sstevel@tonic-gate (void) bdev_strategy(bp); 14660Sstevel@tonic-gate 14670Sstevel@tonic-gate lwp_stat_update(LWP_STAT_INBLK, 1); 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate if (err == 0) 14700Sstevel@tonic-gate err = biowait(bp); 14710Sstevel@tonic-gate else 14720Sstevel@tonic-gate (void) biowait(bp); 14730Sstevel@tonic-gate pageio_done(bp); 14740Sstevel@tonic-gate if (err) 14750Sstevel@tonic-gate goto out; 14760Sstevel@tonic-gate } 14770Sstevel@tonic-gate if (pgoff < PAGESIZE) { 14780Sstevel@tonic-gate pagezero(pp->p_prev, pgoff, PAGESIZE - pgoff); 14790Sstevel@tonic-gate } 14800Sstevel@tonic-gate pvn_plist_init(pp, pl, plsz, off, io_len, rw); 14810Sstevel@tonic-gate } 14820Sstevel@tonic-gate out: 14830Sstevel@tonic-gate if (err) { 14840Sstevel@tonic-gate if (pp != NULL) 14850Sstevel@tonic-gate pvn_read_done(pp, B_ERROR); 14860Sstevel@tonic-gate return (err); 14870Sstevel@tonic-gate } 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate if (pagefound) { 14900Sstevel@tonic-gate /* 14910Sstevel@tonic-gate * Page exists in the cache, acquire the "shared" 14920Sstevel@tonic-gate * lock. If this fails, go back to reread. 14930Sstevel@tonic-gate */ 14940Sstevel@tonic-gate if ((pp = page_lookup(vp, off, SE_SHARED)) == NULL) { 14950Sstevel@tonic-gate goto reread; 14960Sstevel@tonic-gate } 14970Sstevel@tonic-gate pl[0] = pp; 14980Sstevel@tonic-gate pl[1] = NULL; 14990Sstevel@tonic-gate } 15000Sstevel@tonic-gate return (err); 15010Sstevel@tonic-gate } 15020Sstevel@tonic-gate 15030Sstevel@tonic-gate /* 15040Sstevel@tonic-gate * Return all the pages from [off..off+len] in given file 15050Sstevel@tonic-gate */ 15060Sstevel@tonic-gate static int 15070Sstevel@tonic-gate pcfs_getpage( 15080Sstevel@tonic-gate struct vnode *vp, 15090Sstevel@tonic-gate offset_t off, 15100Sstevel@tonic-gate size_t len, 15110Sstevel@tonic-gate uint_t *protp, 15120Sstevel@tonic-gate page_t *pl[], 15130Sstevel@tonic-gate size_t plsz, 15140Sstevel@tonic-gate struct seg *seg, 15150Sstevel@tonic-gate caddr_t addr, 15160Sstevel@tonic-gate enum seg_rw rw, 15170Sstevel@tonic-gate struct cred *cr) 15180Sstevel@tonic-gate { 15190Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 15200Sstevel@tonic-gate int err; 15210Sstevel@tonic-gate 15220Sstevel@tonic-gate PC_DPRINTF0(6, "pcfs_getpage\n"); 15230Sstevel@tonic-gate if (err = pc_verify(fsp)) 15240Sstevel@tonic-gate return (err); 15250Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 15260Sstevel@tonic-gate return (ENOSYS); 15270Sstevel@tonic-gate ASSERT(off <= UINT32_MAX); 15280Sstevel@tonic-gate err = pc_lockfs(fsp, 0, 0); 15290Sstevel@tonic-gate if (err) 15300Sstevel@tonic-gate return (err); 15310Sstevel@tonic-gate if (protp != NULL) 15320Sstevel@tonic-gate *protp = PROT_ALL; 15330Sstevel@tonic-gate 15340Sstevel@tonic-gate ASSERT((off & PAGEOFFSET) == 0); 15350Sstevel@tonic-gate if (len <= PAGESIZE) { 15360Sstevel@tonic-gate err = pcfs_getapage(vp, off, len, protp, pl, 15370Sstevel@tonic-gate plsz, seg, addr, rw, cr); 15380Sstevel@tonic-gate } else { 15390Sstevel@tonic-gate err = pvn_getpages(pcfs_getapage, vp, off, 15400Sstevel@tonic-gate len, protp, pl, plsz, seg, addr, rw, cr); 15410Sstevel@tonic-gate } 15420Sstevel@tonic-gate pc_unlockfs(fsp); 15430Sstevel@tonic-gate return (err); 15440Sstevel@tonic-gate } 15450Sstevel@tonic-gate 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate /* 15480Sstevel@tonic-gate * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE} 15490Sstevel@tonic-gate * If len == 0, do from off to EOF. 15500Sstevel@tonic-gate * 15510Sstevel@tonic-gate * The normal cases should be len == 0 & off == 0 (entire vp list), 15520Sstevel@tonic-gate * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE 15530Sstevel@tonic-gate * (from pageout). 15540Sstevel@tonic-gate * 15550Sstevel@tonic-gate */ 15560Sstevel@tonic-gate /*ARGSUSED*/ 15570Sstevel@tonic-gate static int 15580Sstevel@tonic-gate pcfs_putpage( 15590Sstevel@tonic-gate struct vnode *vp, 15600Sstevel@tonic-gate offset_t off, 15610Sstevel@tonic-gate size_t len, 15620Sstevel@tonic-gate int flags, 15630Sstevel@tonic-gate struct cred *cr) 15640Sstevel@tonic-gate { 15650Sstevel@tonic-gate struct pcnode *pcp; 15660Sstevel@tonic-gate page_t *pp; 15670Sstevel@tonic-gate struct pcfs *fsp; 15680Sstevel@tonic-gate u_offset_t io_off; 15690Sstevel@tonic-gate size_t io_len; 15700Sstevel@tonic-gate offset_t eoff; 15710Sstevel@tonic-gate int err; 15720Sstevel@tonic-gate 15732720Sfrankho /* 15742720Sfrankho * If the filesystem was umounted by force, return immediately. 15752720Sfrankho */ 15762720Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 15772720Sfrankho return (EIO); 15782720Sfrankho 15790Sstevel@tonic-gate PC_DPRINTF1(6, "pcfs_putpage vp=0x%p\n", (void *)vp); 15800Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 15810Sstevel@tonic-gate return (ENOSYS); 15820Sstevel@tonic-gate 15830Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 15840Sstevel@tonic-gate 15850Sstevel@tonic-gate if (err = pc_verify(fsp)) 15860Sstevel@tonic-gate return (err); 15870Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) { 15880Sstevel@tonic-gate PC_DPRINTF1(3, "pcfs_putpage NULL vp=0x%p\n", (void *)vp); 15890Sstevel@tonic-gate return (EIO); 15900Sstevel@tonic-gate } 1591*2972Sfrankho if (pcp->pc_flags & PC_INVAL) 1592*2972Sfrankho return (EIO); 15930Sstevel@tonic-gate 15940Sstevel@tonic-gate if (curproc == proc_pageout) { 15950Sstevel@tonic-gate /* 15960Sstevel@tonic-gate * XXX - This is a quick hack to avoid blocking 15970Sstevel@tonic-gate * pageout. Also to avoid pcfs_getapage deadlocking 15980Sstevel@tonic-gate * with putpage when memory is running out, 15990Sstevel@tonic-gate * since we only have one global lock and we don't 16000Sstevel@tonic-gate * support async putpage. 16010Sstevel@tonic-gate * It should be fixed someday. 16020Sstevel@tonic-gate * 16030Sstevel@tonic-gate * Interestingly, this used to be a test of NOMEMWAIT(). 16040Sstevel@tonic-gate * We only ever got here once pcfs started supporting 16050Sstevel@tonic-gate * NFS sharing, and then only because the NFS server 16060Sstevel@tonic-gate * threads seem to do writes in sched's process context. 16070Sstevel@tonic-gate * Since everyone else seems to just care about pageout, 16080Sstevel@tonic-gate * the test was changed to look for pageout directly. 16090Sstevel@tonic-gate */ 16100Sstevel@tonic-gate return (ENOMEM); 16110Sstevel@tonic-gate } 16120Sstevel@tonic-gate 16130Sstevel@tonic-gate ASSERT(off <= UINT32_MAX); 16140Sstevel@tonic-gate 16150Sstevel@tonic-gate flags &= ~B_ASYNC; /* XXX should fix this later */ 16160Sstevel@tonic-gate 16170Sstevel@tonic-gate err = pc_lockfs(fsp, 0, 0); 16180Sstevel@tonic-gate if (err) 16190Sstevel@tonic-gate return (err); 16200Sstevel@tonic-gate if (!vn_has_cached_data(vp) || off >= pcp->pc_size) { 16210Sstevel@tonic-gate pc_unlockfs(fsp); 16220Sstevel@tonic-gate return (0); 16230Sstevel@tonic-gate } 16240Sstevel@tonic-gate 16250Sstevel@tonic-gate if (len == 0) { 16260Sstevel@tonic-gate /* 16270Sstevel@tonic-gate * Search the entire vp list for pages >= off 16280Sstevel@tonic-gate */ 16290Sstevel@tonic-gate err = pvn_vplist_dirty(vp, off, 16300Sstevel@tonic-gate pcfs_putapage, flags, cr); 16310Sstevel@tonic-gate } else { 16320Sstevel@tonic-gate eoff = off + len; 16330Sstevel@tonic-gate 16340Sstevel@tonic-gate for (io_off = off; io_off < eoff && 16350Sstevel@tonic-gate io_off < pcp->pc_size; io_off += io_len) { 16360Sstevel@tonic-gate /* 16370Sstevel@tonic-gate * If we are not invalidating, synchronously 16380Sstevel@tonic-gate * freeing or writing pages use the routine 16390Sstevel@tonic-gate * page_lookup_nowait() to prevent reclaiming 16400Sstevel@tonic-gate * them from the free list. 16410Sstevel@tonic-gate */ 16420Sstevel@tonic-gate if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) { 16430Sstevel@tonic-gate pp = page_lookup(vp, io_off, 16440Sstevel@tonic-gate (flags & (B_INVAL | B_FREE)) ? 16450Sstevel@tonic-gate SE_EXCL : SE_SHARED); 16460Sstevel@tonic-gate } else { 16470Sstevel@tonic-gate pp = page_lookup_nowait(vp, io_off, 16480Sstevel@tonic-gate (flags & B_FREE) ? SE_EXCL : SE_SHARED); 16490Sstevel@tonic-gate } 16500Sstevel@tonic-gate 16510Sstevel@tonic-gate if (pp == NULL || pvn_getdirty(pp, flags) == 0) 16520Sstevel@tonic-gate io_len = PAGESIZE; 16530Sstevel@tonic-gate else { 16540Sstevel@tonic-gate err = pcfs_putapage(vp, pp, &io_off, &io_len, 16550Sstevel@tonic-gate flags, cr); 16560Sstevel@tonic-gate if (err != 0) 16570Sstevel@tonic-gate break; 16580Sstevel@tonic-gate /* 16590Sstevel@tonic-gate * "io_off" and "io_len" are returned as 16600Sstevel@tonic-gate * the range of pages we actually wrote. 16610Sstevel@tonic-gate * This allows us to skip ahead more quickly 16620Sstevel@tonic-gate * since several pages may've been dealt 16630Sstevel@tonic-gate * with by this iteration of the loop. 16640Sstevel@tonic-gate */ 16650Sstevel@tonic-gate } 16660Sstevel@tonic-gate } 16670Sstevel@tonic-gate } 16680Sstevel@tonic-gate if (err == 0 && (flags & B_INVAL) && 16690Sstevel@tonic-gate off == 0 && len == 0 && vn_has_cached_data(vp)) { 16700Sstevel@tonic-gate /* 16710Sstevel@tonic-gate * If doing "invalidation", make sure that 16720Sstevel@tonic-gate * all pages on the vnode list are actually 16730Sstevel@tonic-gate * gone. 16740Sstevel@tonic-gate */ 16750Sstevel@tonic-gate cmn_err(CE_PANIC, 16760Sstevel@tonic-gate "pcfs_putpage: B_INVAL, pages not gone"); 16770Sstevel@tonic-gate } else if (err) { 16780Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_putpage err=%d\n", err); 16790Sstevel@tonic-gate } 16800Sstevel@tonic-gate pc_unlockfs(fsp); 16810Sstevel@tonic-gate return (err); 16820Sstevel@tonic-gate } 16830Sstevel@tonic-gate 16840Sstevel@tonic-gate /* 16850Sstevel@tonic-gate * Write out a single page, possibly klustering adjacent dirty pages. 16860Sstevel@tonic-gate */ 16870Sstevel@tonic-gate /*ARGSUSED*/ 16880Sstevel@tonic-gate int 16890Sstevel@tonic-gate pcfs_putapage( 16900Sstevel@tonic-gate struct vnode *vp, 16910Sstevel@tonic-gate page_t *pp, 16920Sstevel@tonic-gate u_offset_t *offp, 16930Sstevel@tonic-gate size_t *lenp, 16940Sstevel@tonic-gate int flags, 16950Sstevel@tonic-gate struct cred *cr) 16960Sstevel@tonic-gate { 16970Sstevel@tonic-gate struct pcnode *pcp; 16980Sstevel@tonic-gate struct pcfs *fsp; 16990Sstevel@tonic-gate struct vnode *devvp; 17000Sstevel@tonic-gate size_t io_len; 17010Sstevel@tonic-gate daddr_t bn; 17020Sstevel@tonic-gate u_offset_t lbn, lbnoff, xferoffset; 17030Sstevel@tonic-gate uint_t pgoff, xfersize; 17040Sstevel@tonic-gate int err = 0; 17050Sstevel@tonic-gate u_offset_t io_off; 17060Sstevel@tonic-gate 17070Sstevel@tonic-gate pcp = VTOPC(vp); 17080Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 17090Sstevel@tonic-gate devvp = fsp->pcfs_devvp; 17100Sstevel@tonic-gate 17110Sstevel@tonic-gate /* 17120Sstevel@tonic-gate * If the modified time on the inode has not already been 17130Sstevel@tonic-gate * set elsewhere (e.g. for write/setattr) and this is not 17140Sstevel@tonic-gate * a call from msync (B_FORCE) we set the time now. 17150Sstevel@tonic-gate * This gives us approximate modified times for mmap'ed files 17160Sstevel@tonic-gate * which are modified via stores in the user address space. 17170Sstevel@tonic-gate */ 17180Sstevel@tonic-gate if ((pcp->pc_flags & PC_MOD) == 0 || (flags & B_FORCE)) { 17190Sstevel@tonic-gate pcp->pc_flags |= PC_MOD; 17200Sstevel@tonic-gate pc_mark_mod(pcp); 17210Sstevel@tonic-gate } 17220Sstevel@tonic-gate pp = pvn_write_kluster(vp, pp, &io_off, &io_len, pp->p_offset, 17230Sstevel@tonic-gate PAGESIZE, flags); 17240Sstevel@tonic-gate 17250Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_IRRECOV) { 17260Sstevel@tonic-gate goto out; 17270Sstevel@tonic-gate } 17280Sstevel@tonic-gate 17290Sstevel@tonic-gate PC_DPRINTF1(7, "pc_putpage writing dirty page off=%llu\n", io_off); 17300Sstevel@tonic-gate 17310Sstevel@tonic-gate lbn = pc_lblkno(fsp, io_off); 17320Sstevel@tonic-gate lbnoff = io_off & ~(fsp->pcfs_clsize - 1); 17330Sstevel@tonic-gate xferoffset = io_off & ~(fsp->pcfs_secsize - 1); 17340Sstevel@tonic-gate 17350Sstevel@tonic-gate for (pgoff = 0; pgoff < io_len && xferoffset < pcp->pc_size; 17360Sstevel@tonic-gate pgoff += xfersize, 17370Sstevel@tonic-gate lbn += howmany(xfersize, fsp->pcfs_clsize), 17380Sstevel@tonic-gate lbnoff += xfersize, xferoffset += xfersize) { 17390Sstevel@tonic-gate 17400Sstevel@tonic-gate struct buf *bp; 17410Sstevel@tonic-gate int err1; 17420Sstevel@tonic-gate 17430Sstevel@tonic-gate /* 17440Sstevel@tonic-gate * write as many contiguous blocks as possible from this page 17450Sstevel@tonic-gate */ 17460Sstevel@tonic-gate xfersize = io_len - pgoff; 17470Sstevel@tonic-gate err1 = pc_bmap(pcp, (daddr_t)lbn, &bn, &xfersize); 17480Sstevel@tonic-gate if (err1) { 17490Sstevel@tonic-gate err = err1; 17500Sstevel@tonic-gate goto out; 17510Sstevel@tonic-gate } 17520Sstevel@tonic-gate bp = pageio_setup(pp, xfersize, devvp, B_WRITE | flags); 17530Sstevel@tonic-gate bp->b_edev = devvp->v_rdev; 17540Sstevel@tonic-gate bp->b_dev = cmpdev(devvp->v_rdev); 17550Sstevel@tonic-gate bp->b_blkno = bn + 17560Sstevel@tonic-gate /* add a sector offset within the cluster */ 17570Sstevel@tonic-gate /* when the clustersize > PAGESIZE */ 17580Sstevel@tonic-gate (xferoffset - lbnoff) / fsp->pcfs_secsize; 17590Sstevel@tonic-gate bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff; 17600Sstevel@tonic-gate bp->b_file = vp; 17610Sstevel@tonic-gate bp->b_offset = (offset_t)(io_off + pgoff); 17620Sstevel@tonic-gate 17630Sstevel@tonic-gate (void) bdev_strategy(bp); 17640Sstevel@tonic-gate 17650Sstevel@tonic-gate lwp_stat_update(LWP_STAT_OUBLK, 1); 17660Sstevel@tonic-gate 17670Sstevel@tonic-gate if (err == 0) 17680Sstevel@tonic-gate err = biowait(bp); 17690Sstevel@tonic-gate else 17700Sstevel@tonic-gate (void) biowait(bp); 17710Sstevel@tonic-gate pageio_done(bp); 17720Sstevel@tonic-gate } 17730Sstevel@tonic-gate pvn_write_done(pp, ((err) ? B_ERROR : 0) | B_WRITE | flags); 17740Sstevel@tonic-gate pp = NULL; 17750Sstevel@tonic-gate 17760Sstevel@tonic-gate out: 17770Sstevel@tonic-gate if ((fsp->pcfs_flags & PCFS_IRRECOV) && pp != NULL) { 17780Sstevel@tonic-gate pvn_write_done(pp, B_WRITE | flags); 17790Sstevel@tonic-gate } else if (err != 0 && pp != NULL) { 17800Sstevel@tonic-gate pvn_write_done(pp, B_ERROR | B_WRITE | flags); 17810Sstevel@tonic-gate } 17820Sstevel@tonic-gate 17830Sstevel@tonic-gate if (offp) 17840Sstevel@tonic-gate *offp = io_off; 17850Sstevel@tonic-gate if (lenp) 17860Sstevel@tonic-gate *lenp = io_len; 17870Sstevel@tonic-gate PC_DPRINTF4(4, "pcfs_putapage: vp=%p pp=%p off=%lld len=%lu\n", 17880Sstevel@tonic-gate (void *)vp, (void *)pp, io_off, io_len); 17890Sstevel@tonic-gate if (err) { 17900Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_putapage err=%d", err); 17910Sstevel@tonic-gate } 17920Sstevel@tonic-gate return (err); 17930Sstevel@tonic-gate } 17940Sstevel@tonic-gate 17950Sstevel@tonic-gate /*ARGSUSED*/ 17960Sstevel@tonic-gate static int 17970Sstevel@tonic-gate pcfs_map( 17980Sstevel@tonic-gate struct vnode *vp, 17990Sstevel@tonic-gate offset_t off, 18000Sstevel@tonic-gate struct as *as, 18010Sstevel@tonic-gate caddr_t *addrp, 18020Sstevel@tonic-gate size_t len, 18030Sstevel@tonic-gate uchar_t prot, 18040Sstevel@tonic-gate uchar_t maxprot, 18050Sstevel@tonic-gate uint_t flags, 18060Sstevel@tonic-gate struct cred *cr) 18070Sstevel@tonic-gate { 18080Sstevel@tonic-gate struct segvn_crargs vn_a; 18090Sstevel@tonic-gate int error; 18100Sstevel@tonic-gate 18110Sstevel@tonic-gate PC_DPRINTF0(6, "pcfs_map\n"); 18120Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 18130Sstevel@tonic-gate return (ENOSYS); 18140Sstevel@tonic-gate 18150Sstevel@tonic-gate if (off > UINT32_MAX || off + len > UINT32_MAX) 18160Sstevel@tonic-gate return (ENXIO); 18170Sstevel@tonic-gate 18180Sstevel@tonic-gate as_rangelock(as); 18190Sstevel@tonic-gate if ((flags & MAP_FIXED) == 0) { 18200Sstevel@tonic-gate map_addr(addrp, len, off, 1, flags); 18210Sstevel@tonic-gate if (*addrp == NULL) { 18220Sstevel@tonic-gate as_rangeunlock(as); 18230Sstevel@tonic-gate return (ENOMEM); 18240Sstevel@tonic-gate } 18250Sstevel@tonic-gate } else { 18260Sstevel@tonic-gate /* 18270Sstevel@tonic-gate * User specified address - blow away any previous mappings 18280Sstevel@tonic-gate */ 18290Sstevel@tonic-gate (void) as_unmap(as, *addrp, len); 18300Sstevel@tonic-gate } 18310Sstevel@tonic-gate 18320Sstevel@tonic-gate vn_a.vp = vp; 18330Sstevel@tonic-gate vn_a.offset = off; 18340Sstevel@tonic-gate vn_a.type = flags & MAP_TYPE; 18350Sstevel@tonic-gate vn_a.prot = prot; 18360Sstevel@tonic-gate vn_a.maxprot = maxprot; 18370Sstevel@tonic-gate vn_a.flags = flags & ~MAP_TYPE; 18380Sstevel@tonic-gate vn_a.cred = cr; 18390Sstevel@tonic-gate vn_a.amp = NULL; 18400Sstevel@tonic-gate vn_a.szc = 0; 18410Sstevel@tonic-gate vn_a.lgrp_mem_policy_flags = 0; 18420Sstevel@tonic-gate 18430Sstevel@tonic-gate error = as_map(as, *addrp, len, segvn_create, &vn_a); 18440Sstevel@tonic-gate as_rangeunlock(as); 18450Sstevel@tonic-gate return (error); 18460Sstevel@tonic-gate } 18470Sstevel@tonic-gate 18480Sstevel@tonic-gate /* ARGSUSED */ 18490Sstevel@tonic-gate static int 18500Sstevel@tonic-gate pcfs_seek( 18510Sstevel@tonic-gate struct vnode *vp, 18520Sstevel@tonic-gate offset_t ooff, 18530Sstevel@tonic-gate offset_t *noffp) 18540Sstevel@tonic-gate { 18550Sstevel@tonic-gate if (*noffp < 0) 18560Sstevel@tonic-gate return (EINVAL); 18570Sstevel@tonic-gate else if (*noffp > MAXOFFSET_T) 18580Sstevel@tonic-gate return (EINVAL); 18590Sstevel@tonic-gate else 18600Sstevel@tonic-gate return (0); 18610Sstevel@tonic-gate } 18620Sstevel@tonic-gate 18630Sstevel@tonic-gate /* ARGSUSED */ 18640Sstevel@tonic-gate static int 18650Sstevel@tonic-gate pcfs_addmap( 18660Sstevel@tonic-gate struct vnode *vp, 18670Sstevel@tonic-gate offset_t off, 18680Sstevel@tonic-gate struct as *as, 18690Sstevel@tonic-gate caddr_t addr, 18700Sstevel@tonic-gate size_t len, 18710Sstevel@tonic-gate uchar_t prot, 18720Sstevel@tonic-gate uchar_t maxprot, 18730Sstevel@tonic-gate uint_t flags, 18740Sstevel@tonic-gate struct cred *cr) 18750Sstevel@tonic-gate { 18760Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 18770Sstevel@tonic-gate return (ENOSYS); 18780Sstevel@tonic-gate return (0); 18790Sstevel@tonic-gate } 18800Sstevel@tonic-gate 18810Sstevel@tonic-gate /*ARGSUSED*/ 18820Sstevel@tonic-gate static int 18830Sstevel@tonic-gate pcfs_delmap( 18840Sstevel@tonic-gate struct vnode *vp, 18850Sstevel@tonic-gate offset_t off, 18860Sstevel@tonic-gate struct as *as, 18870Sstevel@tonic-gate caddr_t addr, 18880Sstevel@tonic-gate size_t len, 18890Sstevel@tonic-gate uint_t prot, 18900Sstevel@tonic-gate uint_t maxprot, 18910Sstevel@tonic-gate uint_t flags, 18920Sstevel@tonic-gate struct cred *cr) 18930Sstevel@tonic-gate { 18940Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 18950Sstevel@tonic-gate return (ENOSYS); 18960Sstevel@tonic-gate return (0); 18970Sstevel@tonic-gate } 18980Sstevel@tonic-gate 18990Sstevel@tonic-gate /* 19000Sstevel@tonic-gate * POSIX pathconf() support. 19010Sstevel@tonic-gate */ 19020Sstevel@tonic-gate /* ARGSUSED */ 19030Sstevel@tonic-gate static int 19040Sstevel@tonic-gate pcfs_pathconf( 19050Sstevel@tonic-gate struct vnode *vp, 19060Sstevel@tonic-gate int cmd, 19070Sstevel@tonic-gate ulong_t *valp, 19080Sstevel@tonic-gate struct cred *cr) 19090Sstevel@tonic-gate { 19100Sstevel@tonic-gate ulong_t val; 19110Sstevel@tonic-gate int error = 0; 19120Sstevel@tonic-gate struct statvfs64 vfsbuf; 19130Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 19140Sstevel@tonic-gate 19150Sstevel@tonic-gate switch (cmd) { 19160Sstevel@tonic-gate 19170Sstevel@tonic-gate case _PC_LINK_MAX: 19180Sstevel@tonic-gate val = 1; 19190Sstevel@tonic-gate break; 19200Sstevel@tonic-gate 19210Sstevel@tonic-gate case _PC_MAX_CANON: 19220Sstevel@tonic-gate val = MAX_CANON; 19230Sstevel@tonic-gate break; 19240Sstevel@tonic-gate 19250Sstevel@tonic-gate case _PC_MAX_INPUT: 19260Sstevel@tonic-gate val = MAX_INPUT; 19270Sstevel@tonic-gate break; 19280Sstevel@tonic-gate 19290Sstevel@tonic-gate case _PC_NAME_MAX: 19300Sstevel@tonic-gate bzero(&vfsbuf, sizeof (vfsbuf)); 19310Sstevel@tonic-gate if (error = VFS_STATVFS(vp->v_vfsp, &vfsbuf)) 19320Sstevel@tonic-gate break; 19330Sstevel@tonic-gate val = vfsbuf.f_namemax; 19340Sstevel@tonic-gate break; 19350Sstevel@tonic-gate 19360Sstevel@tonic-gate case _PC_PATH_MAX: 19370Sstevel@tonic-gate case _PC_SYMLINK_MAX: 19380Sstevel@tonic-gate val = PCMAXPATHLEN; 19390Sstevel@tonic-gate break; 19400Sstevel@tonic-gate 19410Sstevel@tonic-gate case _PC_PIPE_BUF: 19420Sstevel@tonic-gate val = PIPE_BUF; 19430Sstevel@tonic-gate break; 19440Sstevel@tonic-gate 19450Sstevel@tonic-gate case _PC_NO_TRUNC: 19460Sstevel@tonic-gate val = (ulong_t)-1; /* Will truncate long file name */ 19470Sstevel@tonic-gate break; 19480Sstevel@tonic-gate 19490Sstevel@tonic-gate case _PC_VDISABLE: 19500Sstevel@tonic-gate val = _POSIX_VDISABLE; 19510Sstevel@tonic-gate break; 19520Sstevel@tonic-gate 19530Sstevel@tonic-gate case _PC_CHOWN_RESTRICTED: 19540Sstevel@tonic-gate if (rstchown) 19550Sstevel@tonic-gate val = rstchown; /* chown restricted enabled */ 19560Sstevel@tonic-gate else 19570Sstevel@tonic-gate val = (ulong_t)-1; 19580Sstevel@tonic-gate break; 19590Sstevel@tonic-gate 19600Sstevel@tonic-gate case _PC_ACL_ENABLED: 19610Sstevel@tonic-gate val = 0; 19620Sstevel@tonic-gate break; 19630Sstevel@tonic-gate 19640Sstevel@tonic-gate case _PC_FILESIZEBITS: 19650Sstevel@tonic-gate /* 19660Sstevel@tonic-gate * Both FAT16 and FAT32 support 4GB - 1 byte for file size. 19670Sstevel@tonic-gate * FAT12 can only go up to the maximum filesystem capacity 19680Sstevel@tonic-gate * which is ~509MB. 19690Sstevel@tonic-gate */ 19700Sstevel@tonic-gate val = IS_FAT12(fsp) ? 30 : 33; 19710Sstevel@tonic-gate break; 19720Sstevel@tonic-gate default: 19730Sstevel@tonic-gate error = EINVAL; 19740Sstevel@tonic-gate break; 19750Sstevel@tonic-gate } 19760Sstevel@tonic-gate 19770Sstevel@tonic-gate if (error == 0) 19780Sstevel@tonic-gate *valp = val; 19790Sstevel@tonic-gate return (error); 19800Sstevel@tonic-gate } 19810Sstevel@tonic-gate 19820Sstevel@tonic-gate /* ARGSUSED */ 19830Sstevel@tonic-gate static int 19840Sstevel@tonic-gate pcfs_space( 19850Sstevel@tonic-gate struct vnode *vp, 19860Sstevel@tonic-gate int cmd, 19870Sstevel@tonic-gate struct flock64 *bfp, 19880Sstevel@tonic-gate int flag, 19890Sstevel@tonic-gate offset_t offset, 19900Sstevel@tonic-gate cred_t *cr, 19910Sstevel@tonic-gate caller_context_t *ct) 19920Sstevel@tonic-gate { 19930Sstevel@tonic-gate struct vattr vattr; 19940Sstevel@tonic-gate int error; 19950Sstevel@tonic-gate 19960Sstevel@tonic-gate if (cmd != F_FREESP) 19970Sstevel@tonic-gate return (EINVAL); 19980Sstevel@tonic-gate 19990Sstevel@tonic-gate if ((error = convoff(vp, bfp, 0, offset)) == 0) { 20000Sstevel@tonic-gate if ((bfp->l_start > UINT32_MAX) || (bfp->l_len > UINT32_MAX)) 20010Sstevel@tonic-gate return (EFBIG); 20020Sstevel@tonic-gate /* 20030Sstevel@tonic-gate * we only support the special case of l_len == 0, 20040Sstevel@tonic-gate * meaning free to end of file at this moment. 20050Sstevel@tonic-gate */ 20060Sstevel@tonic-gate if (bfp->l_len != 0) 20070Sstevel@tonic-gate return (EINVAL); 20080Sstevel@tonic-gate vattr.va_mask = AT_SIZE; 20090Sstevel@tonic-gate vattr.va_size = bfp->l_start; 20100Sstevel@tonic-gate error = VOP_SETATTR(vp, &vattr, 0, cr, ct); 20110Sstevel@tonic-gate } 20120Sstevel@tonic-gate return (error); 20130Sstevel@tonic-gate } 20140Sstevel@tonic-gate 20150Sstevel@tonic-gate /* 20160Sstevel@tonic-gate * Break up 'len' chars from 'buf' into a long file name chunk. 20170Sstevel@tonic-gate * Pad with '0xff' to make Norton Disk Doctor and Microsoft ScanDisk happy. 20180Sstevel@tonic-gate */ 20190Sstevel@tonic-gate void 20200Sstevel@tonic-gate set_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int len) 20210Sstevel@tonic-gate { 20220Sstevel@tonic-gate char *tmp = buf; 20230Sstevel@tonic-gate int i; 20240Sstevel@tonic-gate 20250Sstevel@tonic-gate 20260Sstevel@tonic-gate for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2) { 20270Sstevel@tonic-gate if (len > 0) { 20280Sstevel@tonic-gate ep->pcdl_firstfilename[i] = *tmp; 20290Sstevel@tonic-gate ep->pcdl_firstfilename[i+1] = 0; 20300Sstevel@tonic-gate len--; 20310Sstevel@tonic-gate tmp++; 20320Sstevel@tonic-gate } else { 20330Sstevel@tonic-gate ep->pcdl_firstfilename[i] = (uchar_t)0xff; 20340Sstevel@tonic-gate ep->pcdl_firstfilename[i+1] = (uchar_t)0xff; 20350Sstevel@tonic-gate } 20360Sstevel@tonic-gate } 20370Sstevel@tonic-gate 20380Sstevel@tonic-gate for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2) { 20390Sstevel@tonic-gate if (len > 0) { 20400Sstevel@tonic-gate ep->pcdl_secondfilename[i] = *tmp; 20410Sstevel@tonic-gate ep->pcdl_secondfilename[i+1] = 0; 20420Sstevel@tonic-gate len--; 20430Sstevel@tonic-gate tmp++; 20440Sstevel@tonic-gate } else { 20450Sstevel@tonic-gate ep->pcdl_secondfilename[i] = (uchar_t)0xff; 20460Sstevel@tonic-gate ep->pcdl_secondfilename[i+1] = (uchar_t)0xff; 20470Sstevel@tonic-gate } 20480Sstevel@tonic-gate } 20490Sstevel@tonic-gate for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2) { 20500Sstevel@tonic-gate if (len > 0) { 20510Sstevel@tonic-gate ep->pcdl_thirdfilename[i] = *tmp; 20520Sstevel@tonic-gate ep->pcdl_thirdfilename[i+1] = 0; 20530Sstevel@tonic-gate len--; 20540Sstevel@tonic-gate tmp++; 20550Sstevel@tonic-gate } else { 20560Sstevel@tonic-gate ep->pcdl_thirdfilename[i] = (uchar_t)0xff; 20570Sstevel@tonic-gate ep->pcdl_thirdfilename[i+1] = (uchar_t)0xff; 20580Sstevel@tonic-gate } 20590Sstevel@tonic-gate } 20600Sstevel@tonic-gate } 20610Sstevel@tonic-gate 20620Sstevel@tonic-gate /* 20630Sstevel@tonic-gate * Extract the characters from the long filename chunk into 'buf'. 20640Sstevel@tonic-gate * Return the number of characters extracted. 20650Sstevel@tonic-gate */ 20660Sstevel@tonic-gate static int 20670Sstevel@tonic-gate get_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int foldcase) 20680Sstevel@tonic-gate { 20690Sstevel@tonic-gate char *tmp = buf; 20700Sstevel@tonic-gate int i; 20710Sstevel@tonic-gate 20720Sstevel@tonic-gate for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2, tmp++) { 20730Sstevel@tonic-gate if (ep->pcdl_firstfilename[i+1] != '\0') 20740Sstevel@tonic-gate return (-1); 20750Sstevel@tonic-gate if (foldcase) 20760Sstevel@tonic-gate *tmp = tolower(ep->pcdl_firstfilename[i]); 20770Sstevel@tonic-gate else 20780Sstevel@tonic-gate *tmp = ep->pcdl_firstfilename[i]; 20790Sstevel@tonic-gate if (*tmp == '\0') 20800Sstevel@tonic-gate return (tmp - buf); 20810Sstevel@tonic-gate } 20820Sstevel@tonic-gate for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2, tmp++) { 20830Sstevel@tonic-gate if (ep->pcdl_secondfilename[i+1] != '\0') 20840Sstevel@tonic-gate return (-1); 20850Sstevel@tonic-gate if (foldcase) 20860Sstevel@tonic-gate *tmp = tolower(ep->pcdl_secondfilename[i]); 20870Sstevel@tonic-gate else 20880Sstevel@tonic-gate *tmp = ep->pcdl_secondfilename[i]; 20890Sstevel@tonic-gate if (*tmp == '\0') 20900Sstevel@tonic-gate return (tmp - buf); 20910Sstevel@tonic-gate } 20920Sstevel@tonic-gate for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2, tmp++) { 20930Sstevel@tonic-gate if (ep->pcdl_thirdfilename[i+1] != '\0') 20940Sstevel@tonic-gate return (-1); 20950Sstevel@tonic-gate if (foldcase) 20960Sstevel@tonic-gate *tmp = tolower(ep->pcdl_thirdfilename[i]); 20970Sstevel@tonic-gate else 20980Sstevel@tonic-gate *tmp = ep->pcdl_thirdfilename[i]; 20990Sstevel@tonic-gate if (*tmp == '\0') 21000Sstevel@tonic-gate return (tmp - buf); 21010Sstevel@tonic-gate } 21020Sstevel@tonic-gate *tmp = '\0'; 21030Sstevel@tonic-gate return (tmp - buf); 21040Sstevel@tonic-gate } 21050Sstevel@tonic-gate 21060Sstevel@tonic-gate 21070Sstevel@tonic-gate /* 21080Sstevel@tonic-gate * Checksum the passed in short filename. 21090Sstevel@tonic-gate * This is used to validate each component of the long name to make 21100Sstevel@tonic-gate * sure the long name is valid (it hasn't been "detached" from the 21110Sstevel@tonic-gate * short filename). This algorithm was found in FreeBSD. 21120Sstevel@tonic-gate * (sys/fs/msdosfs/msdosfs_conv.c:winChksum(), Wolfgang Solfrank) 21130Sstevel@tonic-gate */ 21140Sstevel@tonic-gate 21150Sstevel@tonic-gate uchar_t 21160Sstevel@tonic-gate pc_checksum_long_fn(char *name, char *ext) 21170Sstevel@tonic-gate { 21180Sstevel@tonic-gate uchar_t c; 21190Sstevel@tonic-gate char b[11]; 21200Sstevel@tonic-gate 21210Sstevel@tonic-gate bcopy(name, b, 8); 21220Sstevel@tonic-gate bcopy(ext, b+8, 3); 21230Sstevel@tonic-gate 21240Sstevel@tonic-gate c = b[0]; 21250Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[1]; 21260Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[2]; 21270Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[3]; 21280Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[4]; 21290Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[5]; 21300Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[6]; 21310Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[7]; 21320Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[8]; 21330Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[9]; 21340Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[10]; 21350Sstevel@tonic-gate 21360Sstevel@tonic-gate return (c); 21370Sstevel@tonic-gate } 21380Sstevel@tonic-gate 21390Sstevel@tonic-gate /* 21400Sstevel@tonic-gate * Read a chunk of long filename entries into 'namep'. 21410Sstevel@tonic-gate * Return with offset pointing to short entry (on success), or next 21420Sstevel@tonic-gate * entry to read (if this wasn't a valid lfn really). 21430Sstevel@tonic-gate * Uses the passed-in buffer if it can, otherwise kmem_allocs() room for 21440Sstevel@tonic-gate * a long filename. 21450Sstevel@tonic-gate * 21460Sstevel@tonic-gate * Can also be called with a NULL namep, in which case it just returns 21470Sstevel@tonic-gate * whether this was really a valid long filename and consumes it 21480Sstevel@tonic-gate * (used by pc_dirempty()). 21490Sstevel@tonic-gate */ 21500Sstevel@tonic-gate int 21510Sstevel@tonic-gate pc_extract_long_fn(struct pcnode *pcp, char *namep, 21520Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp) 21530Sstevel@tonic-gate { 21540Sstevel@tonic-gate struct pcdir *ep = *epp; 21550Sstevel@tonic-gate struct pcdir_lfn *lep = (struct pcdir_lfn *)ep; 21560Sstevel@tonic-gate struct vnode *dvp = PCTOV(pcp); 21570Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 21580Sstevel@tonic-gate char *lfn; 21590Sstevel@tonic-gate char *lfn_base; 21600Sstevel@tonic-gate int boff; 21610Sstevel@tonic-gate int i, cs; 21620Sstevel@tonic-gate char buf[20]; 21630Sstevel@tonic-gate uchar_t cksum; 21640Sstevel@tonic-gate int detached = 0; 21650Sstevel@tonic-gate int error = 0; 21660Sstevel@tonic-gate int foldcase; 21670Sstevel@tonic-gate 21680Sstevel@tonic-gate foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE); 21690Sstevel@tonic-gate /* use callers buffer unless we didn't get one */ 21700Sstevel@tonic-gate if (namep) 21710Sstevel@tonic-gate lfn_base = namep; 21720Sstevel@tonic-gate else 21730Sstevel@tonic-gate lfn_base = kmem_alloc(PCMAXNAMLEN+1, KM_SLEEP); 21740Sstevel@tonic-gate lfn = lfn_base + PCMAXNAMLEN - 1; 21750Sstevel@tonic-gate *lfn = '\0'; 21760Sstevel@tonic-gate cksum = lep->pcdl_checksum; 21770Sstevel@tonic-gate 21780Sstevel@tonic-gate for (i = (lep->pcdl_ordinal & ~0xc0); i > 0; i--) { 21790Sstevel@tonic-gate /* read next block if necessary */ 21800Sstevel@tonic-gate boff = pc_blkoff(fsp, *offset); 21810Sstevel@tonic-gate if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) { 21820Sstevel@tonic-gate if (*bp != NULL) { 21830Sstevel@tonic-gate brelse(*bp); 21840Sstevel@tonic-gate *bp = NULL; 21850Sstevel@tonic-gate } 21860Sstevel@tonic-gate error = pc_blkatoff(pcp, *offset, bp, &ep); 21870Sstevel@tonic-gate if (error) { 21880Sstevel@tonic-gate if (namep == NULL) 21890Sstevel@tonic-gate kmem_free(lfn_base, PCMAXNAMLEN+1); 21900Sstevel@tonic-gate return (error); 21910Sstevel@tonic-gate } 21920Sstevel@tonic-gate lep = (struct pcdir_lfn *)ep; 21930Sstevel@tonic-gate } 21940Sstevel@tonic-gate /* can this happen? Bad fs? */ 21950Sstevel@tonic-gate if (!PCDL_IS_LFN((struct pcdir *)lep)) { 21960Sstevel@tonic-gate detached = 1; 21970Sstevel@tonic-gate break; 21980Sstevel@tonic-gate } 21990Sstevel@tonic-gate if (cksum != lep->pcdl_checksum) 22000Sstevel@tonic-gate detached = 1; 22010Sstevel@tonic-gate /* process current entry */ 22020Sstevel@tonic-gate cs = get_long_fn_chunk(lep, buf, foldcase); 22030Sstevel@tonic-gate if (cs == -1) { 22040Sstevel@tonic-gate detached = 1; 22050Sstevel@tonic-gate } else { 22060Sstevel@tonic-gate for (; cs > 0; cs--) { 22070Sstevel@tonic-gate /* see if we underflow */ 22080Sstevel@tonic-gate if (lfn >= lfn_base) 22090Sstevel@tonic-gate *--lfn = buf[cs - 1]; 22100Sstevel@tonic-gate else 22110Sstevel@tonic-gate detached = 1; 22120Sstevel@tonic-gate } 22130Sstevel@tonic-gate } 22140Sstevel@tonic-gate lep++; 22150Sstevel@tonic-gate *offset += sizeof (struct pcdir); 22160Sstevel@tonic-gate } 22170Sstevel@tonic-gate /* read next block if necessary */ 22180Sstevel@tonic-gate boff = pc_blkoff(fsp, *offset); 22190Sstevel@tonic-gate ep = (struct pcdir *)lep; 22200Sstevel@tonic-gate if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) { 22210Sstevel@tonic-gate if (*bp != NULL) { 22220Sstevel@tonic-gate brelse(*bp); 22230Sstevel@tonic-gate *bp = NULL; 22240Sstevel@tonic-gate } 22250Sstevel@tonic-gate error = pc_blkatoff(pcp, *offset, bp, &ep); 22260Sstevel@tonic-gate if (error) { 22270Sstevel@tonic-gate if (namep == NULL) 22280Sstevel@tonic-gate kmem_free(lfn_base, PCMAXNAMLEN+1); 22290Sstevel@tonic-gate return (error); 22300Sstevel@tonic-gate } 22310Sstevel@tonic-gate } 22320Sstevel@tonic-gate /* should be on the short one */ 22330Sstevel@tonic-gate if (PCDL_IS_LFN(ep) || ((ep->pcd_filename[0] == PCD_UNUSED) || 22340Sstevel@tonic-gate (ep->pcd_filename[0] == PCD_ERASED))) { 22350Sstevel@tonic-gate detached = 1; 22360Sstevel@tonic-gate } 22370Sstevel@tonic-gate if (detached || 22380Sstevel@tonic-gate (cksum != pc_checksum_long_fn(ep->pcd_filename, ep->pcd_ext)) || 22390Sstevel@tonic-gate !pc_valid_long_fn(lfn)) { 22400Sstevel@tonic-gate /* 22410Sstevel@tonic-gate * process current entry again. This may end up another lfn 22420Sstevel@tonic-gate * or a short name. 22430Sstevel@tonic-gate */ 22440Sstevel@tonic-gate *epp = ep; 22450Sstevel@tonic-gate if (namep == NULL) 22460Sstevel@tonic-gate kmem_free(lfn_base, PCMAXNAMLEN+1); 22470Sstevel@tonic-gate return (EINVAL); 22480Sstevel@tonic-gate } 22490Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) { 22500Sstevel@tonic-gate /* 22510Sstevel@tonic-gate * Don't display label because it may contain 22520Sstevel@tonic-gate * funny characters. 22530Sstevel@tonic-gate */ 22540Sstevel@tonic-gate *offset += sizeof (struct pcdir); 22550Sstevel@tonic-gate ep++; 22560Sstevel@tonic-gate *epp = ep; 22570Sstevel@tonic-gate if (namep == NULL) 22580Sstevel@tonic-gate kmem_free(lfn_base, PCMAXNAMLEN+1); 22590Sstevel@tonic-gate return (EINVAL); 22600Sstevel@tonic-gate } 22610Sstevel@tonic-gate if (namep) { 22620Sstevel@tonic-gate /* lfn is part of namep, but shifted. shift it back */ 22630Sstevel@tonic-gate cs = strlen(lfn); 22640Sstevel@tonic-gate for (i = 0; i < cs; i++) 22650Sstevel@tonic-gate namep[i] = lfn[i]; 22660Sstevel@tonic-gate namep[i] = '\0'; 22670Sstevel@tonic-gate } else { 22680Sstevel@tonic-gate kmem_free(lfn_base, PCMAXNAMLEN+1); 22690Sstevel@tonic-gate } 22700Sstevel@tonic-gate *epp = ep; 22710Sstevel@tonic-gate return (0); 22720Sstevel@tonic-gate } 22730Sstevel@tonic-gate /* 22740Sstevel@tonic-gate * Read a long filename into the pc_dirent structure and copy it out. 22750Sstevel@tonic-gate */ 22760Sstevel@tonic-gate int 22770Sstevel@tonic-gate pc_read_long_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld, 22780Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp) 22790Sstevel@tonic-gate { 22800Sstevel@tonic-gate struct pcdir *ep; 22810Sstevel@tonic-gate struct pcnode *pcp = VTOPC(dvp); 22820Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 22830Sstevel@tonic-gate offset_t uiooffset = uiop->uio_loffset; 22840Sstevel@tonic-gate int error = 0; 22850Sstevel@tonic-gate offset_t oldoffset; 22860Sstevel@tonic-gate 22870Sstevel@tonic-gate oldoffset = *offset; 22880Sstevel@tonic-gate error = pc_extract_long_fn(pcp, ld->d_name, epp, offset, bp); 22890Sstevel@tonic-gate if (error) { 22900Sstevel@tonic-gate if (error == EINVAL) { 22910Sstevel@tonic-gate uiop->uio_loffset += *offset - oldoffset; 22920Sstevel@tonic-gate return (0); 22930Sstevel@tonic-gate } else 22940Sstevel@tonic-gate return (error); 22950Sstevel@tonic-gate } 22960Sstevel@tonic-gate 22970Sstevel@tonic-gate ep = *epp; 22980Sstevel@tonic-gate uiop->uio_loffset += *offset - oldoffset; 22990Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name)); 23000Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 23010Sstevel@tonic-gate uiop->uio_loffset = uiooffset; 23020Sstevel@tonic-gate return (ENOSPC); 23030Sstevel@tonic-gate } 23040Sstevel@tonic-gate ld->d_off = uiop->uio_loffset + sizeof (struct pcdir); 23050Sstevel@tonic-gate ld->d_ino = pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno), 23060Sstevel@tonic-gate pc_blkoff(fsp, *offset), ep->pcd_attr, 23070Sstevel@tonic-gate pc_getstartcluster(fsp, ep), fsp->pcfs_entps); 23080Sstevel@tonic-gate (void) uiomove((caddr_t)ld, ld->d_reclen, UIO_READ, uiop); 23090Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 23100Sstevel@tonic-gate *offset += sizeof (struct pcdir); 23110Sstevel@tonic-gate ep++; 23120Sstevel@tonic-gate *epp = ep; 23130Sstevel@tonic-gate return (0); 23140Sstevel@tonic-gate } 23150Sstevel@tonic-gate 23160Sstevel@tonic-gate /* 23170Sstevel@tonic-gate * Read a short filename into the pc_dirent structure and copy it out. 23180Sstevel@tonic-gate */ 23190Sstevel@tonic-gate int 23200Sstevel@tonic-gate pc_read_short_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld, 23210Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp) 23220Sstevel@tonic-gate { 23230Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 23240Sstevel@tonic-gate int boff = pc_blkoff(fsp, *offset); 23250Sstevel@tonic-gate struct pcdir *ep = *epp; 23260Sstevel@tonic-gate offset_t oldoffset = uiop->uio_loffset; 23270Sstevel@tonic-gate int error; 23280Sstevel@tonic-gate int foldcase; 23290Sstevel@tonic-gate 23300Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) { 23310Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir); 23320Sstevel@tonic-gate *offset += sizeof (struct pcdir); 23330Sstevel@tonic-gate ep++; 23340Sstevel@tonic-gate *epp = ep; 23350Sstevel@tonic-gate return (0); 23360Sstevel@tonic-gate } 23370Sstevel@tonic-gate ld->d_ino = (ino64_t)pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno), 23380Sstevel@tonic-gate boff, ep->pcd_attr, pc_getstartcluster(fsp, ep), fsp->pcfs_entps); 23390Sstevel@tonic-gate foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE); 23400Sstevel@tonic-gate error = pc_fname_ext_to_name(&ld->d_name[0], &ep->pcd_filename[0], 23410Sstevel@tonic-gate &ep->pcd_ext[0], foldcase); 23420Sstevel@tonic-gate if (error == 0) { 23430Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name)); 23440Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 23450Sstevel@tonic-gate uiop->uio_loffset = oldoffset; 23460Sstevel@tonic-gate return (ENOSPC); 23470Sstevel@tonic-gate } 23480Sstevel@tonic-gate ld->d_off = (off64_t)(uiop->uio_loffset + 23490Sstevel@tonic-gate sizeof (struct pcdir)); 23500Sstevel@tonic-gate (void) uiomove((caddr_t)ld, 23510Sstevel@tonic-gate ld->d_reclen, UIO_READ, uiop); 23520Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 23530Sstevel@tonic-gate } else { 23540Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir); 23550Sstevel@tonic-gate } 23560Sstevel@tonic-gate *offset += sizeof (struct pcdir); 23570Sstevel@tonic-gate ep++; 23580Sstevel@tonic-gate *epp = ep; 23590Sstevel@tonic-gate return (0); 23600Sstevel@tonic-gate } 23610Sstevel@tonic-gate 23620Sstevel@tonic-gate static int 23630Sstevel@tonic-gate pcfs_fid(struct vnode *vp, struct fid *fidp) 23640Sstevel@tonic-gate { 23650Sstevel@tonic-gate struct pc_fid *pcfid; 23660Sstevel@tonic-gate struct pcnode *pcp; 23670Sstevel@tonic-gate struct pcfs *fsp; 23680Sstevel@tonic-gate int error; 23690Sstevel@tonic-gate 23700Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 23710Sstevel@tonic-gate if (fsp == NULL) 23720Sstevel@tonic-gate return (EIO); 23730Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 23740Sstevel@tonic-gate if (error) 23750Sstevel@tonic-gate return (error); 2376*2972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 23770Sstevel@tonic-gate pc_unlockfs(fsp); 23780Sstevel@tonic-gate return (EIO); 23790Sstevel@tonic-gate } 23800Sstevel@tonic-gate if (fidp->fid_len < (sizeof (struct pc_fid) - sizeof (ushort_t))) { 23810Sstevel@tonic-gate fidp->fid_len = sizeof (struct pc_fid) - sizeof (ushort_t); 23820Sstevel@tonic-gate pc_unlockfs(fsp); 23830Sstevel@tonic-gate return (ENOSPC); 23840Sstevel@tonic-gate } 23850Sstevel@tonic-gate 23860Sstevel@tonic-gate pcfid = (struct pc_fid *)fidp; 23870Sstevel@tonic-gate bzero(pcfid, sizeof (struct pc_fid)); 23880Sstevel@tonic-gate pcfid->pcfid_len = sizeof (struct pc_fid) - sizeof (ushort_t); 23890Sstevel@tonic-gate if (vp->v_flag & VROOT) { 23900Sstevel@tonic-gate pcfid->pcfid_block = 0; 23910Sstevel@tonic-gate pcfid->pcfid_offset = 0; 23920Sstevel@tonic-gate pcfid->pcfid_ctime = 0; 23930Sstevel@tonic-gate } else { 23940Sstevel@tonic-gate pcfid->pcfid_block = pcp->pc_eblkno; 23950Sstevel@tonic-gate pcfid->pcfid_offset = pcp->pc_eoffset; 23960Sstevel@tonic-gate pcfid->pcfid_ctime = pcp->pc_entry.pcd_crtime.pct_time; 23970Sstevel@tonic-gate } 23980Sstevel@tonic-gate pc_unlockfs(fsp); 23990Sstevel@tonic-gate return (0); 24000Sstevel@tonic-gate } 2401