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 /* 223898Srsb * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/param.h> 290Sstevel@tonic-gate #include <sys/t_lock.h> 300Sstevel@tonic-gate #include <sys/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> 363898Srsb #include <sys/vfs_opreg.h> 370Sstevel@tonic-gate #include <sys/dirent.h> 380Sstevel@tonic-gate #include <sys/vnode.h> 390Sstevel@tonic-gate #include <sys/proc.h> 400Sstevel@tonic-gate #include <sys/file.h> 410Sstevel@tonic-gate #include <sys/fcntl.h> 420Sstevel@tonic-gate #include <sys/uio.h> 430Sstevel@tonic-gate #include <sys/fs/pc_label.h> 440Sstevel@tonic-gate #include <sys/fs/pc_fs.h> 450Sstevel@tonic-gate #include <sys/fs/pc_dir.h> 460Sstevel@tonic-gate #include <sys/fs/pc_node.h> 470Sstevel@tonic-gate #include <sys/mman.h> 480Sstevel@tonic-gate #include <sys/pathname.h> 490Sstevel@tonic-gate #include <sys/vmsystm.h> 500Sstevel@tonic-gate #include <sys/cmn_err.h> 510Sstevel@tonic-gate #include <sys/debug.h> 520Sstevel@tonic-gate #include <sys/statvfs.h> 530Sstevel@tonic-gate #include <sys/unistd.h> 540Sstevel@tonic-gate #include <sys/kmem.h> 550Sstevel@tonic-gate #include <sys/conf.h> 560Sstevel@tonic-gate #include <sys/flock.h> 570Sstevel@tonic-gate #include <sys/policy.h> 582720Sfrankho #include <sys/sdt.h> 594723Sksn #include <sys/sunddi.h> 600Sstevel@tonic-gate 610Sstevel@tonic-gate #include <vm/seg.h> 620Sstevel@tonic-gate #include <vm/page.h> 630Sstevel@tonic-gate #include <vm/pvn.h> 640Sstevel@tonic-gate #include <vm/seg_map.h> 650Sstevel@tonic-gate #include <vm/seg_vn.h> 660Sstevel@tonic-gate #include <vm/hat.h> 670Sstevel@tonic-gate #include <vm/as.h> 680Sstevel@tonic-gate #include <vm/seg_kmem.h> 690Sstevel@tonic-gate 700Sstevel@tonic-gate #include <fs/fs_subr.h> 710Sstevel@tonic-gate 72*5331Samw static int pcfs_open(struct vnode **, int, struct cred *, caller_context_t *ct); 73*5331Samw static int pcfs_close(struct vnode *, int, int, offset_t, struct cred *, 74*5331Samw caller_context_t *ct); 750Sstevel@tonic-gate static int pcfs_read(struct vnode *, struct uio *, int, struct cred *, 76*5331Samw caller_context_t *); 770Sstevel@tonic-gate static int pcfs_write(struct vnode *, struct uio *, int, struct cred *, 78*5331Samw caller_context_t *); 79*5331Samw static int pcfs_getattr(struct vnode *, struct vattr *, int, struct cred *, 80*5331Samw caller_context_t *ct); 810Sstevel@tonic-gate static int pcfs_setattr(struct vnode *, struct vattr *, int, struct cred *, 820Sstevel@tonic-gate caller_context_t *); 83*5331Samw static int pcfs_access(struct vnode *, int, int, struct cred *, 84*5331Samw caller_context_t *ct); 850Sstevel@tonic-gate static int pcfs_lookup(struct vnode *, char *, struct vnode **, 86*5331Samw struct pathname *, int, struct vnode *, struct cred *, 87*5331Samw caller_context_t *, int *, pathname_t *); 880Sstevel@tonic-gate static int pcfs_create(struct vnode *, char *, struct vattr *, 89*5331Samw enum vcexcl, int mode, struct vnode **, struct cred *, int, 90*5331Samw caller_context_t *, vsecattr_t *); 91*5331Samw static int pcfs_remove(struct vnode *, char *, struct cred *, 92*5331Samw caller_context_t *, int); 930Sstevel@tonic-gate static int pcfs_rename(struct vnode *, char *, struct vnode *, char *, 94*5331Samw struct cred *, caller_context_t *, int); 950Sstevel@tonic-gate static int pcfs_mkdir(struct vnode *, char *, struct vattr *, struct vnode **, 96*5331Samw struct cred *, caller_context_t *, int, vsecattr_t *); 97*5331Samw static int pcfs_rmdir(struct vnode *, char *, struct vnode *, struct cred *, 98*5331Samw caller_context_t *, int); 99*5331Samw static int pcfs_readdir(struct vnode *, struct uio *, struct cred *, int *, 100*5331Samw caller_context_t *, int); 101*5331Samw static int pcfs_fsync(struct vnode *, int, struct cred *, caller_context_t *); 102*5331Samw static void pcfs_inactive(struct vnode *, struct cred *, caller_context_t *); 103*5331Samw static int pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *); 1040Sstevel@tonic-gate static int pcfs_space(struct vnode *, int, struct flock64 *, int, 1050Sstevel@tonic-gate offset_t, cred_t *, caller_context_t *); 1060Sstevel@tonic-gate static int pcfs_getpage(struct vnode *, offset_t, size_t, uint_t *, page_t *[], 107*5331Samw size_t, struct seg *, caddr_t, enum seg_rw, struct cred *, 108*5331Samw caller_context_t *); 1090Sstevel@tonic-gate static int pcfs_getapage(struct vnode *, u_offset_t, size_t, uint_t *, 1100Sstevel@tonic-gate page_t *[], size_t, struct seg *, caddr_t, enum seg_rw, struct cred *); 111*5331Samw static int pcfs_putpage(struct vnode *, offset_t, size_t, int, struct cred *, 112*5331Samw caller_context_t *); 1130Sstevel@tonic-gate static int pcfs_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t, 114*5331Samw uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *); 1150Sstevel@tonic-gate static int pcfs_addmap(struct vnode *, offset_t, struct as *, caddr_t, 116*5331Samw size_t, uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *); 1170Sstevel@tonic-gate static int pcfs_delmap(struct vnode *, offset_t, struct as *, caddr_t, 118*5331Samw size_t, uint_t, uint_t, uint_t, struct cred *, caller_context_t *); 119*5331Samw static int pcfs_seek(struct vnode *, offset_t, offset_t *, 120*5331Samw caller_context_t *); 121*5331Samw static int pcfs_pathconf(struct vnode *, int, ulong_t *, struct cred *, 122*5331Samw caller_context_t *); 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate int pcfs_putapage(struct vnode *, page_t *, u_offset_t *, size_t *, int, 1250Sstevel@tonic-gate struct cred *); 1260Sstevel@tonic-gate static int rwpcp(struct pcnode *, struct uio *, enum uio_rw, int); 1270Sstevel@tonic-gate static int get_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int foldcase); 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate extern krwlock_t pcnodes_lock; 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate #define lround(r) (((r)+sizeof (long long)-1)&(~(sizeof (long long)-1))) 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate /* 1340Sstevel@tonic-gate * vnode op vectors for files and directories. 1350Sstevel@tonic-gate */ 1360Sstevel@tonic-gate struct vnodeops *pcfs_fvnodeops; 1370Sstevel@tonic-gate struct vnodeops *pcfs_dvnodeops; 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate const fs_operation_def_t pcfs_fvnodeops_template[] = { 1403898Srsb VOPNAME_OPEN, { .vop_open = pcfs_open }, 1413898Srsb VOPNAME_CLOSE, { .vop_close = pcfs_close }, 1423898Srsb VOPNAME_READ, { .vop_read = pcfs_read }, 1433898Srsb VOPNAME_WRITE, { .vop_write = pcfs_write }, 1443898Srsb VOPNAME_GETATTR, { .vop_getattr = pcfs_getattr }, 1453898Srsb VOPNAME_SETATTR, { .vop_setattr = pcfs_setattr }, 1463898Srsb VOPNAME_ACCESS, { .vop_access = pcfs_access }, 1473898Srsb VOPNAME_FSYNC, { .vop_fsync = pcfs_fsync }, 1483898Srsb VOPNAME_INACTIVE, { .vop_inactive = pcfs_inactive }, 1493898Srsb VOPNAME_FID, { .vop_fid = pcfs_fid }, 1503898Srsb VOPNAME_SEEK, { .vop_seek = pcfs_seek }, 1513898Srsb VOPNAME_SPACE, { .vop_space = pcfs_space }, 1523898Srsb VOPNAME_GETPAGE, { .vop_getpage = pcfs_getpage }, 1533898Srsb VOPNAME_PUTPAGE, { .vop_putpage = pcfs_putpage }, 1543898Srsb VOPNAME_MAP, { .vop_map = pcfs_map }, 1553898Srsb VOPNAME_ADDMAP, { .vop_addmap = pcfs_addmap }, 1563898Srsb VOPNAME_DELMAP, { .vop_delmap = pcfs_delmap }, 1573898Srsb VOPNAME_PATHCONF, { .vop_pathconf = pcfs_pathconf }, 1583898Srsb VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, 1593898Srsb NULL, NULL 1600Sstevel@tonic-gate }; 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate const fs_operation_def_t pcfs_dvnodeops_template[] = { 1633898Srsb VOPNAME_OPEN, { .vop_open = pcfs_open }, 1643898Srsb VOPNAME_CLOSE, { .vop_close = pcfs_close }, 1653898Srsb VOPNAME_GETATTR, { .vop_getattr = pcfs_getattr }, 1663898Srsb VOPNAME_SETATTR, { .vop_setattr = pcfs_setattr }, 1673898Srsb VOPNAME_ACCESS, { .vop_access = pcfs_access }, 1683898Srsb VOPNAME_LOOKUP, { .vop_lookup = pcfs_lookup }, 1693898Srsb VOPNAME_CREATE, { .vop_create = pcfs_create }, 1703898Srsb VOPNAME_REMOVE, { .vop_remove = pcfs_remove }, 1713898Srsb VOPNAME_RENAME, { .vop_rename = pcfs_rename }, 1723898Srsb VOPNAME_MKDIR, { .vop_mkdir = pcfs_mkdir }, 1733898Srsb VOPNAME_RMDIR, { .vop_rmdir = pcfs_rmdir }, 1743898Srsb VOPNAME_READDIR, { .vop_readdir = pcfs_readdir }, 1753898Srsb VOPNAME_FSYNC, { .vop_fsync = pcfs_fsync }, 1763898Srsb VOPNAME_INACTIVE, { .vop_inactive = pcfs_inactive }, 1773898Srsb VOPNAME_FID, { .vop_fid = pcfs_fid }, 1783898Srsb VOPNAME_SEEK, { .vop_seek = pcfs_seek }, 1793898Srsb VOPNAME_PATHCONF, { .vop_pathconf = pcfs_pathconf }, 1803898Srsb VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, 1813898Srsb NULL, NULL 1820Sstevel@tonic-gate }; 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate /*ARGSUSED*/ 1860Sstevel@tonic-gate static int 1870Sstevel@tonic-gate pcfs_open( 1880Sstevel@tonic-gate struct vnode **vpp, 1890Sstevel@tonic-gate int flag, 190*5331Samw struct cred *cr, 191*5331Samw caller_context_t *ct) 1920Sstevel@tonic-gate { 1930Sstevel@tonic-gate return (0); 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate /* 1970Sstevel@tonic-gate * files are sync'ed on close to keep floppy up to date 1980Sstevel@tonic-gate */ 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate /*ARGSUSED*/ 2010Sstevel@tonic-gate static int 2020Sstevel@tonic-gate pcfs_close( 2030Sstevel@tonic-gate struct vnode *vp, 2040Sstevel@tonic-gate int flag, 2050Sstevel@tonic-gate int count, 2060Sstevel@tonic-gate offset_t offset, 207*5331Samw struct cred *cr, 208*5331Samw caller_context_t *ct) 2090Sstevel@tonic-gate { 2100Sstevel@tonic-gate return (0); 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate /*ARGSUSED*/ 2140Sstevel@tonic-gate static int 2150Sstevel@tonic-gate pcfs_read( 2160Sstevel@tonic-gate struct vnode *vp, 2170Sstevel@tonic-gate struct uio *uiop, 2180Sstevel@tonic-gate int ioflag, 2190Sstevel@tonic-gate struct cred *cr, 2200Sstevel@tonic-gate struct caller_context *ct) 2210Sstevel@tonic-gate { 2220Sstevel@tonic-gate struct pcfs *fsp; 2230Sstevel@tonic-gate struct pcnode *pcp; 2240Sstevel@tonic-gate int error; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 2270Sstevel@tonic-gate if (error = pc_verify(fsp)) 2280Sstevel@tonic-gate return (error); 2290Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 2300Sstevel@tonic-gate if (error) 2310Sstevel@tonic-gate return (error); 2322972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 2330Sstevel@tonic-gate pc_unlockfs(fsp); 2340Sstevel@tonic-gate return (EIO); 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate error = rwpcp(pcp, uiop, UIO_READ, ioflag); 2370Sstevel@tonic-gate if ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0) { 2385121Sfrankho pc_mark_acc(fsp, pcp); 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate pc_unlockfs(fsp); 2410Sstevel@tonic-gate if (error) { 2420Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_read: io error = %d\n", error); 2430Sstevel@tonic-gate } 2440Sstevel@tonic-gate return (error); 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate /*ARGSUSED*/ 2480Sstevel@tonic-gate static int 2490Sstevel@tonic-gate pcfs_write( 2500Sstevel@tonic-gate struct vnode *vp, 2510Sstevel@tonic-gate struct uio *uiop, 2520Sstevel@tonic-gate int ioflag, 2530Sstevel@tonic-gate struct cred *cr, 2540Sstevel@tonic-gate struct caller_context *ct) 2550Sstevel@tonic-gate { 2560Sstevel@tonic-gate struct pcfs *fsp; 2570Sstevel@tonic-gate struct pcnode *pcp; 2580Sstevel@tonic-gate int error; 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 2610Sstevel@tonic-gate if (error = pc_verify(fsp)) 2620Sstevel@tonic-gate return (error); 2630Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 2640Sstevel@tonic-gate if (error) 2650Sstevel@tonic-gate return (error); 2662972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 2670Sstevel@tonic-gate pc_unlockfs(fsp); 2680Sstevel@tonic-gate return (EIO); 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate if (ioflag & FAPPEND) { 2710Sstevel@tonic-gate /* 2720Sstevel@tonic-gate * in append mode start at end of file. 2730Sstevel@tonic-gate */ 2740Sstevel@tonic-gate uiop->uio_loffset = pcp->pc_size; 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate error = rwpcp(pcp, uiop, UIO_WRITE, ioflag); 2770Sstevel@tonic-gate pcp->pc_flags |= PC_MOD; 2785121Sfrankho pc_mark_mod(fsp, pcp); 2790Sstevel@tonic-gate if (ioflag & (FSYNC|FDSYNC)) 2800Sstevel@tonic-gate (void) pc_nodeupdate(pcp); 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate pc_unlockfs(fsp); 2830Sstevel@tonic-gate if (error) { 2840Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_write: io error = %d\n", error); 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate return (error); 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate /* 2900Sstevel@tonic-gate * read or write a vnode 2910Sstevel@tonic-gate */ 2920Sstevel@tonic-gate static int 2930Sstevel@tonic-gate rwpcp( 2940Sstevel@tonic-gate struct pcnode *pcp, 2950Sstevel@tonic-gate struct uio *uio, 2960Sstevel@tonic-gate enum uio_rw rw, 2970Sstevel@tonic-gate int ioflag) 2980Sstevel@tonic-gate { 2990Sstevel@tonic-gate struct vnode *vp = PCTOV(pcp); 3000Sstevel@tonic-gate struct pcfs *fsp; 3010Sstevel@tonic-gate daddr_t bn; /* phys block number */ 3020Sstevel@tonic-gate int n; 3030Sstevel@tonic-gate offset_t off; 3040Sstevel@tonic-gate caddr_t base; 3050Sstevel@tonic-gate int mapon, pagecreate; 3060Sstevel@tonic-gate int newpage; 3070Sstevel@tonic-gate int error = 0; 3080Sstevel@tonic-gate rlim64_t limit = uio->uio_llimit; 3090Sstevel@tonic-gate int oresid = uio->uio_resid; 3100Sstevel@tonic-gate 3112720Sfrankho /* 3122720Sfrankho * If the filesystem was umounted by force, return immediately. 3132720Sfrankho */ 3142720Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 3152720Sfrankho return (EIO); 3162720Sfrankho 3170Sstevel@tonic-gate PC_DPRINTF4(5, "rwpcp pcp=%p off=%lld resid=%ld size=%u\n", (void *)pcp, 3180Sstevel@tonic-gate uio->uio_loffset, uio->uio_resid, pcp->pc_size); 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate ASSERT(rw == UIO_READ || rw == UIO_WRITE); 3210Sstevel@tonic-gate ASSERT(vp->v_type == VREG); 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate if (uio->uio_loffset >= UINT32_MAX && rw == UIO_READ) { 3240Sstevel@tonic-gate return (0); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate if (uio->uio_loffset < 0) 3280Sstevel@tonic-gate return (EINVAL); 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T) 3310Sstevel@tonic-gate limit = MAXOFFSET_T; 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate if (uio->uio_loffset >= limit && rw == UIO_WRITE) { 3340Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate mutex_enter(&p->p_lock); 3370Sstevel@tonic-gate (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], p->p_rctls, 3380Sstevel@tonic-gate p, RCA_UNSAFE_SIGINFO); 3390Sstevel@tonic-gate mutex_exit(&p->p_lock); 3400Sstevel@tonic-gate return (EFBIG); 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate /* the following condition will occur only for write */ 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate if (uio->uio_loffset >= UINT32_MAX) 3460Sstevel@tonic-gate return (EFBIG); 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate if (uio->uio_resid == 0) 3490Sstevel@tonic-gate return (0); 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate if (limit > UINT32_MAX) 3520Sstevel@tonic-gate limit = UINT32_MAX; 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 3550Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_IRRECOV) 3560Sstevel@tonic-gate return (EIO); 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate do { 3590Sstevel@tonic-gate /* 3600Sstevel@tonic-gate * Assignments to "n" in this block may appear 3610Sstevel@tonic-gate * to overflow in some cases. However, after careful 3620Sstevel@tonic-gate * analysis it was determined that all assignments to 3630Sstevel@tonic-gate * "n" serve only to make "n" smaller. Since "n" 3640Sstevel@tonic-gate * starts out as no larger than MAXBSIZE, "int" is 3650Sstevel@tonic-gate * safe. 3660Sstevel@tonic-gate */ 3670Sstevel@tonic-gate off = uio->uio_loffset & MAXBMASK; 3680Sstevel@tonic-gate mapon = (int)(uio->uio_loffset & MAXBOFFSET); 3690Sstevel@tonic-gate n = MIN(MAXBSIZE - mapon, uio->uio_resid); 3700Sstevel@tonic-gate if (rw == UIO_READ) { 3710Sstevel@tonic-gate offset_t diff; 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate diff = pcp->pc_size - uio->uio_loffset; 3740Sstevel@tonic-gate if (diff <= 0) 3750Sstevel@tonic-gate return (0); 3760Sstevel@tonic-gate if (diff < n) 3770Sstevel@tonic-gate n = (int)diff; 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate /* 3800Sstevel@tonic-gate * Compare limit with the actual offset + n, not the 3810Sstevel@tonic-gate * rounded down offset "off" or we will overflow 3820Sstevel@tonic-gate * the maximum file size after all. 3830Sstevel@tonic-gate */ 3840Sstevel@tonic-gate if (rw == UIO_WRITE && uio->uio_loffset + n >= limit) { 3850Sstevel@tonic-gate if (uio->uio_loffset >= limit) { 3860Sstevel@tonic-gate error = EFBIG; 3870Sstevel@tonic-gate break; 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate n = (int)(limit - uio->uio_loffset); 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate base = segmap_getmap(segkmap, vp, (u_offset_t)off); 3920Sstevel@tonic-gate pagecreate = 0; 3930Sstevel@tonic-gate newpage = 0; 3940Sstevel@tonic-gate if (rw == UIO_WRITE) { 3950Sstevel@tonic-gate /* 3960Sstevel@tonic-gate * If PAGESIZE < MAXBSIZE, perhaps we ought to deal 3970Sstevel@tonic-gate * with one page at a time, instead of one MAXBSIZE 3980Sstevel@tonic-gate * at a time, so we can fully explore pagecreate 3990Sstevel@tonic-gate * optimization?? 4000Sstevel@tonic-gate */ 4010Sstevel@tonic-gate if (uio->uio_loffset + n > pcp->pc_size) { 4020Sstevel@tonic-gate uint_t ncl, lcn; 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate ncl = (uint_t)howmany((offset_t)pcp->pc_size, 4054723Sksn fsp->pcfs_clsize); 4060Sstevel@tonic-gate if (uio->uio_loffset > pcp->pc_size && 4070Sstevel@tonic-gate ncl < (uint_t)howmany(uio->uio_loffset, 4084723Sksn fsp->pcfs_clsize)) { 4090Sstevel@tonic-gate /* 4100Sstevel@tonic-gate * Allocate and zerofill skipped 4110Sstevel@tonic-gate * clusters. This may not be worth the 4120Sstevel@tonic-gate * effort since a small lseek beyond 4130Sstevel@tonic-gate * eof but still within the cluster 4140Sstevel@tonic-gate * will not be zeroed out. 4150Sstevel@tonic-gate */ 4160Sstevel@tonic-gate lcn = pc_lblkno(fsp, uio->uio_loffset); 4170Sstevel@tonic-gate error = pc_balloc(pcp, (daddr_t)lcn, 4180Sstevel@tonic-gate 1, &bn); 4190Sstevel@tonic-gate ncl = lcn + 1; 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate if (!error && 4220Sstevel@tonic-gate ncl < (uint_t)howmany(uio->uio_loffset + n, 4234723Sksn fsp->pcfs_clsize)) 4240Sstevel@tonic-gate /* 4250Sstevel@tonic-gate * allocate clusters w/o zerofill 4260Sstevel@tonic-gate */ 4270Sstevel@tonic-gate error = pc_balloc(pcp, 4280Sstevel@tonic-gate (daddr_t)pc_lblkno(fsp, 4290Sstevel@tonic-gate uio->uio_loffset + n - 1), 4300Sstevel@tonic-gate 0, &bn); 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate if (error) { 4352972Sfrankho pc_cluster32_t ncl; 4362972Sfrankho int nerror; 4372972Sfrankho 4382972Sfrankho /* 4392972Sfrankho * figure out new file size from 4402972Sfrankho * cluster chain length. If this 4412972Sfrankho * is detected to loop, the chain 4422972Sfrankho * is corrupted and we'd better 4432972Sfrankho * keep our fingers off that file. 4442972Sfrankho */ 4452972Sfrankho nerror = pc_fileclsize(fsp, 4462972Sfrankho pcp->pc_scluster, &ncl); 4472972Sfrankho if (nerror) { 4482972Sfrankho PC_DPRINTF1(2, 4492972Sfrankho "cluster chain " 4502972Sfrankho "corruption, " 4512972Sfrankho "scluster=%d\n", 4522972Sfrankho pcp->pc_scluster); 4532972Sfrankho pcp->pc_size = 0; 4542972Sfrankho pcp->pc_flags |= PC_INVAL; 4552972Sfrankho error = nerror; 4562972Sfrankho (void) segmap_release(segkmap, 4572972Sfrankho base, 0); 4582972Sfrankho break; 4592972Sfrankho } 4602972Sfrankho pcp->pc_size = fsp->pcfs_clsize * ncl; 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate if (error == ENOSPC && 4630Sstevel@tonic-gate (pcp->pc_size - uio->uio_loffset) 4644723Sksn > 0) { 4650Sstevel@tonic-gate PC_DPRINTF3(2, "rwpcp ENOSPC " 4660Sstevel@tonic-gate "off=%lld n=%d size=%d\n", 4670Sstevel@tonic-gate uio->uio_loffset, 4680Sstevel@tonic-gate n, pcp->pc_size); 4690Sstevel@tonic-gate n = (int)(pcp->pc_size - 4704723Sksn uio->uio_loffset); 4710Sstevel@tonic-gate } else { 4720Sstevel@tonic-gate PC_DPRINTF1(1, 4730Sstevel@tonic-gate "rwpcp error1=%d\n", error); 4740Sstevel@tonic-gate (void) segmap_release(segkmap, 4750Sstevel@tonic-gate base, 0); 4760Sstevel@tonic-gate break; 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate } else { 4790Sstevel@tonic-gate pcp->pc_size = 4800Sstevel@tonic-gate (uint_t)(uio->uio_loffset + n); 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate if (mapon == 0) { 4830Sstevel@tonic-gate newpage = segmap_pagecreate(segkmap, 4844723Sksn base, (size_t)n, 0); 4850Sstevel@tonic-gate pagecreate = 1; 4860Sstevel@tonic-gate } 4870Sstevel@tonic-gate } else if (n == MAXBSIZE) { 4880Sstevel@tonic-gate newpage = segmap_pagecreate(segkmap, base, 4894723Sksn (size_t)n, 0); 4900Sstevel@tonic-gate pagecreate = 1; 4910Sstevel@tonic-gate } 4920Sstevel@tonic-gate } 4930Sstevel@tonic-gate error = uiomove(base + mapon, (size_t)n, rw, uio); 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate if (pagecreate && uio->uio_loffset < 4964723Sksn roundup(off + mapon + n, PAGESIZE)) { 4970Sstevel@tonic-gate offset_t nzero, nmoved; 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate nmoved = uio->uio_loffset - (off + mapon); 5000Sstevel@tonic-gate nzero = roundup(mapon + n, PAGESIZE) - nmoved; 5010Sstevel@tonic-gate (void) kzero(base + mapon + nmoved, (size_t)nzero); 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate /* 5050Sstevel@tonic-gate * Unlock the pages which have been allocated by 5060Sstevel@tonic-gate * page_create_va() in segmap_pagecreate(). 5070Sstevel@tonic-gate */ 5085121Sfrankho if (newpage) { 5090Sstevel@tonic-gate segmap_pageunlock(segkmap, base, (size_t)n, 5104723Sksn rw == UIO_WRITE ? S_WRITE : S_READ); 5115121Sfrankho } 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate if (error) { 5140Sstevel@tonic-gate PC_DPRINTF1(1, "rwpcp error2=%d\n", error); 5150Sstevel@tonic-gate /* 5160Sstevel@tonic-gate * If we failed on a write, we may have already 5170Sstevel@tonic-gate * allocated file blocks as well as pages. It's hard 5180Sstevel@tonic-gate * to undo the block allocation, but we must be sure 5190Sstevel@tonic-gate * to invalidate any pages that may have been 5200Sstevel@tonic-gate * allocated. 5210Sstevel@tonic-gate */ 5220Sstevel@tonic-gate if (rw == UIO_WRITE) 5230Sstevel@tonic-gate (void) segmap_release(segkmap, base, SM_INVAL); 5240Sstevel@tonic-gate else 5250Sstevel@tonic-gate (void) segmap_release(segkmap, base, 0); 5260Sstevel@tonic-gate } else { 5270Sstevel@tonic-gate uint_t flags = 0; 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate if (rw == UIO_READ) { 5300Sstevel@tonic-gate if (n + mapon == MAXBSIZE || 5310Sstevel@tonic-gate uio->uio_loffset == pcp->pc_size) 5320Sstevel@tonic-gate flags = SM_DONTNEED; 5330Sstevel@tonic-gate } else if (ioflag & (FSYNC|FDSYNC)) { 5340Sstevel@tonic-gate flags = SM_WRITE; 5350Sstevel@tonic-gate } else if (n + mapon == MAXBSIZE) { 5360Sstevel@tonic-gate flags = SM_WRITE|SM_ASYNC|SM_DONTNEED; 5370Sstevel@tonic-gate } 5380Sstevel@tonic-gate error = segmap_release(segkmap, base, flags); 5390Sstevel@tonic-gate } 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate } while (error == 0 && uio->uio_resid > 0 && n != 0); 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate if (oresid != uio->uio_resid) 5440Sstevel@tonic-gate error = 0; 5450Sstevel@tonic-gate return (error); 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate /*ARGSUSED*/ 5490Sstevel@tonic-gate static int 5500Sstevel@tonic-gate pcfs_getattr( 5510Sstevel@tonic-gate struct vnode *vp, 5520Sstevel@tonic-gate struct vattr *vap, 5530Sstevel@tonic-gate int flags, 554*5331Samw struct cred *cr, 555*5331Samw caller_context_t *ct) 5560Sstevel@tonic-gate { 5570Sstevel@tonic-gate struct pcnode *pcp; 5580Sstevel@tonic-gate struct pcfs *fsp; 5590Sstevel@tonic-gate int error; 5600Sstevel@tonic-gate char attr; 5610Sstevel@tonic-gate struct pctime atime; 5622720Sfrankho int64_t unixtime; 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate PC_DPRINTF1(8, "pcfs_getattr: vp=%p\n", (void *)vp); 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 5670Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 5680Sstevel@tonic-gate if (error) 5690Sstevel@tonic-gate return (error); 5702972Sfrankho 5712972Sfrankho /* 5722972Sfrankho * Note that we don't check for "invalid node" (PC_INVAL) here 5732972Sfrankho * only in order to make stat() succeed. We allow no I/O on such 574*5331Samw * a node, but do allow to check for its existence. 5752972Sfrankho */ 5760Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) { 5770Sstevel@tonic-gate pc_unlockfs(fsp); 5780Sstevel@tonic-gate return (EIO); 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate /* 5810Sstevel@tonic-gate * Copy from pcnode. 5820Sstevel@tonic-gate */ 5830Sstevel@tonic-gate vap->va_type = vp->v_type; 5840Sstevel@tonic-gate attr = pcp->pc_entry.pcd_attr; 5850Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, attr)) 5860Sstevel@tonic-gate vap->va_mode = 0; 5870Sstevel@tonic-gate else if (attr & PCA_LABEL) 5880Sstevel@tonic-gate vap->va_mode = 0444; 5890Sstevel@tonic-gate else if (attr & PCA_RDONLY) 5900Sstevel@tonic-gate vap->va_mode = 0555; 5910Sstevel@tonic-gate else if (fsp->pcfs_flags & PCFS_BOOTPART) { 5920Sstevel@tonic-gate vap->va_mode = 0755; 5930Sstevel@tonic-gate } else { 5940Sstevel@tonic-gate vap->va_mode = 0777; 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate if (attr & PCA_DIR) 5980Sstevel@tonic-gate vap->va_mode |= S_IFDIR; 5990Sstevel@tonic-gate else 6000Sstevel@tonic-gate vap->va_mode |= S_IFREG; 6010Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 6020Sstevel@tonic-gate vap->va_uid = 0; 6030Sstevel@tonic-gate vap->va_gid = 0; 6040Sstevel@tonic-gate } else { 6050Sstevel@tonic-gate vap->va_uid = crgetuid(cr); 6060Sstevel@tonic-gate vap->va_gid = crgetgid(cr); 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate vap->va_fsid = vp->v_vfsp->vfs_dev; 6090Sstevel@tonic-gate vap->va_nodeid = (ino64_t)pc_makenodeid(pcp->pc_eblkno, 6100Sstevel@tonic-gate pcp->pc_eoffset, pcp->pc_entry.pcd_attr, 6115121Sfrankho pc_getstartcluster(fsp, &pcp->pc_entry), pc_direntpersec(fsp)); 6120Sstevel@tonic-gate vap->va_nlink = 1; 6130Sstevel@tonic-gate vap->va_size = (u_offset_t)pcp->pc_size; 6145121Sfrankho vap->va_rdev = 0; 6155121Sfrankho vap->va_nblocks = 6165121Sfrankho (fsblkcnt64_t)howmany((offset_t)pcp->pc_size, DEV_BSIZE); 6175121Sfrankho vap->va_blksize = fsp->pcfs_clsize; 6185121Sfrankho 6195121Sfrankho /* 6205121Sfrankho * FAT root directories have no timestamps. In order not to return 6215121Sfrankho * "time zero" (1/1/1970), we record the time of the mount and give 6225121Sfrankho * that. This breaks less expectations. 6235121Sfrankho */ 6245121Sfrankho if (vp->v_flag & VROOT) { 6255121Sfrankho vap->va_mtime = fsp->pcfs_mounttime; 6265121Sfrankho vap->va_atime = fsp->pcfs_mounttime; 6275121Sfrankho vap->va_ctime = fsp->pcfs_mounttime; 6285121Sfrankho pc_unlockfs(fsp); 6295121Sfrankho return (0); 6305121Sfrankho } 6312720Sfrankho 6322720Sfrankho pc_pcttotv(&pcp->pc_entry.pcd_mtime, &unixtime); 6332720Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) { 6342720Sfrankho if (unixtime > INT32_MAX) 6352720Sfrankho DTRACE_PROBE1(pcfs__mtimeclamped, int64_t, unixtime); 6362720Sfrankho unixtime = MIN(unixtime, INT32_MAX); 6372720Sfrankho } else if (unixtime > INT32_MAX && 6382720Sfrankho get_udatamodel() == DATAMODEL_ILP32) { 6392720Sfrankho pc_unlockfs(fsp); 6402720Sfrankho DTRACE_PROBE1(pcfs__mtimeoverflowed, int64_t, unixtime); 6412720Sfrankho return (EOVERFLOW); 6422720Sfrankho } 6432720Sfrankho 6442720Sfrankho vap->va_mtime.tv_sec = (time_t)unixtime; 6452720Sfrankho vap->va_mtime.tv_nsec = 0; 6462720Sfrankho 6472720Sfrankho /* 6482720Sfrankho * FAT doesn't know about POSIX ctime. 6492720Sfrankho * Best approximation is to always set it to mtime. 6502720Sfrankho */ 6510Sstevel@tonic-gate vap->va_ctime = vap->va_mtime; 6522720Sfrankho 6532720Sfrankho /* 6542720Sfrankho * FAT only stores "last access date". If that's the 6552720Sfrankho * same as the date of last modification then the time 6562720Sfrankho * of last access is known. Otherwise, use midnight. 6572720Sfrankho */ 6580Sstevel@tonic-gate atime.pct_date = pcp->pc_entry.pcd_ladate; 6592720Sfrankho if (atime.pct_date == pcp->pc_entry.pcd_mtime.pct_date) 6602720Sfrankho atime.pct_time = pcp->pc_entry.pcd_mtime.pct_time; 6612720Sfrankho else 6622720Sfrankho atime.pct_time = 0; 6632720Sfrankho pc_pcttotv(&atime, &unixtime); 6642720Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) { 6652720Sfrankho if (unixtime > INT32_MAX) 6662720Sfrankho DTRACE_PROBE1(pcfs__atimeclamped, int64_t, unixtime); 6672720Sfrankho unixtime = MIN(unixtime, INT32_MAX); 6682720Sfrankho } else if (unixtime > INT32_MAX && 6692720Sfrankho get_udatamodel() == DATAMODEL_ILP32) { 6702720Sfrankho pc_unlockfs(fsp); 6712720Sfrankho DTRACE_PROBE1(pcfs__atimeoverflowed, int64_t, unixtime); 6722720Sfrankho return (EOVERFLOW); 6732720Sfrankho } 6742720Sfrankho 6752720Sfrankho vap->va_atime.tv_sec = (time_t)unixtime; 6762720Sfrankho vap->va_atime.tv_nsec = 0; 6772720Sfrankho 6780Sstevel@tonic-gate pc_unlockfs(fsp); 6790Sstevel@tonic-gate return (0); 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate /*ARGSUSED*/ 6840Sstevel@tonic-gate static int 6850Sstevel@tonic-gate pcfs_setattr( 6860Sstevel@tonic-gate struct vnode *vp, 6870Sstevel@tonic-gate struct vattr *vap, 6880Sstevel@tonic-gate int flags, 6890Sstevel@tonic-gate struct cred *cr, 6900Sstevel@tonic-gate caller_context_t *ct) 6910Sstevel@tonic-gate { 6920Sstevel@tonic-gate struct pcnode *pcp; 6930Sstevel@tonic-gate mode_t mask = vap->va_mask; 6940Sstevel@tonic-gate int error; 6950Sstevel@tonic-gate struct pcfs *fsp; 6962720Sfrankho timestruc_t now, *timep; 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate PC_DPRINTF2(6, "pcfs_setattr: vp=%p mask=%x\n", (void *)vp, (int)mask); 6990Sstevel@tonic-gate /* 7000Sstevel@tonic-gate * cannot set these attributes 7010Sstevel@tonic-gate */ 7020Sstevel@tonic-gate if (mask & (AT_NOSET | AT_UID | AT_GID)) { 7030Sstevel@tonic-gate return (EINVAL); 7040Sstevel@tonic-gate } 7050Sstevel@tonic-gate /* 7062720Sfrankho * pcfs_setattr is now allowed on directories to avoid silly warnings 7070Sstevel@tonic-gate * from 'tar' when it tries to set times on a directory, and console 7080Sstevel@tonic-gate * printf's on the NFS server when it gets EINVAL back on such a 7090Sstevel@tonic-gate * request. One possible problem with that since a directory entry 7100Sstevel@tonic-gate * identifies a file, '.' and all the '..' entries in subdirectories 7110Sstevel@tonic-gate * may get out of sync when the directory is updated since they're 7120Sstevel@tonic-gate * treated like separate files. We could fix that by looking for 7130Sstevel@tonic-gate * '.' and giving it the same attributes, and then looking for 7140Sstevel@tonic-gate * all the subdirectories and updating '..', but that's pretty 7150Sstevel@tonic-gate * expensive for something that doesn't seem likely to matter. 7160Sstevel@tonic-gate */ 7170Sstevel@tonic-gate /* can't do some ops on directories anyway */ 7180Sstevel@tonic-gate if ((vp->v_type == VDIR) && 7190Sstevel@tonic-gate (mask & AT_SIZE)) { 7200Sstevel@tonic-gate return (EINVAL); 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 7240Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 7250Sstevel@tonic-gate if (error) 7260Sstevel@tonic-gate return (error); 7272972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 7280Sstevel@tonic-gate pc_unlockfs(fsp); 7290Sstevel@tonic-gate return (EIO); 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 7330Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 7340Sstevel@tonic-gate pc_unlockfs(fsp); 7350Sstevel@tonic-gate return (EACCES); 7360Sstevel@tonic-gate } 7370Sstevel@tonic-gate } 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate /* 7400Sstevel@tonic-gate * Change file access modes. 7410Sstevel@tonic-gate * If nobody has write permission, file is marked readonly. 7420Sstevel@tonic-gate * Otherwise file is writable by anyone. 7430Sstevel@tonic-gate */ 7440Sstevel@tonic-gate if ((mask & AT_MODE) && (vap->va_mode != (mode_t)-1)) { 7450Sstevel@tonic-gate if ((vap->va_mode & 0222) == 0) 7460Sstevel@tonic-gate pcp->pc_entry.pcd_attr |= PCA_RDONLY; 7470Sstevel@tonic-gate else 7480Sstevel@tonic-gate pcp->pc_entry.pcd_attr &= ~PCA_RDONLY; 7490Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 7500Sstevel@tonic-gate } 7510Sstevel@tonic-gate /* 7520Sstevel@tonic-gate * Truncate file. Must have write permission. 7530Sstevel@tonic-gate */ 7540Sstevel@tonic-gate if ((mask & AT_SIZE) && (vap->va_size != (u_offset_t)-1)) { 7550Sstevel@tonic-gate if (pcp->pc_entry.pcd_attr & PCA_RDONLY) { 7560Sstevel@tonic-gate error = EACCES; 7570Sstevel@tonic-gate goto out; 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate if (vap->va_size > UINT32_MAX) { 7600Sstevel@tonic-gate error = EFBIG; 7610Sstevel@tonic-gate goto out; 7620Sstevel@tonic-gate } 7630Sstevel@tonic-gate error = pc_truncate(pcp, (uint_t)vap->va_size); 7640Sstevel@tonic-gate if (error) 7650Sstevel@tonic-gate goto out; 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate /* 7680Sstevel@tonic-gate * Change file modified times. 7690Sstevel@tonic-gate */ 7702720Sfrankho if (mask & (AT_MTIME | AT_CTIME)) { 7710Sstevel@tonic-gate /* 7720Sstevel@tonic-gate * If SysV-compatible option to set access and 7730Sstevel@tonic-gate * modified times if privileged, owner, or write access, 7740Sstevel@tonic-gate * use current time rather than va_mtime. 7750Sstevel@tonic-gate * 7760Sstevel@tonic-gate * XXX - va_mtime.tv_sec == -1 flags this. 7770Sstevel@tonic-gate */ 7782720Sfrankho timep = &vap->va_mtime; 7790Sstevel@tonic-gate if (vap->va_mtime.tv_sec == -1) { 7800Sstevel@tonic-gate gethrestime(&now); 7812720Sfrankho timep = &now; 7820Sstevel@tonic-gate } 7832720Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 && 7842720Sfrankho timep->tv_sec > INT32_MAX) { 7852720Sfrankho error = EOVERFLOW; 7862720Sfrankho goto out; 7872720Sfrankho } 7882720Sfrankho error = pc_tvtopct(timep, &pcp->pc_entry.pcd_mtime); 7892720Sfrankho if (error) 7902720Sfrankho goto out; 7910Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 7920Sstevel@tonic-gate } 7930Sstevel@tonic-gate /* 7940Sstevel@tonic-gate * Change file access times. 7950Sstevel@tonic-gate */ 7962720Sfrankho if (mask & AT_ATIME) { 7970Sstevel@tonic-gate /* 7980Sstevel@tonic-gate * If SysV-compatible option to set access and 7990Sstevel@tonic-gate * modified times if privileged, owner, or write access, 8000Sstevel@tonic-gate * use current time rather than va_mtime. 8010Sstevel@tonic-gate * 8020Sstevel@tonic-gate * XXX - va_atime.tv_sec == -1 flags this. 8030Sstevel@tonic-gate */ 8040Sstevel@tonic-gate struct pctime atime; 8050Sstevel@tonic-gate 8062720Sfrankho timep = &vap->va_atime; 8070Sstevel@tonic-gate if (vap->va_atime.tv_sec == -1) { 8080Sstevel@tonic-gate gethrestime(&now); 8092720Sfrankho timep = &now; 8100Sstevel@tonic-gate } 8112720Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 && 8122720Sfrankho timep->tv_sec > INT32_MAX) { 8132720Sfrankho error = EOVERFLOW; 8142720Sfrankho goto out; 8152720Sfrankho } 8162720Sfrankho error = pc_tvtopct(timep, &atime); 8172720Sfrankho if (error) 8182720Sfrankho goto out; 8190Sstevel@tonic-gate pcp->pc_entry.pcd_ladate = atime.pct_date; 8200Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 8210Sstevel@tonic-gate } 8220Sstevel@tonic-gate out: 8230Sstevel@tonic-gate pc_unlockfs(fsp); 8240Sstevel@tonic-gate return (error); 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate 8270Sstevel@tonic-gate 8280Sstevel@tonic-gate /*ARGSUSED*/ 8290Sstevel@tonic-gate static int 8300Sstevel@tonic-gate pcfs_access( 8310Sstevel@tonic-gate struct vnode *vp, 8320Sstevel@tonic-gate int mode, 8330Sstevel@tonic-gate int flags, 834*5331Samw struct cred *cr, 835*5331Samw caller_context_t *ct) 8360Sstevel@tonic-gate { 8370Sstevel@tonic-gate struct pcnode *pcp; 8380Sstevel@tonic-gate struct pcfs *fsp; 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 8420Sstevel@tonic-gate 8432972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) 8440Sstevel@tonic-gate return (EIO); 8450Sstevel@tonic-gate if ((mode & VWRITE) && (pcp->pc_entry.pcd_attr & PCA_RDONLY)) 8460Sstevel@tonic-gate return (EACCES); 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate /* 8490Sstevel@tonic-gate * If this is a boot partition, privileged users have full access while 8500Sstevel@tonic-gate * others have read-only access. 8510Sstevel@tonic-gate */ 8520Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 8530Sstevel@tonic-gate if ((mode & VWRITE) && 8540Sstevel@tonic-gate secpolicy_pcfs_modify_bootpartition(cr) != 0) 8550Sstevel@tonic-gate return (EACCES); 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate return (0); 8580Sstevel@tonic-gate } 8590Sstevel@tonic-gate 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate /*ARGSUSED*/ 8620Sstevel@tonic-gate static int 8630Sstevel@tonic-gate pcfs_fsync( 8640Sstevel@tonic-gate struct vnode *vp, 8650Sstevel@tonic-gate int syncflag, 866*5331Samw struct cred *cr, 867*5331Samw caller_context_t *ct) 8680Sstevel@tonic-gate { 8690Sstevel@tonic-gate struct pcfs *fsp; 8700Sstevel@tonic-gate struct pcnode *pcp; 8710Sstevel@tonic-gate int error; 8720Sstevel@tonic-gate 8730Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 8740Sstevel@tonic-gate if (error = pc_verify(fsp)) 8750Sstevel@tonic-gate return (error); 8760Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 8770Sstevel@tonic-gate if (error) 8780Sstevel@tonic-gate return (error); 8792972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 8800Sstevel@tonic-gate pc_unlockfs(fsp); 8810Sstevel@tonic-gate return (EIO); 8820Sstevel@tonic-gate } 8830Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_WRITER); 8840Sstevel@tonic-gate error = pc_nodesync(pcp); 8850Sstevel@tonic-gate rw_exit(&pcnodes_lock); 8860Sstevel@tonic-gate pc_unlockfs(fsp); 8870Sstevel@tonic-gate return (error); 8880Sstevel@tonic-gate } 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate /*ARGSUSED*/ 8920Sstevel@tonic-gate static void 8930Sstevel@tonic-gate pcfs_inactive( 8940Sstevel@tonic-gate struct vnode *vp, 895*5331Samw struct cred *cr, 896*5331Samw caller_context_t *ct) 8970Sstevel@tonic-gate { 8980Sstevel@tonic-gate struct pcnode *pcp; 8990Sstevel@tonic-gate struct pcfs *fsp; 9000Sstevel@tonic-gate int error; 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 9030Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 1); 9040Sstevel@tonic-gate 9052720Sfrankho /* 9062720Sfrankho * If the filesystem was umounted by force, all dirty 9072720Sfrankho * pages associated with this vnode are invalidated 9082720Sfrankho * and then the vnode will be freed. 9092720Sfrankho */ 9102720Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) { 9112720Sfrankho pcp = VTOPC(vp); 9122720Sfrankho if (vn_has_cached_data(vp)) { 9132720Sfrankho (void) pvn_vplist_dirty(vp, (u_offset_t)0, 9142720Sfrankho pcfs_putapage, B_INVAL, (struct cred *)NULL); 9152720Sfrankho } 9162720Sfrankho remque(pcp); 9172720Sfrankho if (error == 0) 9182720Sfrankho pc_unlockfs(fsp); 9192720Sfrankho vn_free(vp); 9202720Sfrankho kmem_free(pcp, sizeof (struct pcnode)); 9212720Sfrankho VFS_RELE(PCFSTOVFS(fsp)); 9222720Sfrankho return; 9232720Sfrankho } 9242720Sfrankho 9250Sstevel@tonic-gate mutex_enter(&vp->v_lock); 9260Sstevel@tonic-gate ASSERT(vp->v_count >= 1); 9270Sstevel@tonic-gate if (vp->v_count > 1) { 9280Sstevel@tonic-gate vp->v_count--; /* release our hold from vn_rele */ 9290Sstevel@tonic-gate mutex_exit(&vp->v_lock); 9300Sstevel@tonic-gate pc_unlockfs(fsp); 9310Sstevel@tonic-gate return; 9320Sstevel@tonic-gate } 9330Sstevel@tonic-gate mutex_exit(&vp->v_lock); 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate /* 9360Sstevel@tonic-gate * Check again to confirm that no intervening I/O error 9370Sstevel@tonic-gate * with a subsequent pc_diskchanged() call has released 9382972Sfrankho * the pcnode. If it has then release the vnode as above. 9390Sstevel@tonic-gate */ 9402972Sfrankho pcp = VTOPC(vp); 9412972Sfrankho if (pcp == NULL || pcp->pc_flags & PC_INVAL) { 9422720Sfrankho if (vn_has_cached_data(vp)) 9432720Sfrankho (void) pvn_vplist_dirty(vp, (u_offset_t)0, 9442720Sfrankho pcfs_putapage, B_INVAL | B_TRUNC, 9452720Sfrankho (struct cred *)NULL); 9462972Sfrankho } 9472972Sfrankho 9482972Sfrankho if (pcp == NULL) { 9490Sstevel@tonic-gate vn_free(vp); 9502720Sfrankho } else { 9510Sstevel@tonic-gate pc_rele(pcp); 9522720Sfrankho } 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate if (!error) 9550Sstevel@tonic-gate pc_unlockfs(fsp); 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate /*ARGSUSED*/ 9590Sstevel@tonic-gate static int 9600Sstevel@tonic-gate pcfs_lookup( 9610Sstevel@tonic-gate struct vnode *dvp, 9620Sstevel@tonic-gate char *nm, 9630Sstevel@tonic-gate struct vnode **vpp, 9640Sstevel@tonic-gate struct pathname *pnp, 9650Sstevel@tonic-gate int flags, 9660Sstevel@tonic-gate struct vnode *rdir, 967*5331Samw struct cred *cr, 968*5331Samw caller_context_t *ct, 969*5331Samw int *direntflags, 970*5331Samw pathname_t *realpnp) 9710Sstevel@tonic-gate { 9720Sstevel@tonic-gate struct pcfs *fsp; 9730Sstevel@tonic-gate struct pcnode *pcp; 9740Sstevel@tonic-gate int error; 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate /* 9772720Sfrankho * If the filesystem was umounted by force, return immediately. 9782720Sfrankho */ 9792720Sfrankho if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 9802720Sfrankho return (EIO); 9812720Sfrankho 9822720Sfrankho /* 9830Sstevel@tonic-gate * verify that the dvp is still valid on the disk 9840Sstevel@tonic-gate */ 9850Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 9860Sstevel@tonic-gate if (error = pc_verify(fsp)) 9870Sstevel@tonic-gate return (error); 9880Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 9890Sstevel@tonic-gate if (error) 9900Sstevel@tonic-gate return (error); 9912972Sfrankho if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) { 9920Sstevel@tonic-gate pc_unlockfs(fsp); 9930Sstevel@tonic-gate return (EIO); 9940Sstevel@tonic-gate } 9950Sstevel@tonic-gate /* 9960Sstevel@tonic-gate * Null component name is a synonym for directory being searched. 9970Sstevel@tonic-gate */ 9980Sstevel@tonic-gate if (*nm == '\0') { 9990Sstevel@tonic-gate VN_HOLD(dvp); 10000Sstevel@tonic-gate *vpp = dvp; 10010Sstevel@tonic-gate pc_unlockfs(fsp); 10020Sstevel@tonic-gate return (0); 10030Sstevel@tonic-gate } 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate error = pc_dirlook(VTOPC(dvp), nm, &pcp); 10060Sstevel@tonic-gate if (!error) { 10070Sstevel@tonic-gate *vpp = PCTOV(pcp); 10080Sstevel@tonic-gate pcp->pc_flags |= PC_EXTERNAL; 10090Sstevel@tonic-gate } 10100Sstevel@tonic-gate pc_unlockfs(fsp); 10110Sstevel@tonic-gate return (error); 10120Sstevel@tonic-gate } 10130Sstevel@tonic-gate 10140Sstevel@tonic-gate 10150Sstevel@tonic-gate /*ARGSUSED*/ 10160Sstevel@tonic-gate static int 10170Sstevel@tonic-gate pcfs_create( 10180Sstevel@tonic-gate struct vnode *dvp, 10190Sstevel@tonic-gate char *nm, 10200Sstevel@tonic-gate struct vattr *vap, 10210Sstevel@tonic-gate enum vcexcl exclusive, 10220Sstevel@tonic-gate int mode, 10230Sstevel@tonic-gate struct vnode **vpp, 10240Sstevel@tonic-gate struct cred *cr, 1025*5331Samw int flag, 1026*5331Samw caller_context_t *ct, 1027*5331Samw vsecattr_t *vsecp) 10280Sstevel@tonic-gate { 10290Sstevel@tonic-gate int error; 10300Sstevel@tonic-gate struct pcnode *pcp; 10310Sstevel@tonic-gate struct vnode *vp; 10320Sstevel@tonic-gate struct pcfs *fsp; 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate /* 10350Sstevel@tonic-gate * can't create directories. use pcfs_mkdir. 10360Sstevel@tonic-gate * can't create anything other than files. 10370Sstevel@tonic-gate */ 10380Sstevel@tonic-gate if (vap->va_type == VDIR) 10390Sstevel@tonic-gate return (EISDIR); 10400Sstevel@tonic-gate else if (vap->va_type != VREG) 10410Sstevel@tonic-gate return (EINVAL); 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate pcp = NULL; 10440Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 10450Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 10460Sstevel@tonic-gate if (error) 10470Sstevel@tonic-gate return (error); 10482972Sfrankho if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) { 10490Sstevel@tonic-gate pc_unlockfs(fsp); 10500Sstevel@tonic-gate return (EIO); 10510Sstevel@tonic-gate } 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 10540Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 10550Sstevel@tonic-gate pc_unlockfs(fsp); 10560Sstevel@tonic-gate return (EACCES); 10570Sstevel@tonic-gate } 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate if (*nm == '\0') { 10610Sstevel@tonic-gate /* 10620Sstevel@tonic-gate * Null component name refers to the directory itself. 10630Sstevel@tonic-gate */ 10640Sstevel@tonic-gate VN_HOLD(dvp); 10650Sstevel@tonic-gate pcp = VTOPC(dvp); 10660Sstevel@tonic-gate error = EEXIST; 10670Sstevel@tonic-gate } else { 10680Sstevel@tonic-gate error = pc_direnter(VTOPC(dvp), nm, vap, &pcp); 10690Sstevel@tonic-gate } 10700Sstevel@tonic-gate /* 10710Sstevel@tonic-gate * if file exists and this is a nonexclusive create, 10720Sstevel@tonic-gate * check for access permissions 10730Sstevel@tonic-gate */ 10740Sstevel@tonic-gate if (error == EEXIST) { 10750Sstevel@tonic-gate vp = PCTOV(pcp); 10760Sstevel@tonic-gate if (exclusive == NONEXCL) { 10770Sstevel@tonic-gate if (vp->v_type == VDIR) { 10780Sstevel@tonic-gate error = EISDIR; 10790Sstevel@tonic-gate } else if (mode) { 10800Sstevel@tonic-gate error = pcfs_access(PCTOV(pcp), mode, 0, 1081*5331Samw cr, ct); 10820Sstevel@tonic-gate } else { 10830Sstevel@tonic-gate error = 0; 10840Sstevel@tonic-gate } 10850Sstevel@tonic-gate } 10860Sstevel@tonic-gate if (error) { 10870Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 10880Sstevel@tonic-gate } else if ((vp->v_type == VREG) && (vap->va_mask & AT_SIZE) && 10894723Sksn (vap->va_size == 0)) { 10900Sstevel@tonic-gate error = pc_truncate(pcp, 0L); 10914863Spraks if (error) { 10920Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 10934863Spraks } else { 1094*5331Samw vnevent_create(PCTOV(pcp), ct); 10954863Spraks } 10960Sstevel@tonic-gate } 10970Sstevel@tonic-gate } 10980Sstevel@tonic-gate if (error) { 10990Sstevel@tonic-gate pc_unlockfs(fsp); 11000Sstevel@tonic-gate return (error); 11010Sstevel@tonic-gate } 11020Sstevel@tonic-gate *vpp = PCTOV(pcp); 11030Sstevel@tonic-gate pcp->pc_flags |= PC_EXTERNAL; 11040Sstevel@tonic-gate pc_unlockfs(fsp); 11050Sstevel@tonic-gate return (error); 11060Sstevel@tonic-gate } 11070Sstevel@tonic-gate 11080Sstevel@tonic-gate /*ARGSUSED*/ 11090Sstevel@tonic-gate static int 11100Sstevel@tonic-gate pcfs_remove( 11110Sstevel@tonic-gate struct vnode *vp, 11120Sstevel@tonic-gate char *nm, 1113*5331Samw struct cred *cr, 1114*5331Samw caller_context_t *ct, 1115*5331Samw int flags) 11160Sstevel@tonic-gate { 11170Sstevel@tonic-gate struct pcfs *fsp; 11180Sstevel@tonic-gate struct pcnode *pcp; 11190Sstevel@tonic-gate int error; 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 11220Sstevel@tonic-gate if (error = pc_verify(fsp)) 11230Sstevel@tonic-gate return (error); 11240Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 11250Sstevel@tonic-gate if (error) 11260Sstevel@tonic-gate return (error); 11272972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 11280Sstevel@tonic-gate pc_unlockfs(fsp); 11290Sstevel@tonic-gate return (EIO); 11300Sstevel@tonic-gate } 11310Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 11320Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 11330Sstevel@tonic-gate pc_unlockfs(fsp); 11340Sstevel@tonic-gate return (EACCES); 11350Sstevel@tonic-gate } 11360Sstevel@tonic-gate } 1137*5331Samw error = pc_dirremove(pcp, nm, (struct vnode *)0, VREG, ct); 11380Sstevel@tonic-gate pc_unlockfs(fsp); 11390Sstevel@tonic-gate return (error); 11400Sstevel@tonic-gate } 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate /* 11430Sstevel@tonic-gate * Rename a file or directory 11440Sstevel@tonic-gate * This rename is restricted to only rename files within a directory. 11450Sstevel@tonic-gate * XX should make rename more general 11460Sstevel@tonic-gate */ 11470Sstevel@tonic-gate /*ARGSUSED*/ 11480Sstevel@tonic-gate static int 11490Sstevel@tonic-gate pcfs_rename( 11500Sstevel@tonic-gate struct vnode *sdvp, /* old (source) parent vnode */ 11510Sstevel@tonic-gate char *snm, /* old (source) entry name */ 11520Sstevel@tonic-gate struct vnode *tdvp, /* new (target) parent vnode */ 11530Sstevel@tonic-gate char *tnm, /* new (target) entry name */ 1154*5331Samw struct cred *cr, 1155*5331Samw caller_context_t *ct, 1156*5331Samw int flags) 11570Sstevel@tonic-gate { 11580Sstevel@tonic-gate struct pcfs *fsp; 11590Sstevel@tonic-gate struct pcnode *dp; /* parent pcnode */ 11600Sstevel@tonic-gate struct pcnode *tdp; 11610Sstevel@tonic-gate int error; 11620Sstevel@tonic-gate 11630Sstevel@tonic-gate fsp = VFSTOPCFS(sdvp->v_vfsp); 11640Sstevel@tonic-gate if (error = pc_verify(fsp)) 11650Sstevel@tonic-gate return (error); 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate /* 11680Sstevel@tonic-gate * make sure we can muck with this directory. 11690Sstevel@tonic-gate */ 1170*5331Samw error = pcfs_access(sdvp, VWRITE, 0, cr, ct); 11710Sstevel@tonic-gate if (error) { 11720Sstevel@tonic-gate return (error); 11730Sstevel@tonic-gate } 11740Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 11750Sstevel@tonic-gate if (error) 11760Sstevel@tonic-gate return (error); 11772972Sfrankho if (((dp = VTOPC(sdvp)) == NULL) || ((tdp = VTOPC(tdvp)) == NULL) || 11782972Sfrankho (dp->pc_flags & PC_INVAL) || (tdp->pc_flags & PC_INVAL)) { 11790Sstevel@tonic-gate pc_unlockfs(fsp); 11800Sstevel@tonic-gate return (EIO); 11810Sstevel@tonic-gate } 1182*5331Samw error = pc_rename(dp, tdp, snm, tnm, ct); 11830Sstevel@tonic-gate pc_unlockfs(fsp); 11840Sstevel@tonic-gate return (error); 11850Sstevel@tonic-gate } 11860Sstevel@tonic-gate 11870Sstevel@tonic-gate /*ARGSUSED*/ 11880Sstevel@tonic-gate static int 11890Sstevel@tonic-gate pcfs_mkdir( 11900Sstevel@tonic-gate struct vnode *dvp, 11910Sstevel@tonic-gate char *nm, 11920Sstevel@tonic-gate struct vattr *vap, 11930Sstevel@tonic-gate struct vnode **vpp, 1194*5331Samw struct cred *cr, 1195*5331Samw caller_context_t *ct, 1196*5331Samw int flags, 1197*5331Samw vsecattr_t *vsecp) 11980Sstevel@tonic-gate { 11990Sstevel@tonic-gate struct pcfs *fsp; 12000Sstevel@tonic-gate struct pcnode *pcp; 12010Sstevel@tonic-gate int error; 12020Sstevel@tonic-gate 12030Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 12040Sstevel@tonic-gate if (error = pc_verify(fsp)) 12050Sstevel@tonic-gate return (error); 12060Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 12070Sstevel@tonic-gate if (error) 12080Sstevel@tonic-gate return (error); 12092972Sfrankho if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) { 12100Sstevel@tonic-gate pc_unlockfs(fsp); 12110Sstevel@tonic-gate return (EIO); 12120Sstevel@tonic-gate } 12130Sstevel@tonic-gate 12140Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 12150Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 12160Sstevel@tonic-gate pc_unlockfs(fsp); 12170Sstevel@tonic-gate return (EACCES); 12180Sstevel@tonic-gate } 12190Sstevel@tonic-gate } 12200Sstevel@tonic-gate 12210Sstevel@tonic-gate error = pc_direnter(VTOPC(dvp), nm, vap, &pcp); 12220Sstevel@tonic-gate 12230Sstevel@tonic-gate if (!error) { 12240Sstevel@tonic-gate pcp -> pc_flags |= PC_EXTERNAL; 12250Sstevel@tonic-gate *vpp = PCTOV(pcp); 12260Sstevel@tonic-gate } else if (error == EEXIST) { 12270Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 12280Sstevel@tonic-gate } 12290Sstevel@tonic-gate pc_unlockfs(fsp); 12300Sstevel@tonic-gate return (error); 12310Sstevel@tonic-gate } 12320Sstevel@tonic-gate 12330Sstevel@tonic-gate /*ARGSUSED*/ 12340Sstevel@tonic-gate static int 12350Sstevel@tonic-gate pcfs_rmdir( 12360Sstevel@tonic-gate struct vnode *dvp, 12370Sstevel@tonic-gate char *nm, 12380Sstevel@tonic-gate struct vnode *cdir, 1239*5331Samw struct cred *cr, 1240*5331Samw caller_context_t *ct, 1241*5331Samw int flags) 12420Sstevel@tonic-gate { 12430Sstevel@tonic-gate struct pcfs *fsp; 12440Sstevel@tonic-gate struct pcnode *pcp; 12450Sstevel@tonic-gate int error; 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate fsp = VFSTOPCFS(dvp -> v_vfsp); 12480Sstevel@tonic-gate if (error = pc_verify(fsp)) 12490Sstevel@tonic-gate return (error); 12500Sstevel@tonic-gate if (error = pc_lockfs(fsp, 0, 0)) 12510Sstevel@tonic-gate return (error); 12520Sstevel@tonic-gate 12532972Sfrankho if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) { 12540Sstevel@tonic-gate pc_unlockfs(fsp); 12550Sstevel@tonic-gate return (EIO); 12560Sstevel@tonic-gate } 12570Sstevel@tonic-gate 12580Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 12590Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 12600Sstevel@tonic-gate pc_unlockfs(fsp); 12610Sstevel@tonic-gate return (EACCES); 12620Sstevel@tonic-gate } 12630Sstevel@tonic-gate } 12640Sstevel@tonic-gate 1265*5331Samw error = pc_dirremove(pcp, nm, cdir, VDIR, ct); 12660Sstevel@tonic-gate pc_unlockfs(fsp); 12670Sstevel@tonic-gate return (error); 12680Sstevel@tonic-gate } 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate /* 12710Sstevel@tonic-gate * read entries in a directory. 12720Sstevel@tonic-gate * we must convert pc format to unix format 12730Sstevel@tonic-gate */ 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate /*ARGSUSED*/ 12760Sstevel@tonic-gate static int 12770Sstevel@tonic-gate pcfs_readdir( 12780Sstevel@tonic-gate struct vnode *dvp, 12790Sstevel@tonic-gate struct uio *uiop, 12800Sstevel@tonic-gate struct cred *cr, 1281*5331Samw int *eofp, 1282*5331Samw caller_context_t *ct, 1283*5331Samw int flags) 12840Sstevel@tonic-gate { 12850Sstevel@tonic-gate struct pcnode *pcp; 12860Sstevel@tonic-gate struct pcfs *fsp; 12870Sstevel@tonic-gate struct pcdir *ep; 12880Sstevel@tonic-gate struct buf *bp = NULL; 12890Sstevel@tonic-gate offset_t offset; 12900Sstevel@tonic-gate int boff; 12910Sstevel@tonic-gate struct pc_dirent lbp; 12920Sstevel@tonic-gate struct pc_dirent *ld = &lbp; 12930Sstevel@tonic-gate int error; 12940Sstevel@tonic-gate 12952720Sfrankho /* 12962720Sfrankho * If the filesystem was umounted by force, return immediately. 12972720Sfrankho */ 12982720Sfrankho if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 12992720Sfrankho return (EIO); 13002720Sfrankho 13010Sstevel@tonic-gate if ((uiop->uio_iovcnt != 1) || 13020Sstevel@tonic-gate (uiop->uio_loffset % sizeof (struct pcdir)) != 0) { 13030Sstevel@tonic-gate return (EINVAL); 13040Sstevel@tonic-gate } 13050Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 13060Sstevel@tonic-gate /* 13070Sstevel@tonic-gate * verify that the dp is still valid on the disk 13080Sstevel@tonic-gate */ 13090Sstevel@tonic-gate if (error = pc_verify(fsp)) { 13100Sstevel@tonic-gate return (error); 13110Sstevel@tonic-gate } 13120Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 13130Sstevel@tonic-gate if (error) 13140Sstevel@tonic-gate return (error); 13152972Sfrankho if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) { 13160Sstevel@tonic-gate pc_unlockfs(fsp); 13170Sstevel@tonic-gate return (EIO); 13180Sstevel@tonic-gate } 13190Sstevel@tonic-gate 13200Sstevel@tonic-gate bzero(ld, sizeof (*ld)); 13210Sstevel@tonic-gate 13220Sstevel@tonic-gate if (eofp != NULL) 13230Sstevel@tonic-gate *eofp = 0; 13240Sstevel@tonic-gate offset = uiop->uio_loffset; 13250Sstevel@tonic-gate 13260Sstevel@tonic-gate if (dvp->v_flag & VROOT) { 13270Sstevel@tonic-gate /* 13280Sstevel@tonic-gate * kludge up entries for "." and ".." in the root. 13290Sstevel@tonic-gate */ 13300Sstevel@tonic-gate if (offset == 0) { 13310Sstevel@tonic-gate (void) strcpy(ld->d_name, "."); 13320Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(1); 13330Sstevel@tonic-gate ld->d_off = (off64_t)sizeof (struct pcdir); 13340Sstevel@tonic-gate ld->d_ino = (ino64_t)UINT_MAX; 13350Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 13360Sstevel@tonic-gate pc_unlockfs(fsp); 13370Sstevel@tonic-gate return (ENOSPC); 13380Sstevel@tonic-gate } 13390Sstevel@tonic-gate (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop); 13400Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 13410Sstevel@tonic-gate offset = uiop->uio_loffset; 13420Sstevel@tonic-gate } 13430Sstevel@tonic-gate if (offset == sizeof (struct pcdir)) { 13440Sstevel@tonic-gate (void) strcpy(ld->d_name, ".."); 13450Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(2); 13460Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 13470Sstevel@tonic-gate pc_unlockfs(fsp); 13480Sstevel@tonic-gate return (ENOSPC); 13490Sstevel@tonic-gate } 13500Sstevel@tonic-gate ld->d_off = (off64_t)(uiop->uio_loffset + 13510Sstevel@tonic-gate sizeof (struct pcdir)); 13520Sstevel@tonic-gate ld->d_ino = (ino64_t)UINT_MAX; 13530Sstevel@tonic-gate (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop); 13540Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 13550Sstevel@tonic-gate offset = uiop->uio_loffset; 13560Sstevel@tonic-gate } 13570Sstevel@tonic-gate offset -= 2 * sizeof (struct pcdir); 13580Sstevel@tonic-gate /* offset now has the real offset value into directory file */ 13590Sstevel@tonic-gate } 13600Sstevel@tonic-gate 13610Sstevel@tonic-gate for (;;) { 13620Sstevel@tonic-gate boff = pc_blkoff(fsp, offset); 13630Sstevel@tonic-gate if (boff == 0 || bp == NULL || boff >= bp->b_bcount) { 13640Sstevel@tonic-gate if (bp != NULL) { 13650Sstevel@tonic-gate brelse(bp); 13660Sstevel@tonic-gate bp = NULL; 13670Sstevel@tonic-gate } 13680Sstevel@tonic-gate error = pc_blkatoff(pcp, offset, &bp, &ep); 13690Sstevel@tonic-gate if (error) { 13700Sstevel@tonic-gate if (error == ENOENT) { 13710Sstevel@tonic-gate error = 0; 13720Sstevel@tonic-gate if (eofp) 13730Sstevel@tonic-gate *eofp = 1; 13740Sstevel@tonic-gate } 13750Sstevel@tonic-gate break; 13760Sstevel@tonic-gate } 13770Sstevel@tonic-gate } 13780Sstevel@tonic-gate if (ep->pcd_filename[0] == PCD_UNUSED) { 13790Sstevel@tonic-gate if (eofp) 13800Sstevel@tonic-gate *eofp = 1; 13810Sstevel@tonic-gate break; 13820Sstevel@tonic-gate } 13830Sstevel@tonic-gate /* 13840Sstevel@tonic-gate * Don't display label because it may contain funny characters. 13850Sstevel@tonic-gate */ 13860Sstevel@tonic-gate if (ep->pcd_filename[0] == PCD_ERASED) { 13870Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir); 13880Sstevel@tonic-gate offset += sizeof (struct pcdir); 13890Sstevel@tonic-gate ep++; 13900Sstevel@tonic-gate continue; 13910Sstevel@tonic-gate } 13920Sstevel@tonic-gate if (PCDL_IS_LFN(ep)) { 13930Sstevel@tonic-gate if (pc_read_long_fn(dvp, uiop, ld, &ep, &offset, &bp) != 13940Sstevel@tonic-gate 0) 13950Sstevel@tonic-gate break; 13960Sstevel@tonic-gate continue; 13970Sstevel@tonic-gate } 13980Sstevel@tonic-gate 13990Sstevel@tonic-gate if (pc_read_short_fn(dvp, uiop, ld, &ep, &offset, &bp) != 0) 14000Sstevel@tonic-gate break; 14010Sstevel@tonic-gate } 14020Sstevel@tonic-gate if (bp) 14030Sstevel@tonic-gate brelse(bp); 14040Sstevel@tonic-gate pc_unlockfs(fsp); 14050Sstevel@tonic-gate return (error); 14060Sstevel@tonic-gate } 14070Sstevel@tonic-gate 14080Sstevel@tonic-gate 14090Sstevel@tonic-gate /* 14100Sstevel@tonic-gate * Called from pvn_getpages or pcfs_getpage to get a particular page. 14110Sstevel@tonic-gate * When we are called the pcfs is already locked. 14120Sstevel@tonic-gate */ 14130Sstevel@tonic-gate /*ARGSUSED*/ 14140Sstevel@tonic-gate static int 14150Sstevel@tonic-gate pcfs_getapage( 14160Sstevel@tonic-gate struct vnode *vp, 14170Sstevel@tonic-gate u_offset_t off, 14180Sstevel@tonic-gate size_t len, 14190Sstevel@tonic-gate uint_t *protp, 14200Sstevel@tonic-gate page_t *pl[], /* NULL if async IO is requested */ 14210Sstevel@tonic-gate size_t plsz, 14220Sstevel@tonic-gate struct seg *seg, 14230Sstevel@tonic-gate caddr_t addr, 14240Sstevel@tonic-gate enum seg_rw rw, 14250Sstevel@tonic-gate struct cred *cr) 14260Sstevel@tonic-gate { 14270Sstevel@tonic-gate struct pcnode *pcp; 14280Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 14290Sstevel@tonic-gate struct vnode *devvp; 14300Sstevel@tonic-gate page_t *pp; 14310Sstevel@tonic-gate page_t *pagefound; 14320Sstevel@tonic-gate int err; 14330Sstevel@tonic-gate 14342720Sfrankho /* 14352720Sfrankho * If the filesystem was umounted by force, return immediately. 14362720Sfrankho */ 14372720Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 14382720Sfrankho return (EIO); 14392720Sfrankho 14400Sstevel@tonic-gate PC_DPRINTF3(5, "pcfs_getapage: vp=%p off=%lld len=%lu\n", 14410Sstevel@tonic-gate (void *)vp, off, len); 14420Sstevel@tonic-gate 14432972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) 14440Sstevel@tonic-gate return (EIO); 14450Sstevel@tonic-gate devvp = fsp->pcfs_devvp; 14460Sstevel@tonic-gate 14470Sstevel@tonic-gate /* pcfs doesn't do readaheads */ 14480Sstevel@tonic-gate if (pl == NULL) 14490Sstevel@tonic-gate return (0); 14500Sstevel@tonic-gate 14510Sstevel@tonic-gate pl[0] = NULL; 14520Sstevel@tonic-gate err = 0; 14530Sstevel@tonic-gate /* 14540Sstevel@tonic-gate * If the accessed time on the pcnode has not already been 14550Sstevel@tonic-gate * set elsewhere (e.g. for read/setattr) we set the time now. 14560Sstevel@tonic-gate * This gives us approximate modified times for mmap'ed files 14570Sstevel@tonic-gate * which are accessed via loads in the user address space. 14580Sstevel@tonic-gate */ 14590Sstevel@tonic-gate if ((pcp->pc_flags & PC_ACC) == 0 && 14600Sstevel@tonic-gate ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0)) { 14615121Sfrankho pc_mark_acc(fsp, pcp); 14620Sstevel@tonic-gate } 14630Sstevel@tonic-gate reread: 14640Sstevel@tonic-gate if ((pagefound = page_exists(vp, off)) == NULL) { 14650Sstevel@tonic-gate /* 14660Sstevel@tonic-gate * Need to really do disk IO to get the page(s). 14670Sstevel@tonic-gate */ 14680Sstevel@tonic-gate struct buf *bp; 14690Sstevel@tonic-gate daddr_t lbn, bn; 14700Sstevel@tonic-gate u_offset_t io_off; 14710Sstevel@tonic-gate size_t io_len; 14720Sstevel@tonic-gate u_offset_t lbnoff, xferoffset; 14730Sstevel@tonic-gate u_offset_t pgoff; 14740Sstevel@tonic-gate uint_t xfersize; 14750Sstevel@tonic-gate int err1; 14760Sstevel@tonic-gate 14770Sstevel@tonic-gate lbn = pc_lblkno(fsp, off); 14780Sstevel@tonic-gate lbnoff = off & ~(fsp->pcfs_clsize - 1); 14790Sstevel@tonic-gate xferoffset = off & ~(fsp->pcfs_secsize - 1); 14800Sstevel@tonic-gate 14810Sstevel@tonic-gate pp = pvn_read_kluster(vp, off, seg, addr, &io_off, &io_len, 14820Sstevel@tonic-gate off, (size_t)MIN(pc_blksize(fsp, pcp, off), PAGESIZE), 0); 14830Sstevel@tonic-gate if (pp == NULL) 14840Sstevel@tonic-gate /* 14850Sstevel@tonic-gate * XXX - If pcfs is made MT-hot, this should go 14860Sstevel@tonic-gate * back to reread. 14870Sstevel@tonic-gate */ 14880Sstevel@tonic-gate panic("pcfs_getapage pvn_read_kluster"); 14890Sstevel@tonic-gate 14900Sstevel@tonic-gate for (pgoff = 0; pgoff < PAGESIZE && xferoffset < pcp->pc_size; 14910Sstevel@tonic-gate pgoff += xfersize, 14920Sstevel@tonic-gate lbn += howmany(xfersize, fsp->pcfs_clsize), 14930Sstevel@tonic-gate lbnoff += xfersize, xferoffset += xfersize) { 14940Sstevel@tonic-gate /* 14950Sstevel@tonic-gate * read as many contiguous blocks as possible to 14960Sstevel@tonic-gate * fill this page 14970Sstevel@tonic-gate */ 14980Sstevel@tonic-gate xfersize = PAGESIZE - pgoff; 14990Sstevel@tonic-gate err1 = pc_bmap(pcp, lbn, &bn, &xfersize); 15000Sstevel@tonic-gate if (err1) { 15010Sstevel@tonic-gate PC_DPRINTF1(1, "pc_getapage err=%d", err1); 15020Sstevel@tonic-gate err = err1; 15030Sstevel@tonic-gate goto out; 15040Sstevel@tonic-gate } 15050Sstevel@tonic-gate bp = pageio_setup(pp, xfersize, devvp, B_READ); 15060Sstevel@tonic-gate bp->b_edev = devvp->v_rdev; 15070Sstevel@tonic-gate bp->b_dev = cmpdev(devvp->v_rdev); 15085121Sfrankho bp->b_blkno = bn + btodt(xferoffset - lbnoff); 1509973Selowe bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff; 15100Sstevel@tonic-gate bp->b_file = vp; 15110Sstevel@tonic-gate bp->b_offset = (offset_t)(off + pgoff); 15120Sstevel@tonic-gate 15130Sstevel@tonic-gate (void) bdev_strategy(bp); 15140Sstevel@tonic-gate 15150Sstevel@tonic-gate lwp_stat_update(LWP_STAT_INBLK, 1); 15160Sstevel@tonic-gate 15170Sstevel@tonic-gate if (err == 0) 15180Sstevel@tonic-gate err = biowait(bp); 15190Sstevel@tonic-gate else 15200Sstevel@tonic-gate (void) biowait(bp); 15210Sstevel@tonic-gate pageio_done(bp); 15220Sstevel@tonic-gate if (err) 15230Sstevel@tonic-gate goto out; 15240Sstevel@tonic-gate } 15250Sstevel@tonic-gate if (pgoff < PAGESIZE) { 15260Sstevel@tonic-gate pagezero(pp->p_prev, pgoff, PAGESIZE - pgoff); 15270Sstevel@tonic-gate } 15280Sstevel@tonic-gate pvn_plist_init(pp, pl, plsz, off, io_len, rw); 15290Sstevel@tonic-gate } 15300Sstevel@tonic-gate out: 15310Sstevel@tonic-gate if (err) { 15320Sstevel@tonic-gate if (pp != NULL) 15330Sstevel@tonic-gate pvn_read_done(pp, B_ERROR); 15340Sstevel@tonic-gate return (err); 15350Sstevel@tonic-gate } 15360Sstevel@tonic-gate 15370Sstevel@tonic-gate if (pagefound) { 15380Sstevel@tonic-gate /* 15390Sstevel@tonic-gate * Page exists in the cache, acquire the "shared" 15400Sstevel@tonic-gate * lock. If this fails, go back to reread. 15410Sstevel@tonic-gate */ 15420Sstevel@tonic-gate if ((pp = page_lookup(vp, off, SE_SHARED)) == NULL) { 15430Sstevel@tonic-gate goto reread; 15440Sstevel@tonic-gate } 15450Sstevel@tonic-gate pl[0] = pp; 15460Sstevel@tonic-gate pl[1] = NULL; 15470Sstevel@tonic-gate } 15480Sstevel@tonic-gate return (err); 15490Sstevel@tonic-gate } 15500Sstevel@tonic-gate 15510Sstevel@tonic-gate /* 15520Sstevel@tonic-gate * Return all the pages from [off..off+len] in given file 15530Sstevel@tonic-gate */ 1554*5331Samw /* ARGSUSED */ 15550Sstevel@tonic-gate static int 15560Sstevel@tonic-gate pcfs_getpage( 15570Sstevel@tonic-gate struct vnode *vp, 15580Sstevel@tonic-gate offset_t off, 15590Sstevel@tonic-gate size_t len, 15600Sstevel@tonic-gate uint_t *protp, 15610Sstevel@tonic-gate page_t *pl[], 15620Sstevel@tonic-gate size_t plsz, 15630Sstevel@tonic-gate struct seg *seg, 15640Sstevel@tonic-gate caddr_t addr, 15650Sstevel@tonic-gate enum seg_rw rw, 1566*5331Samw struct cred *cr, 1567*5331Samw caller_context_t *ct) 15680Sstevel@tonic-gate { 15690Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 15700Sstevel@tonic-gate int err; 15710Sstevel@tonic-gate 15720Sstevel@tonic-gate PC_DPRINTF0(6, "pcfs_getpage\n"); 15730Sstevel@tonic-gate if (err = pc_verify(fsp)) 15740Sstevel@tonic-gate return (err); 15750Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 15760Sstevel@tonic-gate return (ENOSYS); 15770Sstevel@tonic-gate ASSERT(off <= UINT32_MAX); 15780Sstevel@tonic-gate err = pc_lockfs(fsp, 0, 0); 15790Sstevel@tonic-gate if (err) 15800Sstevel@tonic-gate return (err); 15810Sstevel@tonic-gate if (protp != NULL) 15820Sstevel@tonic-gate *protp = PROT_ALL; 15830Sstevel@tonic-gate 15840Sstevel@tonic-gate ASSERT((off & PAGEOFFSET) == 0); 15850Sstevel@tonic-gate if (len <= PAGESIZE) { 15860Sstevel@tonic-gate err = pcfs_getapage(vp, off, len, protp, pl, 15870Sstevel@tonic-gate plsz, seg, addr, rw, cr); 15880Sstevel@tonic-gate } else { 15890Sstevel@tonic-gate err = pvn_getpages(pcfs_getapage, vp, off, 15900Sstevel@tonic-gate len, protp, pl, plsz, seg, addr, rw, cr); 15910Sstevel@tonic-gate } 15920Sstevel@tonic-gate pc_unlockfs(fsp); 15930Sstevel@tonic-gate return (err); 15940Sstevel@tonic-gate } 15950Sstevel@tonic-gate 15960Sstevel@tonic-gate 15970Sstevel@tonic-gate /* 15980Sstevel@tonic-gate * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE} 15990Sstevel@tonic-gate * If len == 0, do from off to EOF. 16000Sstevel@tonic-gate * 16010Sstevel@tonic-gate * The normal cases should be len == 0 & off == 0 (entire vp list), 16020Sstevel@tonic-gate * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE 16030Sstevel@tonic-gate * (from pageout). 16040Sstevel@tonic-gate * 16050Sstevel@tonic-gate */ 16060Sstevel@tonic-gate /*ARGSUSED*/ 16070Sstevel@tonic-gate static int 16080Sstevel@tonic-gate pcfs_putpage( 16090Sstevel@tonic-gate struct vnode *vp, 16100Sstevel@tonic-gate offset_t off, 16110Sstevel@tonic-gate size_t len, 16120Sstevel@tonic-gate int flags, 1613*5331Samw struct cred *cr, 1614*5331Samw caller_context_t *ct) 16150Sstevel@tonic-gate { 16160Sstevel@tonic-gate struct pcnode *pcp; 16170Sstevel@tonic-gate page_t *pp; 16180Sstevel@tonic-gate struct pcfs *fsp; 16190Sstevel@tonic-gate u_offset_t io_off; 16200Sstevel@tonic-gate size_t io_len; 16210Sstevel@tonic-gate offset_t eoff; 16220Sstevel@tonic-gate int err; 16230Sstevel@tonic-gate 16242720Sfrankho /* 16252720Sfrankho * If the filesystem was umounted by force, return immediately. 16262720Sfrankho */ 16272720Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 16282720Sfrankho return (EIO); 16292720Sfrankho 16300Sstevel@tonic-gate PC_DPRINTF1(6, "pcfs_putpage vp=0x%p\n", (void *)vp); 16310Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 16320Sstevel@tonic-gate return (ENOSYS); 16330Sstevel@tonic-gate 16340Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 16350Sstevel@tonic-gate 16360Sstevel@tonic-gate if (err = pc_verify(fsp)) 16370Sstevel@tonic-gate return (err); 16380Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) { 16390Sstevel@tonic-gate PC_DPRINTF1(3, "pcfs_putpage NULL vp=0x%p\n", (void *)vp); 16400Sstevel@tonic-gate return (EIO); 16410Sstevel@tonic-gate } 16422972Sfrankho if (pcp->pc_flags & PC_INVAL) 16432972Sfrankho return (EIO); 16440Sstevel@tonic-gate 16450Sstevel@tonic-gate if (curproc == proc_pageout) { 16460Sstevel@tonic-gate /* 16470Sstevel@tonic-gate * XXX - This is a quick hack to avoid blocking 16480Sstevel@tonic-gate * pageout. Also to avoid pcfs_getapage deadlocking 16490Sstevel@tonic-gate * with putpage when memory is running out, 16500Sstevel@tonic-gate * since we only have one global lock and we don't 16510Sstevel@tonic-gate * support async putpage. 16520Sstevel@tonic-gate * It should be fixed someday. 16530Sstevel@tonic-gate * 16540Sstevel@tonic-gate * Interestingly, this used to be a test of NOMEMWAIT(). 16550Sstevel@tonic-gate * We only ever got here once pcfs started supporting 16560Sstevel@tonic-gate * NFS sharing, and then only because the NFS server 16570Sstevel@tonic-gate * threads seem to do writes in sched's process context. 16580Sstevel@tonic-gate * Since everyone else seems to just care about pageout, 16590Sstevel@tonic-gate * the test was changed to look for pageout directly. 16600Sstevel@tonic-gate */ 16610Sstevel@tonic-gate return (ENOMEM); 16620Sstevel@tonic-gate } 16630Sstevel@tonic-gate 16640Sstevel@tonic-gate ASSERT(off <= UINT32_MAX); 16650Sstevel@tonic-gate 16660Sstevel@tonic-gate flags &= ~B_ASYNC; /* XXX should fix this later */ 16670Sstevel@tonic-gate 16680Sstevel@tonic-gate err = pc_lockfs(fsp, 0, 0); 16690Sstevel@tonic-gate if (err) 16700Sstevel@tonic-gate return (err); 16710Sstevel@tonic-gate if (!vn_has_cached_data(vp) || off >= pcp->pc_size) { 16720Sstevel@tonic-gate pc_unlockfs(fsp); 16730Sstevel@tonic-gate return (0); 16740Sstevel@tonic-gate } 16750Sstevel@tonic-gate 16760Sstevel@tonic-gate if (len == 0) { 16770Sstevel@tonic-gate /* 16780Sstevel@tonic-gate * Search the entire vp list for pages >= off 16790Sstevel@tonic-gate */ 16800Sstevel@tonic-gate err = pvn_vplist_dirty(vp, off, 16810Sstevel@tonic-gate pcfs_putapage, flags, cr); 16820Sstevel@tonic-gate } else { 16830Sstevel@tonic-gate eoff = off + len; 16840Sstevel@tonic-gate 16850Sstevel@tonic-gate for (io_off = off; io_off < eoff && 16860Sstevel@tonic-gate io_off < pcp->pc_size; io_off += io_len) { 16870Sstevel@tonic-gate /* 16880Sstevel@tonic-gate * If we are not invalidating, synchronously 16890Sstevel@tonic-gate * freeing or writing pages use the routine 16900Sstevel@tonic-gate * page_lookup_nowait() to prevent reclaiming 16910Sstevel@tonic-gate * them from the free list. 16920Sstevel@tonic-gate */ 16930Sstevel@tonic-gate if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) { 16940Sstevel@tonic-gate pp = page_lookup(vp, io_off, 16954723Sksn (flags & (B_INVAL | B_FREE)) ? 16964723Sksn SE_EXCL : SE_SHARED); 16970Sstevel@tonic-gate } else { 16980Sstevel@tonic-gate pp = page_lookup_nowait(vp, io_off, 16994723Sksn (flags & B_FREE) ? SE_EXCL : SE_SHARED); 17000Sstevel@tonic-gate } 17010Sstevel@tonic-gate 17020Sstevel@tonic-gate if (pp == NULL || pvn_getdirty(pp, flags) == 0) 17030Sstevel@tonic-gate io_len = PAGESIZE; 17040Sstevel@tonic-gate else { 17050Sstevel@tonic-gate err = pcfs_putapage(vp, pp, &io_off, &io_len, 17064723Sksn flags, cr); 17070Sstevel@tonic-gate if (err != 0) 17080Sstevel@tonic-gate break; 17090Sstevel@tonic-gate /* 17100Sstevel@tonic-gate * "io_off" and "io_len" are returned as 17110Sstevel@tonic-gate * the range of pages we actually wrote. 17120Sstevel@tonic-gate * This allows us to skip ahead more quickly 17130Sstevel@tonic-gate * since several pages may've been dealt 17140Sstevel@tonic-gate * with by this iteration of the loop. 17150Sstevel@tonic-gate */ 17160Sstevel@tonic-gate } 17170Sstevel@tonic-gate } 17180Sstevel@tonic-gate } 17190Sstevel@tonic-gate if (err == 0 && (flags & B_INVAL) && 17200Sstevel@tonic-gate off == 0 && len == 0 && vn_has_cached_data(vp)) { 17210Sstevel@tonic-gate /* 17220Sstevel@tonic-gate * If doing "invalidation", make sure that 17230Sstevel@tonic-gate * all pages on the vnode list are actually 17240Sstevel@tonic-gate * gone. 17250Sstevel@tonic-gate */ 17260Sstevel@tonic-gate cmn_err(CE_PANIC, 17274723Sksn "pcfs_putpage: B_INVAL, pages not gone"); 17280Sstevel@tonic-gate } else if (err) { 17290Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_putpage err=%d\n", err); 17300Sstevel@tonic-gate } 17310Sstevel@tonic-gate pc_unlockfs(fsp); 17320Sstevel@tonic-gate return (err); 17330Sstevel@tonic-gate } 17340Sstevel@tonic-gate 17350Sstevel@tonic-gate /* 17360Sstevel@tonic-gate * Write out a single page, possibly klustering adjacent dirty pages. 17370Sstevel@tonic-gate */ 17380Sstevel@tonic-gate /*ARGSUSED*/ 17390Sstevel@tonic-gate int 17400Sstevel@tonic-gate pcfs_putapage( 17410Sstevel@tonic-gate struct vnode *vp, 17420Sstevel@tonic-gate page_t *pp, 17430Sstevel@tonic-gate u_offset_t *offp, 17440Sstevel@tonic-gate size_t *lenp, 17450Sstevel@tonic-gate int flags, 17460Sstevel@tonic-gate struct cred *cr) 17470Sstevel@tonic-gate { 17480Sstevel@tonic-gate struct pcnode *pcp; 17490Sstevel@tonic-gate struct pcfs *fsp; 17500Sstevel@tonic-gate struct vnode *devvp; 17510Sstevel@tonic-gate size_t io_len; 17520Sstevel@tonic-gate daddr_t bn; 17530Sstevel@tonic-gate u_offset_t lbn, lbnoff, xferoffset; 17540Sstevel@tonic-gate uint_t pgoff, xfersize; 17550Sstevel@tonic-gate int err = 0; 17560Sstevel@tonic-gate u_offset_t io_off; 17570Sstevel@tonic-gate 17580Sstevel@tonic-gate pcp = VTOPC(vp); 17590Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 17600Sstevel@tonic-gate devvp = fsp->pcfs_devvp; 17610Sstevel@tonic-gate 17620Sstevel@tonic-gate /* 17630Sstevel@tonic-gate * If the modified time on the inode has not already been 17640Sstevel@tonic-gate * set elsewhere (e.g. for write/setattr) and this is not 17650Sstevel@tonic-gate * a call from msync (B_FORCE) we set the time now. 17660Sstevel@tonic-gate * This gives us approximate modified times for mmap'ed files 17670Sstevel@tonic-gate * which are modified via stores in the user address space. 17680Sstevel@tonic-gate */ 17690Sstevel@tonic-gate if ((pcp->pc_flags & PC_MOD) == 0 || (flags & B_FORCE)) { 17700Sstevel@tonic-gate pcp->pc_flags |= PC_MOD; 17715121Sfrankho pc_mark_mod(fsp, pcp); 17720Sstevel@tonic-gate } 17730Sstevel@tonic-gate pp = pvn_write_kluster(vp, pp, &io_off, &io_len, pp->p_offset, 17740Sstevel@tonic-gate PAGESIZE, flags); 17750Sstevel@tonic-gate 17760Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_IRRECOV) { 17770Sstevel@tonic-gate goto out; 17780Sstevel@tonic-gate } 17790Sstevel@tonic-gate 17800Sstevel@tonic-gate PC_DPRINTF1(7, "pc_putpage writing dirty page off=%llu\n", io_off); 17810Sstevel@tonic-gate 17820Sstevel@tonic-gate lbn = pc_lblkno(fsp, io_off); 17830Sstevel@tonic-gate lbnoff = io_off & ~(fsp->pcfs_clsize - 1); 17840Sstevel@tonic-gate xferoffset = io_off & ~(fsp->pcfs_secsize - 1); 17850Sstevel@tonic-gate 17860Sstevel@tonic-gate for (pgoff = 0; pgoff < io_len && xferoffset < pcp->pc_size; 17870Sstevel@tonic-gate pgoff += xfersize, 17880Sstevel@tonic-gate lbn += howmany(xfersize, fsp->pcfs_clsize), 17890Sstevel@tonic-gate lbnoff += xfersize, xferoffset += xfersize) { 17900Sstevel@tonic-gate 17910Sstevel@tonic-gate struct buf *bp; 17920Sstevel@tonic-gate int err1; 17930Sstevel@tonic-gate 17940Sstevel@tonic-gate /* 17950Sstevel@tonic-gate * write as many contiguous blocks as possible from this page 17960Sstevel@tonic-gate */ 17970Sstevel@tonic-gate xfersize = io_len - pgoff; 17980Sstevel@tonic-gate err1 = pc_bmap(pcp, (daddr_t)lbn, &bn, &xfersize); 17990Sstevel@tonic-gate if (err1) { 18000Sstevel@tonic-gate err = err1; 18010Sstevel@tonic-gate goto out; 18020Sstevel@tonic-gate } 18030Sstevel@tonic-gate bp = pageio_setup(pp, xfersize, devvp, B_WRITE | flags); 18040Sstevel@tonic-gate bp->b_edev = devvp->v_rdev; 18050Sstevel@tonic-gate bp->b_dev = cmpdev(devvp->v_rdev); 18065121Sfrankho bp->b_blkno = bn + btodt(xferoffset - lbnoff); 18070Sstevel@tonic-gate bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff; 18080Sstevel@tonic-gate bp->b_file = vp; 18090Sstevel@tonic-gate bp->b_offset = (offset_t)(io_off + pgoff); 18100Sstevel@tonic-gate 18110Sstevel@tonic-gate (void) bdev_strategy(bp); 18120Sstevel@tonic-gate 18130Sstevel@tonic-gate lwp_stat_update(LWP_STAT_OUBLK, 1); 18140Sstevel@tonic-gate 18150Sstevel@tonic-gate if (err == 0) 18160Sstevel@tonic-gate err = biowait(bp); 18170Sstevel@tonic-gate else 18180Sstevel@tonic-gate (void) biowait(bp); 18190Sstevel@tonic-gate pageio_done(bp); 18200Sstevel@tonic-gate } 18210Sstevel@tonic-gate pvn_write_done(pp, ((err) ? B_ERROR : 0) | B_WRITE | flags); 18220Sstevel@tonic-gate pp = NULL; 18230Sstevel@tonic-gate 18240Sstevel@tonic-gate out: 18250Sstevel@tonic-gate if ((fsp->pcfs_flags & PCFS_IRRECOV) && pp != NULL) { 18260Sstevel@tonic-gate pvn_write_done(pp, B_WRITE | flags); 18270Sstevel@tonic-gate } else if (err != 0 && pp != NULL) { 18280Sstevel@tonic-gate pvn_write_done(pp, B_ERROR | B_WRITE | flags); 18290Sstevel@tonic-gate } 18300Sstevel@tonic-gate 18310Sstevel@tonic-gate if (offp) 18320Sstevel@tonic-gate *offp = io_off; 18330Sstevel@tonic-gate if (lenp) 18340Sstevel@tonic-gate *lenp = io_len; 18350Sstevel@tonic-gate PC_DPRINTF4(4, "pcfs_putapage: vp=%p pp=%p off=%lld len=%lu\n", 18360Sstevel@tonic-gate (void *)vp, (void *)pp, io_off, io_len); 18370Sstevel@tonic-gate if (err) { 18380Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_putapage err=%d", err); 18390Sstevel@tonic-gate } 18400Sstevel@tonic-gate return (err); 18410Sstevel@tonic-gate } 18420Sstevel@tonic-gate 18430Sstevel@tonic-gate /*ARGSUSED*/ 18440Sstevel@tonic-gate static int 18450Sstevel@tonic-gate pcfs_map( 18460Sstevel@tonic-gate struct vnode *vp, 18470Sstevel@tonic-gate offset_t off, 18480Sstevel@tonic-gate struct as *as, 18490Sstevel@tonic-gate caddr_t *addrp, 18500Sstevel@tonic-gate size_t len, 18510Sstevel@tonic-gate uchar_t prot, 18520Sstevel@tonic-gate uchar_t maxprot, 18530Sstevel@tonic-gate uint_t flags, 1854*5331Samw struct cred *cr, 1855*5331Samw caller_context_t *ct) 18560Sstevel@tonic-gate { 18570Sstevel@tonic-gate struct segvn_crargs vn_a; 18580Sstevel@tonic-gate int error; 18590Sstevel@tonic-gate 18600Sstevel@tonic-gate PC_DPRINTF0(6, "pcfs_map\n"); 18610Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 18620Sstevel@tonic-gate return (ENOSYS); 18630Sstevel@tonic-gate 18640Sstevel@tonic-gate if (off > UINT32_MAX || off + len > UINT32_MAX) 18650Sstevel@tonic-gate return (ENXIO); 18660Sstevel@tonic-gate 18670Sstevel@tonic-gate as_rangelock(as); 18680Sstevel@tonic-gate if ((flags & MAP_FIXED) == 0) { 18690Sstevel@tonic-gate map_addr(addrp, len, off, 1, flags); 18700Sstevel@tonic-gate if (*addrp == NULL) { 18710Sstevel@tonic-gate as_rangeunlock(as); 18720Sstevel@tonic-gate return (ENOMEM); 18730Sstevel@tonic-gate } 18740Sstevel@tonic-gate } else { 18750Sstevel@tonic-gate /* 18760Sstevel@tonic-gate * User specified address - blow away any previous mappings 18770Sstevel@tonic-gate */ 18780Sstevel@tonic-gate (void) as_unmap(as, *addrp, len); 18790Sstevel@tonic-gate } 18800Sstevel@tonic-gate 18810Sstevel@tonic-gate vn_a.vp = vp; 18820Sstevel@tonic-gate vn_a.offset = off; 18830Sstevel@tonic-gate vn_a.type = flags & MAP_TYPE; 18840Sstevel@tonic-gate vn_a.prot = prot; 18850Sstevel@tonic-gate vn_a.maxprot = maxprot; 18860Sstevel@tonic-gate vn_a.flags = flags & ~MAP_TYPE; 18870Sstevel@tonic-gate vn_a.cred = cr; 18880Sstevel@tonic-gate vn_a.amp = NULL; 18890Sstevel@tonic-gate vn_a.szc = 0; 18900Sstevel@tonic-gate vn_a.lgrp_mem_policy_flags = 0; 18910Sstevel@tonic-gate 18920Sstevel@tonic-gate error = as_map(as, *addrp, len, segvn_create, &vn_a); 18930Sstevel@tonic-gate as_rangeunlock(as); 18940Sstevel@tonic-gate return (error); 18950Sstevel@tonic-gate } 18960Sstevel@tonic-gate 18970Sstevel@tonic-gate /* ARGSUSED */ 18980Sstevel@tonic-gate static int 18990Sstevel@tonic-gate pcfs_seek( 19000Sstevel@tonic-gate struct vnode *vp, 19010Sstevel@tonic-gate offset_t ooff, 1902*5331Samw offset_t *noffp, 1903*5331Samw caller_context_t *ct) 19040Sstevel@tonic-gate { 19050Sstevel@tonic-gate if (*noffp < 0) 19060Sstevel@tonic-gate return (EINVAL); 19070Sstevel@tonic-gate else if (*noffp > MAXOFFSET_T) 19080Sstevel@tonic-gate return (EINVAL); 19090Sstevel@tonic-gate else 19100Sstevel@tonic-gate return (0); 19110Sstevel@tonic-gate } 19120Sstevel@tonic-gate 19130Sstevel@tonic-gate /* ARGSUSED */ 19140Sstevel@tonic-gate static int 19150Sstevel@tonic-gate pcfs_addmap( 19160Sstevel@tonic-gate struct vnode *vp, 19170Sstevel@tonic-gate offset_t off, 19180Sstevel@tonic-gate struct as *as, 19190Sstevel@tonic-gate caddr_t addr, 19200Sstevel@tonic-gate size_t len, 19210Sstevel@tonic-gate uchar_t prot, 19220Sstevel@tonic-gate uchar_t maxprot, 19230Sstevel@tonic-gate uint_t flags, 1924*5331Samw struct cred *cr, 1925*5331Samw caller_context_t *ct) 19260Sstevel@tonic-gate { 19270Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 19280Sstevel@tonic-gate return (ENOSYS); 19290Sstevel@tonic-gate return (0); 19300Sstevel@tonic-gate } 19310Sstevel@tonic-gate 19320Sstevel@tonic-gate /*ARGSUSED*/ 19330Sstevel@tonic-gate static int 19340Sstevel@tonic-gate pcfs_delmap( 19350Sstevel@tonic-gate struct vnode *vp, 19360Sstevel@tonic-gate offset_t off, 19370Sstevel@tonic-gate struct as *as, 19380Sstevel@tonic-gate caddr_t addr, 19390Sstevel@tonic-gate size_t len, 19400Sstevel@tonic-gate uint_t prot, 19410Sstevel@tonic-gate uint_t maxprot, 19420Sstevel@tonic-gate uint_t flags, 1943*5331Samw struct cred *cr, 1944*5331Samw caller_context_t *ct) 19450Sstevel@tonic-gate { 19460Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 19470Sstevel@tonic-gate return (ENOSYS); 19480Sstevel@tonic-gate return (0); 19490Sstevel@tonic-gate } 19500Sstevel@tonic-gate 19510Sstevel@tonic-gate /* 19520Sstevel@tonic-gate * POSIX pathconf() support. 19530Sstevel@tonic-gate */ 19540Sstevel@tonic-gate /* ARGSUSED */ 19550Sstevel@tonic-gate static int 19560Sstevel@tonic-gate pcfs_pathconf( 19570Sstevel@tonic-gate struct vnode *vp, 19580Sstevel@tonic-gate int cmd, 19590Sstevel@tonic-gate ulong_t *valp, 1960*5331Samw struct cred *cr, 1961*5331Samw caller_context_t *ct) 19620Sstevel@tonic-gate { 19630Sstevel@tonic-gate ulong_t val; 19640Sstevel@tonic-gate int error = 0; 19650Sstevel@tonic-gate struct statvfs64 vfsbuf; 19660Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 19670Sstevel@tonic-gate 19680Sstevel@tonic-gate switch (cmd) { 19690Sstevel@tonic-gate 19700Sstevel@tonic-gate case _PC_LINK_MAX: 19710Sstevel@tonic-gate val = 1; 19720Sstevel@tonic-gate break; 19730Sstevel@tonic-gate 19740Sstevel@tonic-gate case _PC_MAX_CANON: 19750Sstevel@tonic-gate val = MAX_CANON; 19760Sstevel@tonic-gate break; 19770Sstevel@tonic-gate 19780Sstevel@tonic-gate case _PC_MAX_INPUT: 19790Sstevel@tonic-gate val = MAX_INPUT; 19800Sstevel@tonic-gate break; 19810Sstevel@tonic-gate 19820Sstevel@tonic-gate case _PC_NAME_MAX: 19830Sstevel@tonic-gate bzero(&vfsbuf, sizeof (vfsbuf)); 19840Sstevel@tonic-gate if (error = VFS_STATVFS(vp->v_vfsp, &vfsbuf)) 19850Sstevel@tonic-gate break; 19860Sstevel@tonic-gate val = vfsbuf.f_namemax; 19870Sstevel@tonic-gate break; 19880Sstevel@tonic-gate 19890Sstevel@tonic-gate case _PC_PATH_MAX: 19900Sstevel@tonic-gate case _PC_SYMLINK_MAX: 19910Sstevel@tonic-gate val = PCMAXPATHLEN; 19920Sstevel@tonic-gate break; 19930Sstevel@tonic-gate 19940Sstevel@tonic-gate case _PC_PIPE_BUF: 19950Sstevel@tonic-gate val = PIPE_BUF; 19960Sstevel@tonic-gate break; 19970Sstevel@tonic-gate 19980Sstevel@tonic-gate case _PC_NO_TRUNC: 19990Sstevel@tonic-gate val = (ulong_t)-1; /* Will truncate long file name */ 20000Sstevel@tonic-gate break; 20010Sstevel@tonic-gate 20020Sstevel@tonic-gate case _PC_VDISABLE: 20030Sstevel@tonic-gate val = _POSIX_VDISABLE; 20040Sstevel@tonic-gate break; 20050Sstevel@tonic-gate 20060Sstevel@tonic-gate case _PC_CHOWN_RESTRICTED: 20070Sstevel@tonic-gate if (rstchown) 20080Sstevel@tonic-gate val = rstchown; /* chown restricted enabled */ 20090Sstevel@tonic-gate else 20100Sstevel@tonic-gate val = (ulong_t)-1; 20110Sstevel@tonic-gate break; 20120Sstevel@tonic-gate 20130Sstevel@tonic-gate case _PC_ACL_ENABLED: 20140Sstevel@tonic-gate val = 0; 20150Sstevel@tonic-gate break; 20160Sstevel@tonic-gate 20170Sstevel@tonic-gate case _PC_FILESIZEBITS: 20180Sstevel@tonic-gate /* 20190Sstevel@tonic-gate * Both FAT16 and FAT32 support 4GB - 1 byte for file size. 20200Sstevel@tonic-gate * FAT12 can only go up to the maximum filesystem capacity 20210Sstevel@tonic-gate * which is ~509MB. 20220Sstevel@tonic-gate */ 20230Sstevel@tonic-gate val = IS_FAT12(fsp) ? 30 : 33; 20240Sstevel@tonic-gate break; 20250Sstevel@tonic-gate default: 20260Sstevel@tonic-gate error = EINVAL; 20270Sstevel@tonic-gate break; 20280Sstevel@tonic-gate } 20290Sstevel@tonic-gate 20300Sstevel@tonic-gate if (error == 0) 20310Sstevel@tonic-gate *valp = val; 20320Sstevel@tonic-gate return (error); 20330Sstevel@tonic-gate } 20340Sstevel@tonic-gate 20350Sstevel@tonic-gate /* ARGSUSED */ 20360Sstevel@tonic-gate static int 20370Sstevel@tonic-gate pcfs_space( 20380Sstevel@tonic-gate struct vnode *vp, 20390Sstevel@tonic-gate int cmd, 20400Sstevel@tonic-gate struct flock64 *bfp, 20410Sstevel@tonic-gate int flag, 20420Sstevel@tonic-gate offset_t offset, 20430Sstevel@tonic-gate cred_t *cr, 20440Sstevel@tonic-gate caller_context_t *ct) 20450Sstevel@tonic-gate { 20460Sstevel@tonic-gate struct vattr vattr; 20470Sstevel@tonic-gate int error; 20480Sstevel@tonic-gate 20490Sstevel@tonic-gate if (cmd != F_FREESP) 20500Sstevel@tonic-gate return (EINVAL); 20510Sstevel@tonic-gate 20520Sstevel@tonic-gate if ((error = convoff(vp, bfp, 0, offset)) == 0) { 20530Sstevel@tonic-gate if ((bfp->l_start > UINT32_MAX) || (bfp->l_len > UINT32_MAX)) 20540Sstevel@tonic-gate return (EFBIG); 20550Sstevel@tonic-gate /* 20560Sstevel@tonic-gate * we only support the special case of l_len == 0, 20570Sstevel@tonic-gate * meaning free to end of file at this moment. 20580Sstevel@tonic-gate */ 20590Sstevel@tonic-gate if (bfp->l_len != 0) 20600Sstevel@tonic-gate return (EINVAL); 20610Sstevel@tonic-gate vattr.va_mask = AT_SIZE; 20620Sstevel@tonic-gate vattr.va_size = bfp->l_start; 2063*5331Samw error = VOP_SETATTR(vp, (vattr_t *)&vattr, 0, cr, ct); 20640Sstevel@tonic-gate } 20650Sstevel@tonic-gate return (error); 20660Sstevel@tonic-gate } 20670Sstevel@tonic-gate 20680Sstevel@tonic-gate /* 20690Sstevel@tonic-gate * Break up 'len' chars from 'buf' into a long file name chunk. 20700Sstevel@tonic-gate * Pad with '0xff' to make Norton Disk Doctor and Microsoft ScanDisk happy. 20710Sstevel@tonic-gate */ 20720Sstevel@tonic-gate void 20730Sstevel@tonic-gate set_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int len) 20740Sstevel@tonic-gate { 20750Sstevel@tonic-gate int i; 20760Sstevel@tonic-gate 20774723Sksn ASSERT(buf != NULL); 20780Sstevel@tonic-gate 20790Sstevel@tonic-gate for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2) { 20800Sstevel@tonic-gate if (len > 0) { 20814723Sksn ep->pcdl_firstfilename[i] = *buf++; 20824723Sksn ep->pcdl_firstfilename[i + 1] = *buf++; 20834723Sksn len -= 2; 20840Sstevel@tonic-gate } else { 20850Sstevel@tonic-gate ep->pcdl_firstfilename[i] = (uchar_t)0xff; 20864723Sksn ep->pcdl_firstfilename[i + 1] = (uchar_t)0xff; 20870Sstevel@tonic-gate } 20880Sstevel@tonic-gate } 20890Sstevel@tonic-gate 20900Sstevel@tonic-gate for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2) { 20910Sstevel@tonic-gate if (len > 0) { 20924723Sksn ep->pcdl_secondfilename[i] = *buf++; 20934723Sksn ep->pcdl_secondfilename[i + 1] = *buf++; 20944723Sksn len -= 2; 20950Sstevel@tonic-gate } else { 20960Sstevel@tonic-gate ep->pcdl_secondfilename[i] = (uchar_t)0xff; 20974723Sksn ep->pcdl_secondfilename[i + 1] = (uchar_t)0xff; 20980Sstevel@tonic-gate } 20990Sstevel@tonic-gate } 21000Sstevel@tonic-gate for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2) { 21010Sstevel@tonic-gate if (len > 0) { 21024723Sksn ep->pcdl_thirdfilename[i] = *buf++; 21034723Sksn ep->pcdl_thirdfilename[i + 1] = *buf++; 21044723Sksn len -= 2; 21050Sstevel@tonic-gate } else { 21060Sstevel@tonic-gate ep->pcdl_thirdfilename[i] = (uchar_t)0xff; 21074723Sksn ep->pcdl_thirdfilename[i + 1] = (uchar_t)0xff; 21080Sstevel@tonic-gate } 21090Sstevel@tonic-gate } 21100Sstevel@tonic-gate } 21110Sstevel@tonic-gate 21120Sstevel@tonic-gate /* 21130Sstevel@tonic-gate * Extract the characters from the long filename chunk into 'buf'. 21140Sstevel@tonic-gate * Return the number of characters extracted. 21150Sstevel@tonic-gate */ 21160Sstevel@tonic-gate static int 21170Sstevel@tonic-gate get_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int foldcase) 21180Sstevel@tonic-gate { 21190Sstevel@tonic-gate char *tmp = buf; 21200Sstevel@tonic-gate int i; 21210Sstevel@tonic-gate 21224723Sksn /* Copy all the names, no filtering now */ 21234723Sksn 21244723Sksn for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2, tmp += 2) { 21254723Sksn *tmp = ep->pcdl_firstfilename[i]; 21264723Sksn *(tmp + 1) = ep->pcdl_firstfilename[i + 1]; 21274723Sksn 21284723Sksn if ((*tmp == '\0') && (*(tmp+1) == '\0')) 21290Sstevel@tonic-gate return (tmp - buf); 21304723Sksn if (*(tmp + 1) == '\0' && foldcase) { 21314723Sksn *tmp = toupper(*tmp); 21324723Sksn } 21330Sstevel@tonic-gate } 21344723Sksn for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2, tmp += 2) { 21354723Sksn *tmp = ep->pcdl_secondfilename[i]; 21364723Sksn *(tmp + 1) = ep->pcdl_secondfilename[i + 1]; 21374723Sksn 21384723Sksn if ((*tmp == '\0') && (*(tmp+1) == '\0')) 21390Sstevel@tonic-gate return (tmp - buf); 21404723Sksn if (*(tmp + 1) == '\0' && foldcase) { 21414723Sksn *tmp = toupper(*tmp); 21424723Sksn } 21430Sstevel@tonic-gate } 21444723Sksn for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2, tmp += 2) { 21454723Sksn *tmp = ep->pcdl_thirdfilename[i]; 21464723Sksn *(tmp + 1) = ep->pcdl_thirdfilename[i + 1]; 21474723Sksn 21484723Sksn if ((*tmp == '\0') && (*(tmp+1) == '\0')) 21490Sstevel@tonic-gate return (tmp - buf); 21504723Sksn if (*(tmp + 1) == '\0' && foldcase) { 21514723Sksn *tmp = toupper(*tmp); 21524723Sksn } 21530Sstevel@tonic-gate } 21540Sstevel@tonic-gate return (tmp - buf); 21550Sstevel@tonic-gate } 21560Sstevel@tonic-gate 21570Sstevel@tonic-gate 21580Sstevel@tonic-gate /* 21590Sstevel@tonic-gate * Checksum the passed in short filename. 21600Sstevel@tonic-gate * This is used to validate each component of the long name to make 21610Sstevel@tonic-gate * sure the long name is valid (it hasn't been "detached" from the 21620Sstevel@tonic-gate * short filename). This algorithm was found in FreeBSD. 21630Sstevel@tonic-gate * (sys/fs/msdosfs/msdosfs_conv.c:winChksum(), Wolfgang Solfrank) 21640Sstevel@tonic-gate */ 21650Sstevel@tonic-gate 21660Sstevel@tonic-gate uchar_t 21670Sstevel@tonic-gate pc_checksum_long_fn(char *name, char *ext) 21680Sstevel@tonic-gate { 21690Sstevel@tonic-gate uchar_t c; 21700Sstevel@tonic-gate char b[11]; 21710Sstevel@tonic-gate 21720Sstevel@tonic-gate bcopy(name, b, 8); 21730Sstevel@tonic-gate bcopy(ext, b+8, 3); 21740Sstevel@tonic-gate 21750Sstevel@tonic-gate c = b[0]; 21760Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[1]; 21770Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[2]; 21780Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[3]; 21790Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[4]; 21800Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[5]; 21810Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[6]; 21820Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[7]; 21830Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[8]; 21840Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[9]; 21850Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[10]; 21860Sstevel@tonic-gate 21870Sstevel@tonic-gate return (c); 21880Sstevel@tonic-gate } 21890Sstevel@tonic-gate 21900Sstevel@tonic-gate /* 21910Sstevel@tonic-gate * Read a chunk of long filename entries into 'namep'. 21920Sstevel@tonic-gate * Return with offset pointing to short entry (on success), or next 21930Sstevel@tonic-gate * entry to read (if this wasn't a valid lfn really). 21940Sstevel@tonic-gate * Uses the passed-in buffer if it can, otherwise kmem_allocs() room for 21950Sstevel@tonic-gate * a long filename. 21960Sstevel@tonic-gate * 21970Sstevel@tonic-gate * Can also be called with a NULL namep, in which case it just returns 21980Sstevel@tonic-gate * whether this was really a valid long filename and consumes it 21990Sstevel@tonic-gate * (used by pc_dirempty()). 22000Sstevel@tonic-gate */ 22010Sstevel@tonic-gate int 22020Sstevel@tonic-gate pc_extract_long_fn(struct pcnode *pcp, char *namep, 22030Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp) 22040Sstevel@tonic-gate { 22050Sstevel@tonic-gate struct pcdir *ep = *epp; 22060Sstevel@tonic-gate struct pcdir_lfn *lep = (struct pcdir_lfn *)ep; 22070Sstevel@tonic-gate struct vnode *dvp = PCTOV(pcp); 22080Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 22090Sstevel@tonic-gate char *lfn; 22100Sstevel@tonic-gate char *lfn_base; 22110Sstevel@tonic-gate int boff; 22120Sstevel@tonic-gate int i, cs; 22135121Sfrankho char *buf; 22140Sstevel@tonic-gate uchar_t cksum; 22155121Sfrankho int detached = 0; 22160Sstevel@tonic-gate int error = 0; 22170Sstevel@tonic-gate int foldcase; 22184723Sksn int count = 0; 22195121Sfrankho size_t u16l = 0, u8l = 0; 22200Sstevel@tonic-gate 22210Sstevel@tonic-gate foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE); 22224723Sksn lfn_base = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP); 22234723Sksn lfn = lfn_base + PCMAXNAM_UTF16 - sizeof (uint16_t); 22240Sstevel@tonic-gate *lfn = '\0'; 22254723Sksn *(lfn + 1) = '\0'; 22260Sstevel@tonic-gate cksum = lep->pcdl_checksum; 22270Sstevel@tonic-gate 22284723Sksn buf = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP); 22290Sstevel@tonic-gate for (i = (lep->pcdl_ordinal & ~0xc0); i > 0; i--) { 22300Sstevel@tonic-gate /* read next block if necessary */ 22310Sstevel@tonic-gate boff = pc_blkoff(fsp, *offset); 22320Sstevel@tonic-gate if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) { 22330Sstevel@tonic-gate if (*bp != NULL) { 22340Sstevel@tonic-gate brelse(*bp); 22350Sstevel@tonic-gate *bp = NULL; 22360Sstevel@tonic-gate } 22370Sstevel@tonic-gate error = pc_blkatoff(pcp, *offset, bp, &ep); 22380Sstevel@tonic-gate if (error) { 22394723Sksn kmem_free(lfn_base, PCMAXNAM_UTF16); 22404723Sksn kmem_free(buf, PCMAXNAM_UTF16); 22410Sstevel@tonic-gate return (error); 22420Sstevel@tonic-gate } 22430Sstevel@tonic-gate lep = (struct pcdir_lfn *)ep; 22440Sstevel@tonic-gate } 22450Sstevel@tonic-gate /* can this happen? Bad fs? */ 22460Sstevel@tonic-gate if (!PCDL_IS_LFN((struct pcdir *)lep)) { 22470Sstevel@tonic-gate detached = 1; 22480Sstevel@tonic-gate break; 22490Sstevel@tonic-gate } 22500Sstevel@tonic-gate if (cksum != lep->pcdl_checksum) 22510Sstevel@tonic-gate detached = 1; 22520Sstevel@tonic-gate /* process current entry */ 22530Sstevel@tonic-gate cs = get_long_fn_chunk(lep, buf, foldcase); 22544723Sksn count += cs; 22554723Sksn for (; cs > 0; cs--) { 22564723Sksn /* see if we underflow */ 22574723Sksn if (lfn >= lfn_base) 22584723Sksn *--lfn = buf[cs - 1]; 22594723Sksn else 22604723Sksn detached = 1; 22610Sstevel@tonic-gate } 22620Sstevel@tonic-gate lep++; 22630Sstevel@tonic-gate *offset += sizeof (struct pcdir); 22640Sstevel@tonic-gate } 22654723Sksn kmem_free(buf, PCMAXNAM_UTF16); 22660Sstevel@tonic-gate /* read next block if necessary */ 22670Sstevel@tonic-gate boff = pc_blkoff(fsp, *offset); 22680Sstevel@tonic-gate ep = (struct pcdir *)lep; 22690Sstevel@tonic-gate if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) { 22700Sstevel@tonic-gate if (*bp != NULL) { 22710Sstevel@tonic-gate brelse(*bp); 22720Sstevel@tonic-gate *bp = NULL; 22730Sstevel@tonic-gate } 22740Sstevel@tonic-gate error = pc_blkatoff(pcp, *offset, bp, &ep); 22750Sstevel@tonic-gate if (error) { 22764723Sksn kmem_free(lfn_base, PCMAXNAM_UTF16); 22770Sstevel@tonic-gate return (error); 22780Sstevel@tonic-gate } 22790Sstevel@tonic-gate } 22800Sstevel@tonic-gate /* should be on the short one */ 22810Sstevel@tonic-gate if (PCDL_IS_LFN(ep) || ((ep->pcd_filename[0] == PCD_UNUSED) || 22820Sstevel@tonic-gate (ep->pcd_filename[0] == PCD_ERASED))) { 22830Sstevel@tonic-gate detached = 1; 22840Sstevel@tonic-gate } 22850Sstevel@tonic-gate if (detached || 22860Sstevel@tonic-gate (cksum != pc_checksum_long_fn(ep->pcd_filename, ep->pcd_ext)) || 22874723Sksn !pc_valid_long_fn(lfn, 0)) { 22880Sstevel@tonic-gate /* 22890Sstevel@tonic-gate * process current entry again. This may end up another lfn 22900Sstevel@tonic-gate * or a short name. 22910Sstevel@tonic-gate */ 22920Sstevel@tonic-gate *epp = ep; 22934723Sksn kmem_free(lfn_base, PCMAXNAM_UTF16); 22940Sstevel@tonic-gate return (EINVAL); 22950Sstevel@tonic-gate } 22960Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) { 22970Sstevel@tonic-gate /* 22980Sstevel@tonic-gate * Don't display label because it may contain 22990Sstevel@tonic-gate * funny characters. 23000Sstevel@tonic-gate */ 23010Sstevel@tonic-gate *offset += sizeof (struct pcdir); 23020Sstevel@tonic-gate ep++; 23030Sstevel@tonic-gate *epp = ep; 23044723Sksn kmem_free(lfn_base, PCMAXNAM_UTF16); 23050Sstevel@tonic-gate return (EINVAL); 23060Sstevel@tonic-gate } 23070Sstevel@tonic-gate if (namep) { 23084723Sksn u16l = count / 2; 23094723Sksn u8l = PCMAXNAMLEN; 23104723Sksn error = uconv_u16tou8((const uint16_t *)lfn, &u16l, 23114723Sksn (uchar_t *)namep, &u8l, UCONV_IN_LITTLE_ENDIAN); 23124723Sksn /* 23134723Sksn * uconv_u16tou8() will catch conversion errors including 23144723Sksn * the case where there is not enough room to write the 23154723Sksn * converted result and the u8l will never go over the given 23164723Sksn * PCMAXNAMLEN. 23174723Sksn */ 23184723Sksn if (error != 0) { 23194723Sksn kmem_free(lfn_base, PCMAXNAM_UTF16); 23204723Sksn return (EINVAL); 23214723Sksn } 23224723Sksn namep[u8l] = '\0'; 23230Sstevel@tonic-gate } 23244723Sksn kmem_free(lfn_base, PCMAXNAM_UTF16); 23250Sstevel@tonic-gate *epp = ep; 23260Sstevel@tonic-gate return (0); 23270Sstevel@tonic-gate } 23280Sstevel@tonic-gate /* 23290Sstevel@tonic-gate * Read a long filename into the pc_dirent structure and copy it out. 23300Sstevel@tonic-gate */ 23310Sstevel@tonic-gate int 23320Sstevel@tonic-gate pc_read_long_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld, 23330Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp) 23340Sstevel@tonic-gate { 23350Sstevel@tonic-gate struct pcdir *ep; 23360Sstevel@tonic-gate struct pcnode *pcp = VTOPC(dvp); 23370Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 23380Sstevel@tonic-gate offset_t uiooffset = uiop->uio_loffset; 23390Sstevel@tonic-gate int error = 0; 23400Sstevel@tonic-gate offset_t oldoffset; 23410Sstevel@tonic-gate 23420Sstevel@tonic-gate oldoffset = *offset; 23430Sstevel@tonic-gate error = pc_extract_long_fn(pcp, ld->d_name, epp, offset, bp); 23440Sstevel@tonic-gate if (error) { 23450Sstevel@tonic-gate if (error == EINVAL) { 23460Sstevel@tonic-gate uiop->uio_loffset += *offset - oldoffset; 23470Sstevel@tonic-gate return (0); 23480Sstevel@tonic-gate } else 23490Sstevel@tonic-gate return (error); 23500Sstevel@tonic-gate } 23510Sstevel@tonic-gate 23520Sstevel@tonic-gate ep = *epp; 23530Sstevel@tonic-gate uiop->uio_loffset += *offset - oldoffset; 23540Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name)); 23550Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 23560Sstevel@tonic-gate uiop->uio_loffset = uiooffset; 23570Sstevel@tonic-gate return (ENOSPC); 23580Sstevel@tonic-gate } 23590Sstevel@tonic-gate ld->d_off = uiop->uio_loffset + sizeof (struct pcdir); 23600Sstevel@tonic-gate ld->d_ino = pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno), 23610Sstevel@tonic-gate pc_blkoff(fsp, *offset), ep->pcd_attr, 23625121Sfrankho pc_getstartcluster(fsp, ep), pc_direntpersec(fsp)); 23630Sstevel@tonic-gate (void) uiomove((caddr_t)ld, ld->d_reclen, UIO_READ, uiop); 23640Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 23650Sstevel@tonic-gate *offset += sizeof (struct pcdir); 23660Sstevel@tonic-gate ep++; 23670Sstevel@tonic-gate *epp = ep; 23680Sstevel@tonic-gate return (0); 23690Sstevel@tonic-gate } 23700Sstevel@tonic-gate 23710Sstevel@tonic-gate /* 23720Sstevel@tonic-gate * Read a short filename into the pc_dirent structure and copy it out. 23730Sstevel@tonic-gate */ 23740Sstevel@tonic-gate int 23750Sstevel@tonic-gate pc_read_short_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld, 23760Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp) 23770Sstevel@tonic-gate { 23780Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 23790Sstevel@tonic-gate int boff = pc_blkoff(fsp, *offset); 23800Sstevel@tonic-gate struct pcdir *ep = *epp; 23810Sstevel@tonic-gate offset_t oldoffset = uiop->uio_loffset; 23820Sstevel@tonic-gate int error; 23830Sstevel@tonic-gate int foldcase; 23840Sstevel@tonic-gate 23850Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) { 23860Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir); 23870Sstevel@tonic-gate *offset += sizeof (struct pcdir); 23880Sstevel@tonic-gate ep++; 23890Sstevel@tonic-gate *epp = ep; 23900Sstevel@tonic-gate return (0); 23910Sstevel@tonic-gate } 23920Sstevel@tonic-gate ld->d_ino = (ino64_t)pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno), 23935121Sfrankho boff, ep->pcd_attr, pc_getstartcluster(fsp, ep), 23945121Sfrankho pc_direntpersec(fsp)); 23950Sstevel@tonic-gate foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE); 23960Sstevel@tonic-gate error = pc_fname_ext_to_name(&ld->d_name[0], &ep->pcd_filename[0], 23970Sstevel@tonic-gate &ep->pcd_ext[0], foldcase); 23980Sstevel@tonic-gate if (error == 0) { 23990Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name)); 24000Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 24010Sstevel@tonic-gate uiop->uio_loffset = oldoffset; 24020Sstevel@tonic-gate return (ENOSPC); 24030Sstevel@tonic-gate } 24040Sstevel@tonic-gate ld->d_off = (off64_t)(uiop->uio_loffset + 24050Sstevel@tonic-gate sizeof (struct pcdir)); 24060Sstevel@tonic-gate (void) uiomove((caddr_t)ld, 24070Sstevel@tonic-gate ld->d_reclen, UIO_READ, uiop); 24080Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 24090Sstevel@tonic-gate } else { 24100Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir); 24110Sstevel@tonic-gate } 24120Sstevel@tonic-gate *offset += sizeof (struct pcdir); 24130Sstevel@tonic-gate ep++; 24140Sstevel@tonic-gate *epp = ep; 24150Sstevel@tonic-gate return (0); 24160Sstevel@tonic-gate } 24170Sstevel@tonic-gate 2418*5331Samw /* ARGSUSED */ 24190Sstevel@tonic-gate static int 2420*5331Samw pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct) 24210Sstevel@tonic-gate { 24220Sstevel@tonic-gate struct pc_fid *pcfid; 24230Sstevel@tonic-gate struct pcnode *pcp; 24240Sstevel@tonic-gate struct pcfs *fsp; 24250Sstevel@tonic-gate int error; 24260Sstevel@tonic-gate 24270Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 24280Sstevel@tonic-gate if (fsp == NULL) 24290Sstevel@tonic-gate return (EIO); 24300Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 24310Sstevel@tonic-gate if (error) 24320Sstevel@tonic-gate return (error); 24332972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 24340Sstevel@tonic-gate pc_unlockfs(fsp); 24350Sstevel@tonic-gate return (EIO); 24360Sstevel@tonic-gate } 24370Sstevel@tonic-gate if (fidp->fid_len < (sizeof (struct pc_fid) - sizeof (ushort_t))) { 24380Sstevel@tonic-gate fidp->fid_len = sizeof (struct pc_fid) - sizeof (ushort_t); 24390Sstevel@tonic-gate pc_unlockfs(fsp); 24400Sstevel@tonic-gate return (ENOSPC); 24410Sstevel@tonic-gate } 24420Sstevel@tonic-gate 24430Sstevel@tonic-gate pcfid = (struct pc_fid *)fidp; 24440Sstevel@tonic-gate bzero(pcfid, sizeof (struct pc_fid)); 24450Sstevel@tonic-gate pcfid->pcfid_len = sizeof (struct pc_fid) - sizeof (ushort_t); 24460Sstevel@tonic-gate if (vp->v_flag & VROOT) { 24470Sstevel@tonic-gate pcfid->pcfid_block = 0; 24480Sstevel@tonic-gate pcfid->pcfid_offset = 0; 24490Sstevel@tonic-gate pcfid->pcfid_ctime = 0; 24500Sstevel@tonic-gate } else { 24510Sstevel@tonic-gate pcfid->pcfid_block = pcp->pc_eblkno; 24520Sstevel@tonic-gate pcfid->pcfid_offset = pcp->pc_eoffset; 24530Sstevel@tonic-gate pcfid->pcfid_ctime = pcp->pc_entry.pcd_crtime.pct_time; 24540Sstevel@tonic-gate } 24550Sstevel@tonic-gate pc_unlockfs(fsp); 24560Sstevel@tonic-gate return (0); 24570Sstevel@tonic-gate } 2458