1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/param.h> 30*0Sstevel@tonic-gate #include <sys/t_lock.h> 31*0Sstevel@tonic-gate #include <sys/systm.h> 32*0Sstevel@tonic-gate #include <sys/sysmacros.h> 33*0Sstevel@tonic-gate #include <sys/user.h> 34*0Sstevel@tonic-gate #include <sys/buf.h> 35*0Sstevel@tonic-gate #include <sys/stat.h> 36*0Sstevel@tonic-gate #include <sys/vfs.h> 37*0Sstevel@tonic-gate #include <sys/dirent.h> 38*0Sstevel@tonic-gate #include <sys/vnode.h> 39*0Sstevel@tonic-gate #include <sys/proc.h> 40*0Sstevel@tonic-gate #include <sys/file.h> 41*0Sstevel@tonic-gate #include <sys/fcntl.h> 42*0Sstevel@tonic-gate #include <sys/uio.h> 43*0Sstevel@tonic-gate #include <sys/fs/pc_label.h> 44*0Sstevel@tonic-gate #include <sys/fs/pc_fs.h> 45*0Sstevel@tonic-gate #include <sys/fs/pc_dir.h> 46*0Sstevel@tonic-gate #include <sys/fs/pc_node.h> 47*0Sstevel@tonic-gate #include <sys/mman.h> 48*0Sstevel@tonic-gate #include <sys/pathname.h> 49*0Sstevel@tonic-gate #include <sys/vmsystm.h> 50*0Sstevel@tonic-gate #include <sys/cmn_err.h> 51*0Sstevel@tonic-gate #include <sys/debug.h> 52*0Sstevel@tonic-gate #include <sys/statvfs.h> 53*0Sstevel@tonic-gate #include <sys/unistd.h> 54*0Sstevel@tonic-gate #include <sys/kmem.h> 55*0Sstevel@tonic-gate #include <sys/conf.h> 56*0Sstevel@tonic-gate #include <sys/flock.h> 57*0Sstevel@tonic-gate #include <sys/policy.h> 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate #include <vm/seg.h> 60*0Sstevel@tonic-gate #include <vm/page.h> 61*0Sstevel@tonic-gate #include <vm/pvn.h> 62*0Sstevel@tonic-gate #include <vm/seg_map.h> 63*0Sstevel@tonic-gate #include <vm/seg_vn.h> 64*0Sstevel@tonic-gate #include <vm/hat.h> 65*0Sstevel@tonic-gate #include <vm/as.h> 66*0Sstevel@tonic-gate #include <vm/seg_kmem.h> 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate #include <fs/fs_subr.h> 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate static int pcfs_open(struct vnode **, int, struct cred *); 71*0Sstevel@tonic-gate static int pcfs_close(struct vnode *, int, int, offset_t, struct cred *); 72*0Sstevel@tonic-gate static int pcfs_read(struct vnode *, struct uio *, int, struct cred *, 73*0Sstevel@tonic-gate struct caller_context *); 74*0Sstevel@tonic-gate static int pcfs_write(struct vnode *, struct uio *, int, struct cred *, 75*0Sstevel@tonic-gate struct caller_context *); 76*0Sstevel@tonic-gate static int pcfs_getattr(struct vnode *, struct vattr *, int, struct cred *); 77*0Sstevel@tonic-gate static int pcfs_setattr(struct vnode *, struct vattr *, int, struct cred *, 78*0Sstevel@tonic-gate caller_context_t *); 79*0Sstevel@tonic-gate static int pcfs_access(struct vnode *, int, int, struct cred *); 80*0Sstevel@tonic-gate static int pcfs_lookup(struct vnode *, char *, struct vnode **, 81*0Sstevel@tonic-gate struct pathname *, int, struct vnode *, struct cred *); 82*0Sstevel@tonic-gate static int pcfs_create(struct vnode *, char *, struct vattr *, 83*0Sstevel@tonic-gate enum vcexcl, int mode, struct vnode **, struct cred *, int); 84*0Sstevel@tonic-gate static int pcfs_remove(struct vnode *, char *, struct cred *); 85*0Sstevel@tonic-gate static int pcfs_rename(struct vnode *, char *, struct vnode *, char *, 86*0Sstevel@tonic-gate struct cred *); 87*0Sstevel@tonic-gate static int pcfs_mkdir(struct vnode *, char *, struct vattr *, struct vnode **, 88*0Sstevel@tonic-gate struct cred *); 89*0Sstevel@tonic-gate static int pcfs_rmdir(struct vnode *, char *, struct vnode *, struct cred *); 90*0Sstevel@tonic-gate static int pcfs_readdir(struct vnode *, struct uio *, struct cred *, int *); 91*0Sstevel@tonic-gate static int pcfs_fsync(struct vnode *, int, struct cred *); 92*0Sstevel@tonic-gate static void pcfs_inactive(struct vnode *, struct cred *); 93*0Sstevel@tonic-gate static int pcfs_fid(struct vnode *vp, struct fid *fidp); 94*0Sstevel@tonic-gate static int pcfs_space(struct vnode *, int, struct flock64 *, int, 95*0Sstevel@tonic-gate offset_t, cred_t *, caller_context_t *); 96*0Sstevel@tonic-gate static int pcfs_getpage(struct vnode *, offset_t, size_t, uint_t *, page_t *[], 97*0Sstevel@tonic-gate size_t, struct seg *, caddr_t, enum seg_rw, struct cred *); 98*0Sstevel@tonic-gate static int pcfs_getapage(struct vnode *, u_offset_t, size_t, uint_t *, 99*0Sstevel@tonic-gate page_t *[], size_t, struct seg *, caddr_t, enum seg_rw, struct cred *); 100*0Sstevel@tonic-gate static int pcfs_putpage(struct vnode *, offset_t, size_t, int, struct cred *); 101*0Sstevel@tonic-gate static int pcfs_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t, 102*0Sstevel@tonic-gate uchar_t, uchar_t, uint_t, struct cred *); 103*0Sstevel@tonic-gate static int pcfs_addmap(struct vnode *, offset_t, struct as *, caddr_t, 104*0Sstevel@tonic-gate size_t, uchar_t, uchar_t, uint_t, struct cred *); 105*0Sstevel@tonic-gate static int pcfs_delmap(struct vnode *, offset_t, struct as *, caddr_t, 106*0Sstevel@tonic-gate size_t, uint_t, uint_t, uint_t, struct cred *); 107*0Sstevel@tonic-gate static int pcfs_seek(struct vnode *, offset_t, offset_t *); 108*0Sstevel@tonic-gate static int pcfs_pathconf(struct vnode *, int, ulong_t *, struct cred *); 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate int pcfs_putapage(struct vnode *, page_t *, u_offset_t *, size_t *, int, 111*0Sstevel@tonic-gate struct cred *); 112*0Sstevel@tonic-gate static int rwpcp(struct pcnode *, struct uio *, enum uio_rw, int); 113*0Sstevel@tonic-gate static int get_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int foldcase); 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate extern krwlock_t pcnodes_lock; 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate #define lround(r) (((r)+sizeof (long long)-1)&(~(sizeof (long long)-1))) 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate /* 120*0Sstevel@tonic-gate * vnode op vectors for files and directories. 121*0Sstevel@tonic-gate */ 122*0Sstevel@tonic-gate struct vnodeops *pcfs_fvnodeops; 123*0Sstevel@tonic-gate struct vnodeops *pcfs_dvnodeops; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate const fs_operation_def_t pcfs_fvnodeops_template[] = { 126*0Sstevel@tonic-gate VOPNAME_OPEN, pcfs_open, 127*0Sstevel@tonic-gate VOPNAME_CLOSE, pcfs_close, 128*0Sstevel@tonic-gate VOPNAME_READ, pcfs_read, 129*0Sstevel@tonic-gate VOPNAME_WRITE, pcfs_write, 130*0Sstevel@tonic-gate VOPNAME_GETATTR, pcfs_getattr, 131*0Sstevel@tonic-gate VOPNAME_SETATTR, pcfs_setattr, 132*0Sstevel@tonic-gate VOPNAME_ACCESS, pcfs_access, 133*0Sstevel@tonic-gate VOPNAME_FSYNC, pcfs_fsync, 134*0Sstevel@tonic-gate VOPNAME_INACTIVE, (fs_generic_func_p) pcfs_inactive, 135*0Sstevel@tonic-gate VOPNAME_FID, pcfs_fid, 136*0Sstevel@tonic-gate VOPNAME_SEEK, pcfs_seek, 137*0Sstevel@tonic-gate VOPNAME_SPACE, pcfs_space, 138*0Sstevel@tonic-gate VOPNAME_GETPAGE, pcfs_getpage, 139*0Sstevel@tonic-gate VOPNAME_PUTPAGE, pcfs_putpage, 140*0Sstevel@tonic-gate VOPNAME_MAP, (fs_generic_func_p) pcfs_map, 141*0Sstevel@tonic-gate VOPNAME_ADDMAP, (fs_generic_func_p) pcfs_addmap, 142*0Sstevel@tonic-gate VOPNAME_DELMAP, pcfs_delmap, 143*0Sstevel@tonic-gate VOPNAME_PATHCONF, pcfs_pathconf, 144*0Sstevel@tonic-gate VOPNAME_VNEVENT, fs_vnevent_support, 145*0Sstevel@tonic-gate NULL, NULL 146*0Sstevel@tonic-gate }; 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate const fs_operation_def_t pcfs_dvnodeops_template[] = { 149*0Sstevel@tonic-gate VOPNAME_OPEN, pcfs_open, 150*0Sstevel@tonic-gate VOPNAME_CLOSE, pcfs_close, 151*0Sstevel@tonic-gate VOPNAME_GETATTR, pcfs_getattr, 152*0Sstevel@tonic-gate VOPNAME_SETATTR, pcfs_setattr, 153*0Sstevel@tonic-gate VOPNAME_ACCESS, pcfs_access, 154*0Sstevel@tonic-gate VOPNAME_LOOKUP, pcfs_lookup, 155*0Sstevel@tonic-gate VOPNAME_CREATE, pcfs_create, 156*0Sstevel@tonic-gate VOPNAME_REMOVE, pcfs_remove, 157*0Sstevel@tonic-gate VOPNAME_RENAME, pcfs_rename, 158*0Sstevel@tonic-gate VOPNAME_MKDIR, pcfs_mkdir, 159*0Sstevel@tonic-gate VOPNAME_RMDIR, pcfs_rmdir, 160*0Sstevel@tonic-gate VOPNAME_READDIR, pcfs_readdir, 161*0Sstevel@tonic-gate VOPNAME_FSYNC, pcfs_fsync, 162*0Sstevel@tonic-gate VOPNAME_INACTIVE, (fs_generic_func_p) pcfs_inactive, 163*0Sstevel@tonic-gate VOPNAME_FID, pcfs_fid, 164*0Sstevel@tonic-gate VOPNAME_SEEK, pcfs_seek, 165*0Sstevel@tonic-gate VOPNAME_PATHCONF, pcfs_pathconf, 166*0Sstevel@tonic-gate VOPNAME_VNEVENT, fs_vnevent_support, 167*0Sstevel@tonic-gate NULL, NULL 168*0Sstevel@tonic-gate }; 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate /*ARGSUSED*/ 172*0Sstevel@tonic-gate static int 173*0Sstevel@tonic-gate pcfs_open( 174*0Sstevel@tonic-gate struct vnode **vpp, 175*0Sstevel@tonic-gate int flag, 176*0Sstevel@tonic-gate struct cred *cr) 177*0Sstevel@tonic-gate { 178*0Sstevel@tonic-gate return (0); 179*0Sstevel@tonic-gate } 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate /* 182*0Sstevel@tonic-gate * files are sync'ed on close to keep floppy up to date 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate /*ARGSUSED*/ 186*0Sstevel@tonic-gate static int 187*0Sstevel@tonic-gate pcfs_close( 188*0Sstevel@tonic-gate struct vnode *vp, 189*0Sstevel@tonic-gate int flag, 190*0Sstevel@tonic-gate int count, 191*0Sstevel@tonic-gate offset_t offset, 192*0Sstevel@tonic-gate struct cred *cr) 193*0Sstevel@tonic-gate { 194*0Sstevel@tonic-gate return (0); 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate /*ARGSUSED*/ 198*0Sstevel@tonic-gate static int 199*0Sstevel@tonic-gate pcfs_read( 200*0Sstevel@tonic-gate struct vnode *vp, 201*0Sstevel@tonic-gate struct uio *uiop, 202*0Sstevel@tonic-gate int ioflag, 203*0Sstevel@tonic-gate struct cred *cr, 204*0Sstevel@tonic-gate struct caller_context *ct) 205*0Sstevel@tonic-gate { 206*0Sstevel@tonic-gate struct pcfs *fsp; 207*0Sstevel@tonic-gate struct pcnode *pcp; 208*0Sstevel@tonic-gate int error; 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 211*0Sstevel@tonic-gate if (error = pc_verify(fsp)) 212*0Sstevel@tonic-gate return (error); 213*0Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 214*0Sstevel@tonic-gate if (error) 215*0Sstevel@tonic-gate return (error); 216*0Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) { 217*0Sstevel@tonic-gate pc_unlockfs(fsp); 218*0Sstevel@tonic-gate return (EIO); 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate error = rwpcp(pcp, uiop, UIO_READ, ioflag); 221*0Sstevel@tonic-gate if ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0) { 222*0Sstevel@tonic-gate pcp->pc_flags |= PC_ACC; 223*0Sstevel@tonic-gate pc_mark_acc(pcp); 224*0Sstevel@tonic-gate } 225*0Sstevel@tonic-gate pc_unlockfs(fsp); 226*0Sstevel@tonic-gate if (error) { 227*0Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_read: io error = %d\n", error); 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate return (error); 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate /*ARGSUSED*/ 233*0Sstevel@tonic-gate static int 234*0Sstevel@tonic-gate pcfs_write( 235*0Sstevel@tonic-gate struct vnode *vp, 236*0Sstevel@tonic-gate struct uio *uiop, 237*0Sstevel@tonic-gate int ioflag, 238*0Sstevel@tonic-gate struct cred *cr, 239*0Sstevel@tonic-gate struct caller_context *ct) 240*0Sstevel@tonic-gate { 241*0Sstevel@tonic-gate struct pcfs *fsp; 242*0Sstevel@tonic-gate struct pcnode *pcp; 243*0Sstevel@tonic-gate int error; 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 246*0Sstevel@tonic-gate if (error = pc_verify(fsp)) 247*0Sstevel@tonic-gate return (error); 248*0Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 249*0Sstevel@tonic-gate if (error) 250*0Sstevel@tonic-gate return (error); 251*0Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) { 252*0Sstevel@tonic-gate pc_unlockfs(fsp); 253*0Sstevel@tonic-gate return (EIO); 254*0Sstevel@tonic-gate } 255*0Sstevel@tonic-gate if (ioflag & FAPPEND) { 256*0Sstevel@tonic-gate /* 257*0Sstevel@tonic-gate * in append mode start at end of file. 258*0Sstevel@tonic-gate */ 259*0Sstevel@tonic-gate uiop->uio_loffset = pcp->pc_size; 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate error = rwpcp(pcp, uiop, UIO_WRITE, ioflag); 262*0Sstevel@tonic-gate pcp->pc_flags |= PC_MOD; 263*0Sstevel@tonic-gate pc_mark_mod(pcp); 264*0Sstevel@tonic-gate if (ioflag & (FSYNC|FDSYNC)) 265*0Sstevel@tonic-gate (void) pc_nodeupdate(pcp); 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate pc_unlockfs(fsp); 268*0Sstevel@tonic-gate if (error) { 269*0Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_write: io error = %d\n", error); 270*0Sstevel@tonic-gate } 271*0Sstevel@tonic-gate return (error); 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate /* 275*0Sstevel@tonic-gate * read or write a vnode 276*0Sstevel@tonic-gate */ 277*0Sstevel@tonic-gate static int 278*0Sstevel@tonic-gate rwpcp( 279*0Sstevel@tonic-gate struct pcnode *pcp, 280*0Sstevel@tonic-gate struct uio *uio, 281*0Sstevel@tonic-gate enum uio_rw rw, 282*0Sstevel@tonic-gate int ioflag) 283*0Sstevel@tonic-gate { 284*0Sstevel@tonic-gate struct vnode *vp = PCTOV(pcp); 285*0Sstevel@tonic-gate struct pcfs *fsp; 286*0Sstevel@tonic-gate daddr_t bn; /* phys block number */ 287*0Sstevel@tonic-gate int n; 288*0Sstevel@tonic-gate offset_t off; 289*0Sstevel@tonic-gate caddr_t base; 290*0Sstevel@tonic-gate int mapon, pagecreate; 291*0Sstevel@tonic-gate int newpage; 292*0Sstevel@tonic-gate int error = 0; 293*0Sstevel@tonic-gate rlim64_t limit = uio->uio_llimit; 294*0Sstevel@tonic-gate int oresid = uio->uio_resid; 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate PC_DPRINTF4(5, "rwpcp pcp=%p off=%lld resid=%ld size=%u\n", (void *)pcp, 297*0Sstevel@tonic-gate uio->uio_loffset, uio->uio_resid, pcp->pc_size); 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate ASSERT(rw == UIO_READ || rw == UIO_WRITE); 300*0Sstevel@tonic-gate ASSERT(vp->v_type == VREG); 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate if (uio->uio_loffset >= UINT32_MAX && rw == UIO_READ) { 303*0Sstevel@tonic-gate return (0); 304*0Sstevel@tonic-gate } 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate if (uio->uio_loffset < 0) 307*0Sstevel@tonic-gate return (EINVAL); 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T) 310*0Sstevel@tonic-gate limit = MAXOFFSET_T; 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate if (uio->uio_loffset >= limit && rw == UIO_WRITE) { 313*0Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate mutex_enter(&p->p_lock); 316*0Sstevel@tonic-gate (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], p->p_rctls, 317*0Sstevel@tonic-gate p, RCA_UNSAFE_SIGINFO); 318*0Sstevel@tonic-gate mutex_exit(&p->p_lock); 319*0Sstevel@tonic-gate return (EFBIG); 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate /* the following condition will occur only for write */ 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate if (uio->uio_loffset >= UINT32_MAX) 325*0Sstevel@tonic-gate return (EFBIG); 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate if (uio->uio_resid == 0) 328*0Sstevel@tonic-gate return (0); 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate if (limit > UINT32_MAX) 331*0Sstevel@tonic-gate limit = UINT32_MAX; 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 334*0Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_IRRECOV) 335*0Sstevel@tonic-gate return (EIO); 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate do { 338*0Sstevel@tonic-gate /* 339*0Sstevel@tonic-gate * Assignments to "n" in this block may appear 340*0Sstevel@tonic-gate * to overflow in some cases. However, after careful 341*0Sstevel@tonic-gate * analysis it was determined that all assignments to 342*0Sstevel@tonic-gate * "n" serve only to make "n" smaller. Since "n" 343*0Sstevel@tonic-gate * starts out as no larger than MAXBSIZE, "int" is 344*0Sstevel@tonic-gate * safe. 345*0Sstevel@tonic-gate */ 346*0Sstevel@tonic-gate off = uio->uio_loffset & MAXBMASK; 347*0Sstevel@tonic-gate mapon = (int)(uio->uio_loffset & MAXBOFFSET); 348*0Sstevel@tonic-gate n = MIN(MAXBSIZE - mapon, uio->uio_resid); 349*0Sstevel@tonic-gate if (rw == UIO_READ) { 350*0Sstevel@tonic-gate offset_t diff; 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate diff = pcp->pc_size - uio->uio_loffset; 353*0Sstevel@tonic-gate if (diff <= 0) 354*0Sstevel@tonic-gate return (0); 355*0Sstevel@tonic-gate if (diff < n) 356*0Sstevel@tonic-gate n = (int)diff; 357*0Sstevel@tonic-gate } 358*0Sstevel@tonic-gate /* 359*0Sstevel@tonic-gate * Compare limit with the actual offset + n, not the 360*0Sstevel@tonic-gate * rounded down offset "off" or we will overflow 361*0Sstevel@tonic-gate * the maximum file size after all. 362*0Sstevel@tonic-gate */ 363*0Sstevel@tonic-gate if (rw == UIO_WRITE && uio->uio_loffset + n >= limit) { 364*0Sstevel@tonic-gate if (uio->uio_loffset >= limit) { 365*0Sstevel@tonic-gate error = EFBIG; 366*0Sstevel@tonic-gate break; 367*0Sstevel@tonic-gate } 368*0Sstevel@tonic-gate n = (int)(limit - uio->uio_loffset); 369*0Sstevel@tonic-gate } 370*0Sstevel@tonic-gate base = segmap_getmap(segkmap, vp, (u_offset_t)off); 371*0Sstevel@tonic-gate pagecreate = 0; 372*0Sstevel@tonic-gate newpage = 0; 373*0Sstevel@tonic-gate if (rw == UIO_WRITE) { 374*0Sstevel@tonic-gate /* 375*0Sstevel@tonic-gate * If PAGESIZE < MAXBSIZE, perhaps we ought to deal 376*0Sstevel@tonic-gate * with one page at a time, instead of one MAXBSIZE 377*0Sstevel@tonic-gate * at a time, so we can fully explore pagecreate 378*0Sstevel@tonic-gate * optimization?? 379*0Sstevel@tonic-gate */ 380*0Sstevel@tonic-gate if (uio->uio_loffset + n > pcp->pc_size) { 381*0Sstevel@tonic-gate uint_t ncl, lcn; 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate ncl = (uint_t)howmany((offset_t)pcp->pc_size, 384*0Sstevel@tonic-gate fsp->pcfs_clsize); 385*0Sstevel@tonic-gate if (uio->uio_loffset > pcp->pc_size && 386*0Sstevel@tonic-gate ncl < (uint_t)howmany(uio->uio_loffset, 387*0Sstevel@tonic-gate fsp->pcfs_clsize)) { 388*0Sstevel@tonic-gate /* 389*0Sstevel@tonic-gate * Allocate and zerofill skipped 390*0Sstevel@tonic-gate * clusters. This may not be worth the 391*0Sstevel@tonic-gate * effort since a small lseek beyond 392*0Sstevel@tonic-gate * eof but still within the cluster 393*0Sstevel@tonic-gate * will not be zeroed out. 394*0Sstevel@tonic-gate */ 395*0Sstevel@tonic-gate lcn = pc_lblkno(fsp, uio->uio_loffset); 396*0Sstevel@tonic-gate error = pc_balloc(pcp, (daddr_t)lcn, 397*0Sstevel@tonic-gate 1, &bn); 398*0Sstevel@tonic-gate ncl = lcn + 1; 399*0Sstevel@tonic-gate } 400*0Sstevel@tonic-gate if (!error && 401*0Sstevel@tonic-gate ncl < (uint_t)howmany(uio->uio_loffset + n, 402*0Sstevel@tonic-gate fsp->pcfs_clsize)) 403*0Sstevel@tonic-gate /* 404*0Sstevel@tonic-gate * allocate clusters w/o zerofill 405*0Sstevel@tonic-gate */ 406*0Sstevel@tonic-gate error = pc_balloc(pcp, 407*0Sstevel@tonic-gate (daddr_t)pc_lblkno(fsp, 408*0Sstevel@tonic-gate uio->uio_loffset + n - 1), 409*0Sstevel@tonic-gate 0, &bn); 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate if (error) { 414*0Sstevel@tonic-gate /* figure out new file size */ 415*0Sstevel@tonic-gate pcp->pc_size = fsp->pcfs_clsize * 416*0Sstevel@tonic-gate pc_fileclsize(fsp, 417*0Sstevel@tonic-gate pcp->pc_scluster); 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate if (error == ENOSPC && 420*0Sstevel@tonic-gate (pcp->pc_size - uio->uio_loffset) 421*0Sstevel@tonic-gate > 0) { 422*0Sstevel@tonic-gate PC_DPRINTF3(2, "rwpcp ENOSPC " 423*0Sstevel@tonic-gate "off=%lld n=%d size=%d\n", 424*0Sstevel@tonic-gate uio->uio_loffset, 425*0Sstevel@tonic-gate n, pcp->pc_size); 426*0Sstevel@tonic-gate n = (int)(pcp->pc_size - 427*0Sstevel@tonic-gate uio->uio_loffset); 428*0Sstevel@tonic-gate } else { 429*0Sstevel@tonic-gate PC_DPRINTF1(1, 430*0Sstevel@tonic-gate "rwpcp error1=%d\n", error); 431*0Sstevel@tonic-gate (void) segmap_release(segkmap, 432*0Sstevel@tonic-gate base, 0); 433*0Sstevel@tonic-gate break; 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate } else { 436*0Sstevel@tonic-gate pcp->pc_size = 437*0Sstevel@tonic-gate (uint_t)(uio->uio_loffset + n); 438*0Sstevel@tonic-gate } 439*0Sstevel@tonic-gate if (mapon == 0) { 440*0Sstevel@tonic-gate newpage = segmap_pagecreate(segkmap, 441*0Sstevel@tonic-gate base, (size_t)n, 0); 442*0Sstevel@tonic-gate pagecreate = 1; 443*0Sstevel@tonic-gate } 444*0Sstevel@tonic-gate } else if (n == MAXBSIZE) { 445*0Sstevel@tonic-gate newpage = segmap_pagecreate(segkmap, base, 446*0Sstevel@tonic-gate (size_t)n, 0); 447*0Sstevel@tonic-gate pagecreate = 1; 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate } 450*0Sstevel@tonic-gate error = uiomove(base + mapon, (size_t)n, rw, uio); 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate if (pagecreate && uio->uio_loffset < 453*0Sstevel@tonic-gate roundup(off + mapon + n, PAGESIZE)) { 454*0Sstevel@tonic-gate offset_t nzero, nmoved; 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate nmoved = uio->uio_loffset - (off + mapon); 457*0Sstevel@tonic-gate nzero = roundup(mapon + n, PAGESIZE) - nmoved; 458*0Sstevel@tonic-gate (void) kzero(base + mapon + nmoved, (size_t)nzero); 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate /* 462*0Sstevel@tonic-gate * Unlock the pages which have been allocated by 463*0Sstevel@tonic-gate * page_create_va() in segmap_pagecreate(). 464*0Sstevel@tonic-gate */ 465*0Sstevel@tonic-gate if (newpage) 466*0Sstevel@tonic-gate segmap_pageunlock(segkmap, base, (size_t)n, 467*0Sstevel@tonic-gate rw == UIO_WRITE ? S_WRITE : S_READ); 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate if (error) { 470*0Sstevel@tonic-gate PC_DPRINTF1(1, "rwpcp error2=%d\n", error); 471*0Sstevel@tonic-gate /* 472*0Sstevel@tonic-gate * If we failed on a write, we may have already 473*0Sstevel@tonic-gate * allocated file blocks as well as pages. It's hard 474*0Sstevel@tonic-gate * to undo the block allocation, but we must be sure 475*0Sstevel@tonic-gate * to invalidate any pages that may have been 476*0Sstevel@tonic-gate * allocated. 477*0Sstevel@tonic-gate */ 478*0Sstevel@tonic-gate if (rw == UIO_WRITE) 479*0Sstevel@tonic-gate (void) segmap_release(segkmap, base, SM_INVAL); 480*0Sstevel@tonic-gate else 481*0Sstevel@tonic-gate (void) segmap_release(segkmap, base, 0); 482*0Sstevel@tonic-gate } else { 483*0Sstevel@tonic-gate uint_t flags = 0; 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate if (rw == UIO_READ) { 486*0Sstevel@tonic-gate if (n + mapon == MAXBSIZE || 487*0Sstevel@tonic-gate uio->uio_loffset == pcp->pc_size) 488*0Sstevel@tonic-gate flags = SM_DONTNEED; 489*0Sstevel@tonic-gate } else if (ioflag & (FSYNC|FDSYNC)) { 490*0Sstevel@tonic-gate flags = SM_WRITE; 491*0Sstevel@tonic-gate } else if (n + mapon == MAXBSIZE) { 492*0Sstevel@tonic-gate flags = SM_WRITE|SM_ASYNC|SM_DONTNEED; 493*0Sstevel@tonic-gate } 494*0Sstevel@tonic-gate error = segmap_release(segkmap, base, flags); 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate } while (error == 0 && uio->uio_resid > 0 && n != 0); 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate if (oresid != uio->uio_resid) 500*0Sstevel@tonic-gate error = 0; 501*0Sstevel@tonic-gate return (error); 502*0Sstevel@tonic-gate } 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate /*ARGSUSED*/ 505*0Sstevel@tonic-gate static int 506*0Sstevel@tonic-gate pcfs_getattr( 507*0Sstevel@tonic-gate struct vnode *vp, 508*0Sstevel@tonic-gate struct vattr *vap, 509*0Sstevel@tonic-gate int flags, 510*0Sstevel@tonic-gate struct cred *cr) 511*0Sstevel@tonic-gate { 512*0Sstevel@tonic-gate struct pcnode *pcp; 513*0Sstevel@tonic-gate struct pcfs *fsp; 514*0Sstevel@tonic-gate int error; 515*0Sstevel@tonic-gate char attr; 516*0Sstevel@tonic-gate struct pctime atime; 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate PC_DPRINTF1(8, "pcfs_getattr: vp=%p\n", (void *)vp); 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 521*0Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 522*0Sstevel@tonic-gate if (error) 523*0Sstevel@tonic-gate return (error); 524*0Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) { 525*0Sstevel@tonic-gate pc_unlockfs(fsp); 526*0Sstevel@tonic-gate return (EIO); 527*0Sstevel@tonic-gate } 528*0Sstevel@tonic-gate /* 529*0Sstevel@tonic-gate * Copy from pcnode. 530*0Sstevel@tonic-gate */ 531*0Sstevel@tonic-gate vap->va_type = vp->v_type; 532*0Sstevel@tonic-gate attr = pcp->pc_entry.pcd_attr; 533*0Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, attr)) 534*0Sstevel@tonic-gate vap->va_mode = 0; 535*0Sstevel@tonic-gate else if (attr & PCA_LABEL) 536*0Sstevel@tonic-gate vap->va_mode = 0444; 537*0Sstevel@tonic-gate else if (attr & PCA_RDONLY) 538*0Sstevel@tonic-gate vap->va_mode = 0555; 539*0Sstevel@tonic-gate else if (fsp->pcfs_flags & PCFS_BOOTPART) { 540*0Sstevel@tonic-gate vap->va_mode = 0755; 541*0Sstevel@tonic-gate } else { 542*0Sstevel@tonic-gate vap->va_mode = 0777; 543*0Sstevel@tonic-gate } 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate if (attr & PCA_DIR) 546*0Sstevel@tonic-gate vap->va_mode |= S_IFDIR; 547*0Sstevel@tonic-gate else 548*0Sstevel@tonic-gate vap->va_mode |= S_IFREG; 549*0Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 550*0Sstevel@tonic-gate vap->va_uid = 0; 551*0Sstevel@tonic-gate vap->va_gid = 0; 552*0Sstevel@tonic-gate } else { 553*0Sstevel@tonic-gate vap->va_uid = crgetuid(cr); 554*0Sstevel@tonic-gate vap->va_gid = crgetgid(cr); 555*0Sstevel@tonic-gate } 556*0Sstevel@tonic-gate vap->va_fsid = vp->v_vfsp->vfs_dev; 557*0Sstevel@tonic-gate vap->va_nodeid = (ino64_t)pc_makenodeid(pcp->pc_eblkno, 558*0Sstevel@tonic-gate pcp->pc_eoffset, pcp->pc_entry.pcd_attr, 559*0Sstevel@tonic-gate pc_getstartcluster(fsp, &pcp->pc_entry), fsp->pcfs_entps); 560*0Sstevel@tonic-gate vap->va_nlink = 1; 561*0Sstevel@tonic-gate vap->va_size = (u_offset_t)pcp->pc_size; 562*0Sstevel@tonic-gate pc_pcttotv(&pcp->pc_entry.pcd_mtime, &vap->va_mtime); 563*0Sstevel@tonic-gate vap->va_ctime = vap->va_mtime; 564*0Sstevel@tonic-gate atime.pct_time = 0; 565*0Sstevel@tonic-gate atime.pct_date = pcp->pc_entry.pcd_ladate; 566*0Sstevel@tonic-gate pc_pcttotv(&atime, &vap->va_atime); 567*0Sstevel@tonic-gate vap->va_rdev = 0; 568*0Sstevel@tonic-gate vap->va_nblocks = (fsblkcnt64_t)howmany((offset_t)pcp->pc_size, 569*0Sstevel@tonic-gate DEV_BSIZE); 570*0Sstevel@tonic-gate vap->va_blksize = fsp->pcfs_clsize; 571*0Sstevel@tonic-gate pc_unlockfs(fsp); 572*0Sstevel@tonic-gate return (0); 573*0Sstevel@tonic-gate } 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate 576*0Sstevel@tonic-gate /*ARGSUSED*/ 577*0Sstevel@tonic-gate static int 578*0Sstevel@tonic-gate pcfs_setattr( 579*0Sstevel@tonic-gate struct vnode *vp, 580*0Sstevel@tonic-gate struct vattr *vap, 581*0Sstevel@tonic-gate int flags, 582*0Sstevel@tonic-gate struct cred *cr, 583*0Sstevel@tonic-gate caller_context_t *ct) 584*0Sstevel@tonic-gate { 585*0Sstevel@tonic-gate struct pcnode *pcp; 586*0Sstevel@tonic-gate mode_t mask = vap->va_mask; 587*0Sstevel@tonic-gate int error; 588*0Sstevel@tonic-gate struct pcfs *fsp; 589*0Sstevel@tonic-gate timestruc_t now; 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate PC_DPRINTF2(6, "pcfs_setattr: vp=%p mask=%x\n", (void *)vp, (int)mask); 592*0Sstevel@tonic-gate /* 593*0Sstevel@tonic-gate * cannot set these attributes 594*0Sstevel@tonic-gate */ 595*0Sstevel@tonic-gate if (mask & (AT_NOSET | AT_UID | AT_GID)) { 596*0Sstevel@tonic-gate return (EINVAL); 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate /* 599*0Sstevel@tonic-gate * pcfs_settar is now allowed on directories to avoid silly warnings 600*0Sstevel@tonic-gate * from 'tar' when it tries to set times on a directory, and console 601*0Sstevel@tonic-gate * printf's on the NFS server when it gets EINVAL back on such a 602*0Sstevel@tonic-gate * request. One possible problem with that since a directory entry 603*0Sstevel@tonic-gate * identifies a file, '.' and all the '..' entries in subdirectories 604*0Sstevel@tonic-gate * may get out of sync when the directory is updated since they're 605*0Sstevel@tonic-gate * treated like separate files. We could fix that by looking for 606*0Sstevel@tonic-gate * '.' and giving it the same attributes, and then looking for 607*0Sstevel@tonic-gate * all the subdirectories and updating '..', but that's pretty 608*0Sstevel@tonic-gate * expensive for something that doesn't seem likely to matter. 609*0Sstevel@tonic-gate */ 610*0Sstevel@tonic-gate /* can't do some ops on directories anyway */ 611*0Sstevel@tonic-gate if ((vp->v_type == VDIR) && 612*0Sstevel@tonic-gate (mask & AT_SIZE)) { 613*0Sstevel@tonic-gate return (EINVAL); 614*0Sstevel@tonic-gate } 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 617*0Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 618*0Sstevel@tonic-gate if (error) 619*0Sstevel@tonic-gate return (error); 620*0Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) { 621*0Sstevel@tonic-gate pc_unlockfs(fsp); 622*0Sstevel@tonic-gate return (EIO); 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 626*0Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 627*0Sstevel@tonic-gate pc_unlockfs(fsp); 628*0Sstevel@tonic-gate return (EACCES); 629*0Sstevel@tonic-gate } 630*0Sstevel@tonic-gate } 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate /* 633*0Sstevel@tonic-gate * Change file access modes. 634*0Sstevel@tonic-gate * If nobody has write permission, file is marked readonly. 635*0Sstevel@tonic-gate * Otherwise file is writable by anyone. 636*0Sstevel@tonic-gate */ 637*0Sstevel@tonic-gate if ((mask & AT_MODE) && (vap->va_mode != (mode_t)-1)) { 638*0Sstevel@tonic-gate if ((vap->va_mode & 0222) == 0) 639*0Sstevel@tonic-gate pcp->pc_entry.pcd_attr |= PCA_RDONLY; 640*0Sstevel@tonic-gate else 641*0Sstevel@tonic-gate pcp->pc_entry.pcd_attr &= ~PCA_RDONLY; 642*0Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 643*0Sstevel@tonic-gate } 644*0Sstevel@tonic-gate /* 645*0Sstevel@tonic-gate * Truncate file. Must have write permission. 646*0Sstevel@tonic-gate */ 647*0Sstevel@tonic-gate if ((mask & AT_SIZE) && (vap->va_size != (u_offset_t)-1)) { 648*0Sstevel@tonic-gate if (pcp->pc_entry.pcd_attr & PCA_RDONLY) { 649*0Sstevel@tonic-gate error = EACCES; 650*0Sstevel@tonic-gate goto out; 651*0Sstevel@tonic-gate } 652*0Sstevel@tonic-gate if (vap->va_size > UINT32_MAX) { 653*0Sstevel@tonic-gate error = EFBIG; 654*0Sstevel@tonic-gate goto out; 655*0Sstevel@tonic-gate } 656*0Sstevel@tonic-gate error = pc_truncate(pcp, (uint_t)vap->va_size); 657*0Sstevel@tonic-gate if (error) 658*0Sstevel@tonic-gate goto out; 659*0Sstevel@tonic-gate } 660*0Sstevel@tonic-gate /* 661*0Sstevel@tonic-gate * Change file modified times. 662*0Sstevel@tonic-gate */ 663*0Sstevel@tonic-gate if ((mask & (AT_MTIME | AT_CTIME)) && (vap->va_mtime.tv_sec != -1)) { 664*0Sstevel@tonic-gate /* 665*0Sstevel@tonic-gate * If SysV-compatible option to set access and 666*0Sstevel@tonic-gate * modified times if privileged, owner, or write access, 667*0Sstevel@tonic-gate * use current time rather than va_mtime. 668*0Sstevel@tonic-gate * 669*0Sstevel@tonic-gate * XXX - va_mtime.tv_sec == -1 flags this. 670*0Sstevel@tonic-gate */ 671*0Sstevel@tonic-gate if (vap->va_mtime.tv_sec == -1) { 672*0Sstevel@tonic-gate gethrestime(&now); 673*0Sstevel@tonic-gate pc_tvtopct(&now, &pcp->pc_entry.pcd_mtime); 674*0Sstevel@tonic-gate } else { 675*0Sstevel@tonic-gate pc_tvtopct(&vap->va_mtime, &pcp->pc_entry.pcd_mtime); 676*0Sstevel@tonic-gate } 677*0Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 678*0Sstevel@tonic-gate } 679*0Sstevel@tonic-gate /* 680*0Sstevel@tonic-gate * Change file access times. 681*0Sstevel@tonic-gate */ 682*0Sstevel@tonic-gate if ((mask & (AT_ATIME)) && (vap->va_atime.tv_sec != -1)) { 683*0Sstevel@tonic-gate /* 684*0Sstevel@tonic-gate * If SysV-compatible option to set access and 685*0Sstevel@tonic-gate * modified times if privileged, owner, or write access, 686*0Sstevel@tonic-gate * use current time rather than va_mtime. 687*0Sstevel@tonic-gate * 688*0Sstevel@tonic-gate * XXX - va_atime.tv_sec == -1 flags this. 689*0Sstevel@tonic-gate */ 690*0Sstevel@tonic-gate struct pctime atime; 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate if (vap->va_atime.tv_sec == -1) { 693*0Sstevel@tonic-gate gethrestime(&now); 694*0Sstevel@tonic-gate pc_tvtopct(&now, &atime); 695*0Sstevel@tonic-gate } else { 696*0Sstevel@tonic-gate pc_tvtopct(&vap->va_atime, &atime); 697*0Sstevel@tonic-gate } 698*0Sstevel@tonic-gate pcp->pc_entry.pcd_ladate = atime.pct_date; 699*0Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 700*0Sstevel@tonic-gate } 701*0Sstevel@tonic-gate out: 702*0Sstevel@tonic-gate pc_unlockfs(fsp); 703*0Sstevel@tonic-gate return (error); 704*0Sstevel@tonic-gate } 705*0Sstevel@tonic-gate 706*0Sstevel@tonic-gate 707*0Sstevel@tonic-gate /*ARGSUSED*/ 708*0Sstevel@tonic-gate static int 709*0Sstevel@tonic-gate pcfs_access( 710*0Sstevel@tonic-gate struct vnode *vp, 711*0Sstevel@tonic-gate int mode, 712*0Sstevel@tonic-gate int flags, 713*0Sstevel@tonic-gate struct cred *cr) 714*0Sstevel@tonic-gate { 715*0Sstevel@tonic-gate struct pcnode *pcp; 716*0Sstevel@tonic-gate struct pcfs *fsp; 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) 722*0Sstevel@tonic-gate return (EIO); 723*0Sstevel@tonic-gate if ((mode & VWRITE) && (pcp->pc_entry.pcd_attr & PCA_RDONLY)) 724*0Sstevel@tonic-gate return (EACCES); 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate /* 727*0Sstevel@tonic-gate * If this is a boot partition, privileged users have full access while 728*0Sstevel@tonic-gate * others have read-only access. 729*0Sstevel@tonic-gate */ 730*0Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 731*0Sstevel@tonic-gate if ((mode & VWRITE) && 732*0Sstevel@tonic-gate secpolicy_pcfs_modify_bootpartition(cr) != 0) 733*0Sstevel@tonic-gate return (EACCES); 734*0Sstevel@tonic-gate } 735*0Sstevel@tonic-gate return (0); 736*0Sstevel@tonic-gate } 737*0Sstevel@tonic-gate 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate /*ARGSUSED*/ 740*0Sstevel@tonic-gate static int 741*0Sstevel@tonic-gate pcfs_fsync( 742*0Sstevel@tonic-gate struct vnode *vp, 743*0Sstevel@tonic-gate int syncflag, 744*0Sstevel@tonic-gate struct cred *cr) 745*0Sstevel@tonic-gate { 746*0Sstevel@tonic-gate struct pcfs *fsp; 747*0Sstevel@tonic-gate struct pcnode *pcp; 748*0Sstevel@tonic-gate int error; 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 751*0Sstevel@tonic-gate if (error = pc_verify(fsp)) 752*0Sstevel@tonic-gate return (error); 753*0Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 754*0Sstevel@tonic-gate if (error) 755*0Sstevel@tonic-gate return (error); 756*0Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) { 757*0Sstevel@tonic-gate pc_unlockfs(fsp); 758*0Sstevel@tonic-gate return (EIO); 759*0Sstevel@tonic-gate } 760*0Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_WRITER); 761*0Sstevel@tonic-gate error = pc_nodesync(pcp); 762*0Sstevel@tonic-gate rw_exit(&pcnodes_lock); 763*0Sstevel@tonic-gate pc_unlockfs(fsp); 764*0Sstevel@tonic-gate return (error); 765*0Sstevel@tonic-gate } 766*0Sstevel@tonic-gate 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate /*ARGSUSED*/ 769*0Sstevel@tonic-gate static void 770*0Sstevel@tonic-gate pcfs_inactive( 771*0Sstevel@tonic-gate struct vnode *vp, 772*0Sstevel@tonic-gate struct cred *cr) 773*0Sstevel@tonic-gate { 774*0Sstevel@tonic-gate struct pcnode *pcp; 775*0Sstevel@tonic-gate struct pcfs *fsp; 776*0Sstevel@tonic-gate int error; 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 779*0Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 1); 780*0Sstevel@tonic-gate 781*0Sstevel@tonic-gate mutex_enter(&vp->v_lock); 782*0Sstevel@tonic-gate ASSERT(vp->v_count >= 1); 783*0Sstevel@tonic-gate if (vp->v_count > 1) { 784*0Sstevel@tonic-gate vp->v_count--; /* release our hold from vn_rele */ 785*0Sstevel@tonic-gate mutex_exit(&vp->v_lock); 786*0Sstevel@tonic-gate pc_unlockfs(fsp); 787*0Sstevel@tonic-gate return; 788*0Sstevel@tonic-gate } 789*0Sstevel@tonic-gate mutex_exit(&vp->v_lock); 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate /* 792*0Sstevel@tonic-gate * Check again to confirm that no intervening I/O error 793*0Sstevel@tonic-gate * with a subsequent pc_diskchanged() call has released 794*0Sstevel@tonic-gate * the pcnode. If it has then release the vnode as above. 795*0Sstevel@tonic-gate */ 796*0Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) 797*0Sstevel@tonic-gate vn_free(vp); 798*0Sstevel@tonic-gate else 799*0Sstevel@tonic-gate pc_rele(pcp); 800*0Sstevel@tonic-gate 801*0Sstevel@tonic-gate if (!error) 802*0Sstevel@tonic-gate pc_unlockfs(fsp); 803*0Sstevel@tonic-gate } 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate /*ARGSUSED*/ 806*0Sstevel@tonic-gate static int 807*0Sstevel@tonic-gate pcfs_lookup( 808*0Sstevel@tonic-gate struct vnode *dvp, 809*0Sstevel@tonic-gate char *nm, 810*0Sstevel@tonic-gate struct vnode **vpp, 811*0Sstevel@tonic-gate struct pathname *pnp, 812*0Sstevel@tonic-gate int flags, 813*0Sstevel@tonic-gate struct vnode *rdir, 814*0Sstevel@tonic-gate struct cred *cr) 815*0Sstevel@tonic-gate { 816*0Sstevel@tonic-gate struct pcfs *fsp; 817*0Sstevel@tonic-gate struct pcnode *pcp; 818*0Sstevel@tonic-gate int error; 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate /* 821*0Sstevel@tonic-gate * verify that the dvp is still valid on the disk 822*0Sstevel@tonic-gate */ 823*0Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 824*0Sstevel@tonic-gate if (error = pc_verify(fsp)) 825*0Sstevel@tonic-gate return (error); 826*0Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 827*0Sstevel@tonic-gate if (error) 828*0Sstevel@tonic-gate return (error); 829*0Sstevel@tonic-gate if (VTOPC(dvp) == NULL) { 830*0Sstevel@tonic-gate pc_unlockfs(fsp); 831*0Sstevel@tonic-gate return (EIO); 832*0Sstevel@tonic-gate } 833*0Sstevel@tonic-gate /* 834*0Sstevel@tonic-gate * Null component name is a synonym for directory being searched. 835*0Sstevel@tonic-gate */ 836*0Sstevel@tonic-gate if (*nm == '\0') { 837*0Sstevel@tonic-gate VN_HOLD(dvp); 838*0Sstevel@tonic-gate *vpp = dvp; 839*0Sstevel@tonic-gate pc_unlockfs(fsp); 840*0Sstevel@tonic-gate return (0); 841*0Sstevel@tonic-gate } 842*0Sstevel@tonic-gate 843*0Sstevel@tonic-gate error = pc_dirlook(VTOPC(dvp), nm, &pcp); 844*0Sstevel@tonic-gate if (!error) { 845*0Sstevel@tonic-gate *vpp = PCTOV(pcp); 846*0Sstevel@tonic-gate pcp->pc_flags |= PC_EXTERNAL; 847*0Sstevel@tonic-gate } 848*0Sstevel@tonic-gate pc_unlockfs(fsp); 849*0Sstevel@tonic-gate return (error); 850*0Sstevel@tonic-gate } 851*0Sstevel@tonic-gate 852*0Sstevel@tonic-gate 853*0Sstevel@tonic-gate /*ARGSUSED*/ 854*0Sstevel@tonic-gate static int 855*0Sstevel@tonic-gate pcfs_create( 856*0Sstevel@tonic-gate struct vnode *dvp, 857*0Sstevel@tonic-gate char *nm, 858*0Sstevel@tonic-gate struct vattr *vap, 859*0Sstevel@tonic-gate enum vcexcl exclusive, 860*0Sstevel@tonic-gate int mode, 861*0Sstevel@tonic-gate struct vnode **vpp, 862*0Sstevel@tonic-gate struct cred *cr, 863*0Sstevel@tonic-gate int flag) 864*0Sstevel@tonic-gate { 865*0Sstevel@tonic-gate int error; 866*0Sstevel@tonic-gate struct pcnode *pcp; 867*0Sstevel@tonic-gate struct vnode *vp; 868*0Sstevel@tonic-gate struct pcfs *fsp; 869*0Sstevel@tonic-gate 870*0Sstevel@tonic-gate /* 871*0Sstevel@tonic-gate * can't create directories. use pcfs_mkdir. 872*0Sstevel@tonic-gate * can't create anything other than files. 873*0Sstevel@tonic-gate */ 874*0Sstevel@tonic-gate if (vap->va_type == VDIR) 875*0Sstevel@tonic-gate return (EISDIR); 876*0Sstevel@tonic-gate else if (vap->va_type != VREG) 877*0Sstevel@tonic-gate return (EINVAL); 878*0Sstevel@tonic-gate 879*0Sstevel@tonic-gate pcp = NULL; 880*0Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 881*0Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 882*0Sstevel@tonic-gate if (error) 883*0Sstevel@tonic-gate return (error); 884*0Sstevel@tonic-gate if (VTOPC(dvp) == NULL) { 885*0Sstevel@tonic-gate pc_unlockfs(fsp); 886*0Sstevel@tonic-gate return (EIO); 887*0Sstevel@tonic-gate } 888*0Sstevel@tonic-gate 889*0Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 890*0Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 891*0Sstevel@tonic-gate pc_unlockfs(fsp); 892*0Sstevel@tonic-gate return (EACCES); 893*0Sstevel@tonic-gate } 894*0Sstevel@tonic-gate } 895*0Sstevel@tonic-gate 896*0Sstevel@tonic-gate if (*nm == '\0') { 897*0Sstevel@tonic-gate /* 898*0Sstevel@tonic-gate * Null component name refers to the directory itself. 899*0Sstevel@tonic-gate */ 900*0Sstevel@tonic-gate VN_HOLD(dvp); 901*0Sstevel@tonic-gate pcp = VTOPC(dvp); 902*0Sstevel@tonic-gate error = EEXIST; 903*0Sstevel@tonic-gate } else { 904*0Sstevel@tonic-gate error = pc_direnter(VTOPC(dvp), nm, vap, &pcp); 905*0Sstevel@tonic-gate } 906*0Sstevel@tonic-gate /* 907*0Sstevel@tonic-gate * if file exists and this is a nonexclusive create, 908*0Sstevel@tonic-gate * check for access permissions 909*0Sstevel@tonic-gate */ 910*0Sstevel@tonic-gate if (error == EEXIST) { 911*0Sstevel@tonic-gate vp = PCTOV(pcp); 912*0Sstevel@tonic-gate if (exclusive == NONEXCL) { 913*0Sstevel@tonic-gate if (vp->v_type == VDIR) { 914*0Sstevel@tonic-gate error = EISDIR; 915*0Sstevel@tonic-gate } else if (mode) { 916*0Sstevel@tonic-gate error = pcfs_access(PCTOV(pcp), mode, 0, 917*0Sstevel@tonic-gate cr); 918*0Sstevel@tonic-gate } else { 919*0Sstevel@tonic-gate error = 0; 920*0Sstevel@tonic-gate } 921*0Sstevel@tonic-gate } 922*0Sstevel@tonic-gate if (error) { 923*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 924*0Sstevel@tonic-gate } else if ((vp->v_type == VREG) && (vap->va_mask & AT_SIZE) && 925*0Sstevel@tonic-gate (vap->va_size == 0)) { 926*0Sstevel@tonic-gate error = pc_truncate(pcp, 0L); 927*0Sstevel@tonic-gate if (error) 928*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 929*0Sstevel@tonic-gate } 930*0Sstevel@tonic-gate } 931*0Sstevel@tonic-gate if (error) { 932*0Sstevel@tonic-gate pc_unlockfs(fsp); 933*0Sstevel@tonic-gate return (error); 934*0Sstevel@tonic-gate } 935*0Sstevel@tonic-gate *vpp = PCTOV(pcp); 936*0Sstevel@tonic-gate pcp->pc_flags |= PC_EXTERNAL; 937*0Sstevel@tonic-gate pc_unlockfs(fsp); 938*0Sstevel@tonic-gate return (error); 939*0Sstevel@tonic-gate } 940*0Sstevel@tonic-gate 941*0Sstevel@tonic-gate /*ARGSUSED*/ 942*0Sstevel@tonic-gate static int 943*0Sstevel@tonic-gate pcfs_remove( 944*0Sstevel@tonic-gate struct vnode *vp, 945*0Sstevel@tonic-gate char *nm, 946*0Sstevel@tonic-gate struct cred *cr) 947*0Sstevel@tonic-gate { 948*0Sstevel@tonic-gate struct pcfs *fsp; 949*0Sstevel@tonic-gate struct pcnode *pcp; 950*0Sstevel@tonic-gate int error; 951*0Sstevel@tonic-gate 952*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 953*0Sstevel@tonic-gate if (error = pc_verify(fsp)) 954*0Sstevel@tonic-gate return (error); 955*0Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 956*0Sstevel@tonic-gate if (error) 957*0Sstevel@tonic-gate return (error); 958*0Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) { 959*0Sstevel@tonic-gate pc_unlockfs(fsp); 960*0Sstevel@tonic-gate return (EIO); 961*0Sstevel@tonic-gate } 962*0Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 963*0Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 964*0Sstevel@tonic-gate pc_unlockfs(fsp); 965*0Sstevel@tonic-gate return (EACCES); 966*0Sstevel@tonic-gate } 967*0Sstevel@tonic-gate } 968*0Sstevel@tonic-gate error = pc_dirremove(pcp, nm, (struct vnode *)0, VREG); 969*0Sstevel@tonic-gate pc_unlockfs(fsp); 970*0Sstevel@tonic-gate return (error); 971*0Sstevel@tonic-gate } 972*0Sstevel@tonic-gate 973*0Sstevel@tonic-gate /* 974*0Sstevel@tonic-gate * Rename a file or directory 975*0Sstevel@tonic-gate * This rename is restricted to only rename files within a directory. 976*0Sstevel@tonic-gate * XX should make rename more general 977*0Sstevel@tonic-gate */ 978*0Sstevel@tonic-gate /*ARGSUSED*/ 979*0Sstevel@tonic-gate static int 980*0Sstevel@tonic-gate pcfs_rename( 981*0Sstevel@tonic-gate struct vnode *sdvp, /* old (source) parent vnode */ 982*0Sstevel@tonic-gate char *snm, /* old (source) entry name */ 983*0Sstevel@tonic-gate struct vnode *tdvp, /* new (target) parent vnode */ 984*0Sstevel@tonic-gate char *tnm, /* new (target) entry name */ 985*0Sstevel@tonic-gate struct cred *cr) 986*0Sstevel@tonic-gate { 987*0Sstevel@tonic-gate struct pcfs *fsp; 988*0Sstevel@tonic-gate struct pcnode *dp; /* parent pcnode */ 989*0Sstevel@tonic-gate struct pcnode *tdp; 990*0Sstevel@tonic-gate int error; 991*0Sstevel@tonic-gate 992*0Sstevel@tonic-gate fsp = VFSTOPCFS(sdvp->v_vfsp); 993*0Sstevel@tonic-gate if (error = pc_verify(fsp)) 994*0Sstevel@tonic-gate return (error); 995*0Sstevel@tonic-gate if (((dp = VTOPC(sdvp)) == NULL) || ((tdp = VTOPC(tdvp)) == NULL)) { 996*0Sstevel@tonic-gate return (EIO); 997*0Sstevel@tonic-gate } 998*0Sstevel@tonic-gate 999*0Sstevel@tonic-gate /* 1000*0Sstevel@tonic-gate * make sure we can muck with this directory. 1001*0Sstevel@tonic-gate */ 1002*0Sstevel@tonic-gate error = pcfs_access(sdvp, VWRITE, 0, cr); 1003*0Sstevel@tonic-gate if (error) { 1004*0Sstevel@tonic-gate return (error); 1005*0Sstevel@tonic-gate } 1006*0Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 1007*0Sstevel@tonic-gate if (error) 1008*0Sstevel@tonic-gate return (error); 1009*0Sstevel@tonic-gate if ((VTOPC(sdvp) == NULL) || (VTOPC(tdvp) == NULL)) { 1010*0Sstevel@tonic-gate pc_unlockfs(fsp); 1011*0Sstevel@tonic-gate return (EIO); 1012*0Sstevel@tonic-gate } 1013*0Sstevel@tonic-gate error = pc_rename(dp, tdp, snm, tnm); 1014*0Sstevel@tonic-gate pc_unlockfs(fsp); 1015*0Sstevel@tonic-gate return (error); 1016*0Sstevel@tonic-gate } 1017*0Sstevel@tonic-gate 1018*0Sstevel@tonic-gate /*ARGSUSED*/ 1019*0Sstevel@tonic-gate static int 1020*0Sstevel@tonic-gate pcfs_mkdir( 1021*0Sstevel@tonic-gate struct vnode *dvp, 1022*0Sstevel@tonic-gate char *nm, 1023*0Sstevel@tonic-gate struct vattr *vap, 1024*0Sstevel@tonic-gate struct vnode **vpp, 1025*0Sstevel@tonic-gate struct cred *cr) 1026*0Sstevel@tonic-gate { 1027*0Sstevel@tonic-gate struct pcfs *fsp; 1028*0Sstevel@tonic-gate struct pcnode *pcp; 1029*0Sstevel@tonic-gate int error; 1030*0Sstevel@tonic-gate 1031*0Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 1032*0Sstevel@tonic-gate if (error = pc_verify(fsp)) 1033*0Sstevel@tonic-gate return (error); 1034*0Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 1035*0Sstevel@tonic-gate if (error) 1036*0Sstevel@tonic-gate return (error); 1037*0Sstevel@tonic-gate if (VTOPC(dvp) == NULL) { 1038*0Sstevel@tonic-gate pc_unlockfs(fsp); 1039*0Sstevel@tonic-gate return (EIO); 1040*0Sstevel@tonic-gate } 1041*0Sstevel@tonic-gate 1042*0Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 1043*0Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 1044*0Sstevel@tonic-gate pc_unlockfs(fsp); 1045*0Sstevel@tonic-gate return (EACCES); 1046*0Sstevel@tonic-gate } 1047*0Sstevel@tonic-gate } 1048*0Sstevel@tonic-gate 1049*0Sstevel@tonic-gate error = pc_direnter(VTOPC(dvp), nm, vap, &pcp); 1050*0Sstevel@tonic-gate 1051*0Sstevel@tonic-gate if (!error) { 1052*0Sstevel@tonic-gate pcp -> pc_flags |= PC_EXTERNAL; 1053*0Sstevel@tonic-gate *vpp = PCTOV(pcp); 1054*0Sstevel@tonic-gate } else if (error == EEXIST) { 1055*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 1056*0Sstevel@tonic-gate } 1057*0Sstevel@tonic-gate pc_unlockfs(fsp); 1058*0Sstevel@tonic-gate return (error); 1059*0Sstevel@tonic-gate } 1060*0Sstevel@tonic-gate 1061*0Sstevel@tonic-gate /*ARGSUSED*/ 1062*0Sstevel@tonic-gate static int 1063*0Sstevel@tonic-gate pcfs_rmdir( 1064*0Sstevel@tonic-gate struct vnode *dvp, 1065*0Sstevel@tonic-gate char *nm, 1066*0Sstevel@tonic-gate struct vnode *cdir, 1067*0Sstevel@tonic-gate struct cred *cr) 1068*0Sstevel@tonic-gate { 1069*0Sstevel@tonic-gate struct pcfs *fsp; 1070*0Sstevel@tonic-gate struct pcnode *pcp; 1071*0Sstevel@tonic-gate int error; 1072*0Sstevel@tonic-gate 1073*0Sstevel@tonic-gate fsp = VFSTOPCFS(dvp -> v_vfsp); 1074*0Sstevel@tonic-gate if (error = pc_verify(fsp)) 1075*0Sstevel@tonic-gate return (error); 1076*0Sstevel@tonic-gate if (error = pc_lockfs(fsp, 0, 0)) 1077*0Sstevel@tonic-gate return (error); 1078*0Sstevel@tonic-gate 1079*0Sstevel@tonic-gate if ((pcp = VTOPC(dvp)) == NULL) { 1080*0Sstevel@tonic-gate pc_unlockfs(fsp); 1081*0Sstevel@tonic-gate return (EIO); 1082*0Sstevel@tonic-gate } 1083*0Sstevel@tonic-gate 1084*0Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 1085*0Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 1086*0Sstevel@tonic-gate pc_unlockfs(fsp); 1087*0Sstevel@tonic-gate return (EACCES); 1088*0Sstevel@tonic-gate } 1089*0Sstevel@tonic-gate } 1090*0Sstevel@tonic-gate 1091*0Sstevel@tonic-gate error = pc_dirremove(pcp, nm, cdir, VDIR); 1092*0Sstevel@tonic-gate pc_unlockfs(fsp); 1093*0Sstevel@tonic-gate return (error); 1094*0Sstevel@tonic-gate } 1095*0Sstevel@tonic-gate 1096*0Sstevel@tonic-gate /* 1097*0Sstevel@tonic-gate * read entries in a directory. 1098*0Sstevel@tonic-gate * we must convert pc format to unix format 1099*0Sstevel@tonic-gate */ 1100*0Sstevel@tonic-gate 1101*0Sstevel@tonic-gate /*ARGSUSED*/ 1102*0Sstevel@tonic-gate static int 1103*0Sstevel@tonic-gate pcfs_readdir( 1104*0Sstevel@tonic-gate struct vnode *dvp, 1105*0Sstevel@tonic-gate struct uio *uiop, 1106*0Sstevel@tonic-gate struct cred *cr, 1107*0Sstevel@tonic-gate int *eofp) 1108*0Sstevel@tonic-gate { 1109*0Sstevel@tonic-gate struct pcnode *pcp; 1110*0Sstevel@tonic-gate struct pcfs *fsp; 1111*0Sstevel@tonic-gate struct pcdir *ep; 1112*0Sstevel@tonic-gate struct buf *bp = NULL; 1113*0Sstevel@tonic-gate offset_t offset; 1114*0Sstevel@tonic-gate int boff; 1115*0Sstevel@tonic-gate struct pc_dirent lbp; 1116*0Sstevel@tonic-gate struct pc_dirent *ld = &lbp; 1117*0Sstevel@tonic-gate int error; 1118*0Sstevel@tonic-gate 1119*0Sstevel@tonic-gate if ((uiop->uio_iovcnt != 1) || 1120*0Sstevel@tonic-gate (uiop->uio_loffset % sizeof (struct pcdir)) != 0) { 1121*0Sstevel@tonic-gate return (EINVAL); 1122*0Sstevel@tonic-gate } 1123*0Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 1124*0Sstevel@tonic-gate /* 1125*0Sstevel@tonic-gate * verify that the dp is still valid on the disk 1126*0Sstevel@tonic-gate */ 1127*0Sstevel@tonic-gate if (error = pc_verify(fsp)) { 1128*0Sstevel@tonic-gate return (error); 1129*0Sstevel@tonic-gate } 1130*0Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 1131*0Sstevel@tonic-gate if (error) 1132*0Sstevel@tonic-gate return (error); 1133*0Sstevel@tonic-gate if ((pcp = VTOPC(dvp)) == NULL) { 1134*0Sstevel@tonic-gate pc_unlockfs(fsp); 1135*0Sstevel@tonic-gate return (EIO); 1136*0Sstevel@tonic-gate } 1137*0Sstevel@tonic-gate 1138*0Sstevel@tonic-gate bzero(ld, sizeof (*ld)); 1139*0Sstevel@tonic-gate 1140*0Sstevel@tonic-gate if (eofp != NULL) 1141*0Sstevel@tonic-gate *eofp = 0; 1142*0Sstevel@tonic-gate offset = uiop->uio_loffset; 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gate if (dvp->v_flag & VROOT) { 1145*0Sstevel@tonic-gate /* 1146*0Sstevel@tonic-gate * kludge up entries for "." and ".." in the root. 1147*0Sstevel@tonic-gate */ 1148*0Sstevel@tonic-gate if (offset == 0) { 1149*0Sstevel@tonic-gate (void) strcpy(ld->d_name, "."); 1150*0Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(1); 1151*0Sstevel@tonic-gate ld->d_off = (off64_t)sizeof (struct pcdir); 1152*0Sstevel@tonic-gate ld->d_ino = (ino64_t)UINT_MAX; 1153*0Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 1154*0Sstevel@tonic-gate pc_unlockfs(fsp); 1155*0Sstevel@tonic-gate return (ENOSPC); 1156*0Sstevel@tonic-gate } 1157*0Sstevel@tonic-gate (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop); 1158*0Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 1159*0Sstevel@tonic-gate offset = uiop->uio_loffset; 1160*0Sstevel@tonic-gate } 1161*0Sstevel@tonic-gate if (offset == sizeof (struct pcdir)) { 1162*0Sstevel@tonic-gate (void) strcpy(ld->d_name, ".."); 1163*0Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(2); 1164*0Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 1165*0Sstevel@tonic-gate pc_unlockfs(fsp); 1166*0Sstevel@tonic-gate return (ENOSPC); 1167*0Sstevel@tonic-gate } 1168*0Sstevel@tonic-gate ld->d_off = (off64_t)(uiop->uio_loffset + 1169*0Sstevel@tonic-gate sizeof (struct pcdir)); 1170*0Sstevel@tonic-gate ld->d_ino = (ino64_t)UINT_MAX; 1171*0Sstevel@tonic-gate (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop); 1172*0Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 1173*0Sstevel@tonic-gate offset = uiop->uio_loffset; 1174*0Sstevel@tonic-gate } 1175*0Sstevel@tonic-gate offset -= 2 * sizeof (struct pcdir); 1176*0Sstevel@tonic-gate /* offset now has the real offset value into directory file */ 1177*0Sstevel@tonic-gate } 1178*0Sstevel@tonic-gate 1179*0Sstevel@tonic-gate for (;;) { 1180*0Sstevel@tonic-gate boff = pc_blkoff(fsp, offset); 1181*0Sstevel@tonic-gate if (boff == 0 || bp == NULL || boff >= bp->b_bcount) { 1182*0Sstevel@tonic-gate if (bp != NULL) { 1183*0Sstevel@tonic-gate brelse(bp); 1184*0Sstevel@tonic-gate bp = NULL; 1185*0Sstevel@tonic-gate } 1186*0Sstevel@tonic-gate error = pc_blkatoff(pcp, offset, &bp, &ep); 1187*0Sstevel@tonic-gate if (error) { 1188*0Sstevel@tonic-gate if (error == ENOENT) { 1189*0Sstevel@tonic-gate error = 0; 1190*0Sstevel@tonic-gate if (eofp) 1191*0Sstevel@tonic-gate *eofp = 1; 1192*0Sstevel@tonic-gate } 1193*0Sstevel@tonic-gate break; 1194*0Sstevel@tonic-gate } 1195*0Sstevel@tonic-gate } 1196*0Sstevel@tonic-gate if (ep->pcd_filename[0] == PCD_UNUSED) { 1197*0Sstevel@tonic-gate if (eofp) 1198*0Sstevel@tonic-gate *eofp = 1; 1199*0Sstevel@tonic-gate break; 1200*0Sstevel@tonic-gate } 1201*0Sstevel@tonic-gate /* 1202*0Sstevel@tonic-gate * Don't display label because it may contain funny characters. 1203*0Sstevel@tonic-gate */ 1204*0Sstevel@tonic-gate if (ep->pcd_filename[0] == PCD_ERASED) { 1205*0Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir); 1206*0Sstevel@tonic-gate offset += sizeof (struct pcdir); 1207*0Sstevel@tonic-gate ep++; 1208*0Sstevel@tonic-gate continue; 1209*0Sstevel@tonic-gate } 1210*0Sstevel@tonic-gate if (PCDL_IS_LFN(ep)) { 1211*0Sstevel@tonic-gate if (pc_read_long_fn(dvp, uiop, ld, &ep, &offset, &bp) != 1212*0Sstevel@tonic-gate 0) 1213*0Sstevel@tonic-gate break; 1214*0Sstevel@tonic-gate continue; 1215*0Sstevel@tonic-gate } 1216*0Sstevel@tonic-gate 1217*0Sstevel@tonic-gate if (pc_read_short_fn(dvp, uiop, ld, &ep, &offset, &bp) != 0) 1218*0Sstevel@tonic-gate break; 1219*0Sstevel@tonic-gate } 1220*0Sstevel@tonic-gate if (bp) 1221*0Sstevel@tonic-gate brelse(bp); 1222*0Sstevel@tonic-gate pc_unlockfs(fsp); 1223*0Sstevel@tonic-gate return (error); 1224*0Sstevel@tonic-gate } 1225*0Sstevel@tonic-gate 1226*0Sstevel@tonic-gate 1227*0Sstevel@tonic-gate /* 1228*0Sstevel@tonic-gate * Called from pvn_getpages or pcfs_getpage to get a particular page. 1229*0Sstevel@tonic-gate * When we are called the pcfs is already locked. 1230*0Sstevel@tonic-gate */ 1231*0Sstevel@tonic-gate /*ARGSUSED*/ 1232*0Sstevel@tonic-gate static int 1233*0Sstevel@tonic-gate pcfs_getapage( 1234*0Sstevel@tonic-gate struct vnode *vp, 1235*0Sstevel@tonic-gate u_offset_t off, 1236*0Sstevel@tonic-gate size_t len, 1237*0Sstevel@tonic-gate uint_t *protp, 1238*0Sstevel@tonic-gate page_t *pl[], /* NULL if async IO is requested */ 1239*0Sstevel@tonic-gate size_t plsz, 1240*0Sstevel@tonic-gate struct seg *seg, 1241*0Sstevel@tonic-gate caddr_t addr, 1242*0Sstevel@tonic-gate enum seg_rw rw, 1243*0Sstevel@tonic-gate struct cred *cr) 1244*0Sstevel@tonic-gate { 1245*0Sstevel@tonic-gate struct pcnode *pcp; 1246*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 1247*0Sstevel@tonic-gate struct vnode *devvp; 1248*0Sstevel@tonic-gate page_t *pp; 1249*0Sstevel@tonic-gate page_t *pagefound; 1250*0Sstevel@tonic-gate int err; 1251*0Sstevel@tonic-gate 1252*0Sstevel@tonic-gate PC_DPRINTF3(5, "pcfs_getapage: vp=%p off=%lld len=%lu\n", 1253*0Sstevel@tonic-gate (void *)vp, off, len); 1254*0Sstevel@tonic-gate 1255*0Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) 1256*0Sstevel@tonic-gate return (EIO); 1257*0Sstevel@tonic-gate devvp = fsp->pcfs_devvp; 1258*0Sstevel@tonic-gate 1259*0Sstevel@tonic-gate /* pcfs doesn't do readaheads */ 1260*0Sstevel@tonic-gate if (pl == NULL) 1261*0Sstevel@tonic-gate return (0); 1262*0Sstevel@tonic-gate 1263*0Sstevel@tonic-gate pl[0] = NULL; 1264*0Sstevel@tonic-gate err = 0; 1265*0Sstevel@tonic-gate /* 1266*0Sstevel@tonic-gate * If the accessed time on the pcnode has not already been 1267*0Sstevel@tonic-gate * set elsewhere (e.g. for read/setattr) we set the time now. 1268*0Sstevel@tonic-gate * This gives us approximate modified times for mmap'ed files 1269*0Sstevel@tonic-gate * which are accessed via loads in the user address space. 1270*0Sstevel@tonic-gate */ 1271*0Sstevel@tonic-gate if ((pcp->pc_flags & PC_ACC) == 0 && 1272*0Sstevel@tonic-gate ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0)) { 1273*0Sstevel@tonic-gate pcp->pc_flags |= PC_ACC; 1274*0Sstevel@tonic-gate pc_mark_acc(pcp); 1275*0Sstevel@tonic-gate } 1276*0Sstevel@tonic-gate reread: 1277*0Sstevel@tonic-gate if ((pagefound = page_exists(vp, off)) == NULL) { 1278*0Sstevel@tonic-gate /* 1279*0Sstevel@tonic-gate * Need to really do disk IO to get the page(s). 1280*0Sstevel@tonic-gate */ 1281*0Sstevel@tonic-gate struct buf *bp; 1282*0Sstevel@tonic-gate daddr_t lbn, bn; 1283*0Sstevel@tonic-gate u_offset_t io_off; 1284*0Sstevel@tonic-gate size_t io_len; 1285*0Sstevel@tonic-gate u_offset_t lbnoff, xferoffset; 1286*0Sstevel@tonic-gate u_offset_t pgoff; 1287*0Sstevel@tonic-gate uint_t xfersize; 1288*0Sstevel@tonic-gate int err1; 1289*0Sstevel@tonic-gate 1290*0Sstevel@tonic-gate lbn = pc_lblkno(fsp, off); 1291*0Sstevel@tonic-gate lbnoff = off & ~(fsp->pcfs_clsize - 1); 1292*0Sstevel@tonic-gate xferoffset = off & ~(fsp->pcfs_secsize - 1); 1293*0Sstevel@tonic-gate 1294*0Sstevel@tonic-gate pp = pvn_read_kluster(vp, off, seg, addr, &io_off, &io_len, 1295*0Sstevel@tonic-gate off, (size_t)MIN(pc_blksize(fsp, pcp, off), PAGESIZE), 0); 1296*0Sstevel@tonic-gate if (pp == NULL) 1297*0Sstevel@tonic-gate /* 1298*0Sstevel@tonic-gate * XXX - If pcfs is made MT-hot, this should go 1299*0Sstevel@tonic-gate * back to reread. 1300*0Sstevel@tonic-gate */ 1301*0Sstevel@tonic-gate panic("pcfs_getapage pvn_read_kluster"); 1302*0Sstevel@tonic-gate 1303*0Sstevel@tonic-gate for (pgoff = 0; pgoff < PAGESIZE && xferoffset < pcp->pc_size; 1304*0Sstevel@tonic-gate pgoff += xfersize, 1305*0Sstevel@tonic-gate lbn += howmany(xfersize, fsp->pcfs_clsize), 1306*0Sstevel@tonic-gate lbnoff += xfersize, xferoffset += xfersize) { 1307*0Sstevel@tonic-gate /* 1308*0Sstevel@tonic-gate * read as many contiguous blocks as possible to 1309*0Sstevel@tonic-gate * fill this page 1310*0Sstevel@tonic-gate */ 1311*0Sstevel@tonic-gate xfersize = PAGESIZE - pgoff; 1312*0Sstevel@tonic-gate err1 = pc_bmap(pcp, lbn, &bn, &xfersize); 1313*0Sstevel@tonic-gate if (err1) { 1314*0Sstevel@tonic-gate PC_DPRINTF1(1, "pc_getapage err=%d", err1); 1315*0Sstevel@tonic-gate err = err1; 1316*0Sstevel@tonic-gate goto out; 1317*0Sstevel@tonic-gate } 1318*0Sstevel@tonic-gate bp = pageio_setup(pp, xfersize, devvp, B_READ); 1319*0Sstevel@tonic-gate bp->b_edev = devvp->v_rdev; 1320*0Sstevel@tonic-gate bp->b_dev = cmpdev(devvp->v_rdev); 1321*0Sstevel@tonic-gate bp->b_blkno = bn + 1322*0Sstevel@tonic-gate /* add a sector offset within the cluster */ 1323*0Sstevel@tonic-gate /* when the clustersize > PAGESIZE */ 1324*0Sstevel@tonic-gate (xferoffset - lbnoff) / fsp->pcfs_secsize; 1325*0Sstevel@tonic-gate bp->b_un.b_addr = (caddr_t)pgoff; 1326*0Sstevel@tonic-gate bp->b_file = vp; 1327*0Sstevel@tonic-gate bp->b_offset = (offset_t)(off + pgoff); 1328*0Sstevel@tonic-gate 1329*0Sstevel@tonic-gate (void) bdev_strategy(bp); 1330*0Sstevel@tonic-gate 1331*0Sstevel@tonic-gate lwp_stat_update(LWP_STAT_INBLK, 1); 1332*0Sstevel@tonic-gate 1333*0Sstevel@tonic-gate if (err == 0) 1334*0Sstevel@tonic-gate err = biowait(bp); 1335*0Sstevel@tonic-gate else 1336*0Sstevel@tonic-gate (void) biowait(bp); 1337*0Sstevel@tonic-gate pageio_done(bp); 1338*0Sstevel@tonic-gate if (err) 1339*0Sstevel@tonic-gate goto out; 1340*0Sstevel@tonic-gate } 1341*0Sstevel@tonic-gate if (pgoff < PAGESIZE) { 1342*0Sstevel@tonic-gate pagezero(pp->p_prev, pgoff, PAGESIZE - pgoff); 1343*0Sstevel@tonic-gate } 1344*0Sstevel@tonic-gate pvn_plist_init(pp, pl, plsz, off, io_len, rw); 1345*0Sstevel@tonic-gate } 1346*0Sstevel@tonic-gate out: 1347*0Sstevel@tonic-gate if (err) { 1348*0Sstevel@tonic-gate if (pp != NULL) 1349*0Sstevel@tonic-gate pvn_read_done(pp, B_ERROR); 1350*0Sstevel@tonic-gate return (err); 1351*0Sstevel@tonic-gate } 1352*0Sstevel@tonic-gate 1353*0Sstevel@tonic-gate if (pagefound) { 1354*0Sstevel@tonic-gate /* 1355*0Sstevel@tonic-gate * Page exists in the cache, acquire the "shared" 1356*0Sstevel@tonic-gate * lock. If this fails, go back to reread. 1357*0Sstevel@tonic-gate */ 1358*0Sstevel@tonic-gate if ((pp = page_lookup(vp, off, SE_SHARED)) == NULL) { 1359*0Sstevel@tonic-gate goto reread; 1360*0Sstevel@tonic-gate } 1361*0Sstevel@tonic-gate pl[0] = pp; 1362*0Sstevel@tonic-gate pl[1] = NULL; 1363*0Sstevel@tonic-gate } 1364*0Sstevel@tonic-gate return (err); 1365*0Sstevel@tonic-gate } 1366*0Sstevel@tonic-gate 1367*0Sstevel@tonic-gate /* 1368*0Sstevel@tonic-gate * Return all the pages from [off..off+len] in given file 1369*0Sstevel@tonic-gate */ 1370*0Sstevel@tonic-gate static int 1371*0Sstevel@tonic-gate pcfs_getpage( 1372*0Sstevel@tonic-gate struct vnode *vp, 1373*0Sstevel@tonic-gate offset_t off, 1374*0Sstevel@tonic-gate size_t len, 1375*0Sstevel@tonic-gate uint_t *protp, 1376*0Sstevel@tonic-gate page_t *pl[], 1377*0Sstevel@tonic-gate size_t plsz, 1378*0Sstevel@tonic-gate struct seg *seg, 1379*0Sstevel@tonic-gate caddr_t addr, 1380*0Sstevel@tonic-gate enum seg_rw rw, 1381*0Sstevel@tonic-gate struct cred *cr) 1382*0Sstevel@tonic-gate { 1383*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 1384*0Sstevel@tonic-gate int err; 1385*0Sstevel@tonic-gate 1386*0Sstevel@tonic-gate PC_DPRINTF0(6, "pcfs_getpage\n"); 1387*0Sstevel@tonic-gate if (err = pc_verify(fsp)) 1388*0Sstevel@tonic-gate return (err); 1389*0Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 1390*0Sstevel@tonic-gate return (ENOSYS); 1391*0Sstevel@tonic-gate ASSERT(off <= UINT32_MAX); 1392*0Sstevel@tonic-gate err = pc_lockfs(fsp, 0, 0); 1393*0Sstevel@tonic-gate if (err) 1394*0Sstevel@tonic-gate return (err); 1395*0Sstevel@tonic-gate if (protp != NULL) 1396*0Sstevel@tonic-gate *protp = PROT_ALL; 1397*0Sstevel@tonic-gate 1398*0Sstevel@tonic-gate ASSERT((off & PAGEOFFSET) == 0); 1399*0Sstevel@tonic-gate if (len <= PAGESIZE) { 1400*0Sstevel@tonic-gate err = pcfs_getapage(vp, off, len, protp, pl, 1401*0Sstevel@tonic-gate plsz, seg, addr, rw, cr); 1402*0Sstevel@tonic-gate } else { 1403*0Sstevel@tonic-gate err = pvn_getpages(pcfs_getapage, vp, off, 1404*0Sstevel@tonic-gate len, protp, pl, plsz, seg, addr, rw, cr); 1405*0Sstevel@tonic-gate } 1406*0Sstevel@tonic-gate pc_unlockfs(fsp); 1407*0Sstevel@tonic-gate return (err); 1408*0Sstevel@tonic-gate } 1409*0Sstevel@tonic-gate 1410*0Sstevel@tonic-gate 1411*0Sstevel@tonic-gate /* 1412*0Sstevel@tonic-gate * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE} 1413*0Sstevel@tonic-gate * If len == 0, do from off to EOF. 1414*0Sstevel@tonic-gate * 1415*0Sstevel@tonic-gate * The normal cases should be len == 0 & off == 0 (entire vp list), 1416*0Sstevel@tonic-gate * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE 1417*0Sstevel@tonic-gate * (from pageout). 1418*0Sstevel@tonic-gate * 1419*0Sstevel@tonic-gate */ 1420*0Sstevel@tonic-gate /*ARGSUSED*/ 1421*0Sstevel@tonic-gate static int 1422*0Sstevel@tonic-gate pcfs_putpage( 1423*0Sstevel@tonic-gate struct vnode *vp, 1424*0Sstevel@tonic-gate offset_t off, 1425*0Sstevel@tonic-gate size_t len, 1426*0Sstevel@tonic-gate int flags, 1427*0Sstevel@tonic-gate struct cred *cr) 1428*0Sstevel@tonic-gate { 1429*0Sstevel@tonic-gate struct pcnode *pcp; 1430*0Sstevel@tonic-gate page_t *pp; 1431*0Sstevel@tonic-gate struct pcfs *fsp; 1432*0Sstevel@tonic-gate u_offset_t io_off; 1433*0Sstevel@tonic-gate size_t io_len; 1434*0Sstevel@tonic-gate offset_t eoff; 1435*0Sstevel@tonic-gate int err; 1436*0Sstevel@tonic-gate 1437*0Sstevel@tonic-gate PC_DPRINTF1(6, "pcfs_putpage vp=0x%p\n", (void *)vp); 1438*0Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 1439*0Sstevel@tonic-gate return (ENOSYS); 1440*0Sstevel@tonic-gate 1441*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 1442*0Sstevel@tonic-gate 1443*0Sstevel@tonic-gate if (err = pc_verify(fsp)) 1444*0Sstevel@tonic-gate return (err); 1445*0Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) { 1446*0Sstevel@tonic-gate PC_DPRINTF1(3, "pcfs_putpage NULL vp=0x%p\n", (void *)vp); 1447*0Sstevel@tonic-gate return (EIO); 1448*0Sstevel@tonic-gate } 1449*0Sstevel@tonic-gate 1450*0Sstevel@tonic-gate if (curproc == proc_pageout) { 1451*0Sstevel@tonic-gate /* 1452*0Sstevel@tonic-gate * XXX - This is a quick hack to avoid blocking 1453*0Sstevel@tonic-gate * pageout. Also to avoid pcfs_getapage deadlocking 1454*0Sstevel@tonic-gate * with putpage when memory is running out, 1455*0Sstevel@tonic-gate * since we only have one global lock and we don't 1456*0Sstevel@tonic-gate * support async putpage. 1457*0Sstevel@tonic-gate * It should be fixed someday. 1458*0Sstevel@tonic-gate * 1459*0Sstevel@tonic-gate * Interestingly, this used to be a test of NOMEMWAIT(). 1460*0Sstevel@tonic-gate * We only ever got here once pcfs started supporting 1461*0Sstevel@tonic-gate * NFS sharing, and then only because the NFS server 1462*0Sstevel@tonic-gate * threads seem to do writes in sched's process context. 1463*0Sstevel@tonic-gate * Since everyone else seems to just care about pageout, 1464*0Sstevel@tonic-gate * the test was changed to look for pageout directly. 1465*0Sstevel@tonic-gate */ 1466*0Sstevel@tonic-gate return (ENOMEM); 1467*0Sstevel@tonic-gate } 1468*0Sstevel@tonic-gate 1469*0Sstevel@tonic-gate ASSERT(off <= UINT32_MAX); 1470*0Sstevel@tonic-gate 1471*0Sstevel@tonic-gate flags &= ~B_ASYNC; /* XXX should fix this later */ 1472*0Sstevel@tonic-gate 1473*0Sstevel@tonic-gate err = pc_lockfs(fsp, 0, 0); 1474*0Sstevel@tonic-gate if (err) 1475*0Sstevel@tonic-gate return (err); 1476*0Sstevel@tonic-gate if (!vn_has_cached_data(vp) || off >= pcp->pc_size) { 1477*0Sstevel@tonic-gate pc_unlockfs(fsp); 1478*0Sstevel@tonic-gate return (0); 1479*0Sstevel@tonic-gate } 1480*0Sstevel@tonic-gate 1481*0Sstevel@tonic-gate if (len == 0) { 1482*0Sstevel@tonic-gate /* 1483*0Sstevel@tonic-gate * Search the entire vp list for pages >= off 1484*0Sstevel@tonic-gate */ 1485*0Sstevel@tonic-gate err = pvn_vplist_dirty(vp, off, 1486*0Sstevel@tonic-gate pcfs_putapage, flags, cr); 1487*0Sstevel@tonic-gate } else { 1488*0Sstevel@tonic-gate eoff = off + len; 1489*0Sstevel@tonic-gate 1490*0Sstevel@tonic-gate for (io_off = off; io_off < eoff && 1491*0Sstevel@tonic-gate io_off < pcp->pc_size; io_off += io_len) { 1492*0Sstevel@tonic-gate /* 1493*0Sstevel@tonic-gate * If we are not invalidating, synchronously 1494*0Sstevel@tonic-gate * freeing or writing pages use the routine 1495*0Sstevel@tonic-gate * page_lookup_nowait() to prevent reclaiming 1496*0Sstevel@tonic-gate * them from the free list. 1497*0Sstevel@tonic-gate */ 1498*0Sstevel@tonic-gate if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) { 1499*0Sstevel@tonic-gate pp = page_lookup(vp, io_off, 1500*0Sstevel@tonic-gate (flags & (B_INVAL | B_FREE)) ? 1501*0Sstevel@tonic-gate SE_EXCL : SE_SHARED); 1502*0Sstevel@tonic-gate } else { 1503*0Sstevel@tonic-gate pp = page_lookup_nowait(vp, io_off, 1504*0Sstevel@tonic-gate (flags & B_FREE) ? SE_EXCL : SE_SHARED); 1505*0Sstevel@tonic-gate } 1506*0Sstevel@tonic-gate 1507*0Sstevel@tonic-gate if (pp == NULL || pvn_getdirty(pp, flags) == 0) 1508*0Sstevel@tonic-gate io_len = PAGESIZE; 1509*0Sstevel@tonic-gate else { 1510*0Sstevel@tonic-gate err = pcfs_putapage(vp, pp, &io_off, &io_len, 1511*0Sstevel@tonic-gate flags, cr); 1512*0Sstevel@tonic-gate if (err != 0) 1513*0Sstevel@tonic-gate break; 1514*0Sstevel@tonic-gate /* 1515*0Sstevel@tonic-gate * "io_off" and "io_len" are returned as 1516*0Sstevel@tonic-gate * the range of pages we actually wrote. 1517*0Sstevel@tonic-gate * This allows us to skip ahead more quickly 1518*0Sstevel@tonic-gate * since several pages may've been dealt 1519*0Sstevel@tonic-gate * with by this iteration of the loop. 1520*0Sstevel@tonic-gate */ 1521*0Sstevel@tonic-gate } 1522*0Sstevel@tonic-gate } 1523*0Sstevel@tonic-gate } 1524*0Sstevel@tonic-gate if (err == 0 && (flags & B_INVAL) && 1525*0Sstevel@tonic-gate off == 0 && len == 0 && vn_has_cached_data(vp)) { 1526*0Sstevel@tonic-gate /* 1527*0Sstevel@tonic-gate * If doing "invalidation", make sure that 1528*0Sstevel@tonic-gate * all pages on the vnode list are actually 1529*0Sstevel@tonic-gate * gone. 1530*0Sstevel@tonic-gate */ 1531*0Sstevel@tonic-gate cmn_err(CE_PANIC, 1532*0Sstevel@tonic-gate "pcfs_putpage: B_INVAL, pages not gone"); 1533*0Sstevel@tonic-gate } else if (err) { 1534*0Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_putpage err=%d\n", err); 1535*0Sstevel@tonic-gate } 1536*0Sstevel@tonic-gate pc_unlockfs(fsp); 1537*0Sstevel@tonic-gate return (err); 1538*0Sstevel@tonic-gate } 1539*0Sstevel@tonic-gate 1540*0Sstevel@tonic-gate /* 1541*0Sstevel@tonic-gate * Write out a single page, possibly klustering adjacent dirty pages. 1542*0Sstevel@tonic-gate */ 1543*0Sstevel@tonic-gate /*ARGSUSED*/ 1544*0Sstevel@tonic-gate int 1545*0Sstevel@tonic-gate pcfs_putapage( 1546*0Sstevel@tonic-gate struct vnode *vp, 1547*0Sstevel@tonic-gate page_t *pp, 1548*0Sstevel@tonic-gate u_offset_t *offp, 1549*0Sstevel@tonic-gate size_t *lenp, 1550*0Sstevel@tonic-gate int flags, 1551*0Sstevel@tonic-gate struct cred *cr) 1552*0Sstevel@tonic-gate { 1553*0Sstevel@tonic-gate struct pcnode *pcp; 1554*0Sstevel@tonic-gate struct pcfs *fsp; 1555*0Sstevel@tonic-gate struct vnode *devvp; 1556*0Sstevel@tonic-gate size_t io_len; 1557*0Sstevel@tonic-gate daddr_t bn; 1558*0Sstevel@tonic-gate u_offset_t lbn, lbnoff, xferoffset; 1559*0Sstevel@tonic-gate uint_t pgoff, xfersize; 1560*0Sstevel@tonic-gate int err = 0; 1561*0Sstevel@tonic-gate u_offset_t io_off; 1562*0Sstevel@tonic-gate 1563*0Sstevel@tonic-gate pcp = VTOPC(vp); 1564*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 1565*0Sstevel@tonic-gate devvp = fsp->pcfs_devvp; 1566*0Sstevel@tonic-gate 1567*0Sstevel@tonic-gate /* 1568*0Sstevel@tonic-gate * If the modified time on the inode has not already been 1569*0Sstevel@tonic-gate * set elsewhere (e.g. for write/setattr) and this is not 1570*0Sstevel@tonic-gate * a call from msync (B_FORCE) we set the time now. 1571*0Sstevel@tonic-gate * This gives us approximate modified times for mmap'ed files 1572*0Sstevel@tonic-gate * which are modified via stores in the user address space. 1573*0Sstevel@tonic-gate */ 1574*0Sstevel@tonic-gate if ((pcp->pc_flags & PC_MOD) == 0 || (flags & B_FORCE)) { 1575*0Sstevel@tonic-gate pcp->pc_flags |= PC_MOD; 1576*0Sstevel@tonic-gate pc_mark_mod(pcp); 1577*0Sstevel@tonic-gate } 1578*0Sstevel@tonic-gate pp = pvn_write_kluster(vp, pp, &io_off, &io_len, pp->p_offset, 1579*0Sstevel@tonic-gate PAGESIZE, flags); 1580*0Sstevel@tonic-gate 1581*0Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_IRRECOV) { 1582*0Sstevel@tonic-gate goto out; 1583*0Sstevel@tonic-gate } 1584*0Sstevel@tonic-gate 1585*0Sstevel@tonic-gate PC_DPRINTF1(7, "pc_putpage writing dirty page off=%llu\n", io_off); 1586*0Sstevel@tonic-gate 1587*0Sstevel@tonic-gate lbn = pc_lblkno(fsp, io_off); 1588*0Sstevel@tonic-gate lbnoff = io_off & ~(fsp->pcfs_clsize - 1); 1589*0Sstevel@tonic-gate xferoffset = io_off & ~(fsp->pcfs_secsize - 1); 1590*0Sstevel@tonic-gate 1591*0Sstevel@tonic-gate for (pgoff = 0; pgoff < io_len && xferoffset < pcp->pc_size; 1592*0Sstevel@tonic-gate pgoff += xfersize, 1593*0Sstevel@tonic-gate lbn += howmany(xfersize, fsp->pcfs_clsize), 1594*0Sstevel@tonic-gate lbnoff += xfersize, xferoffset += xfersize) { 1595*0Sstevel@tonic-gate 1596*0Sstevel@tonic-gate struct buf *bp; 1597*0Sstevel@tonic-gate int err1; 1598*0Sstevel@tonic-gate 1599*0Sstevel@tonic-gate /* 1600*0Sstevel@tonic-gate * write as many contiguous blocks as possible from this page 1601*0Sstevel@tonic-gate */ 1602*0Sstevel@tonic-gate xfersize = io_len - pgoff; 1603*0Sstevel@tonic-gate err1 = pc_bmap(pcp, (daddr_t)lbn, &bn, &xfersize); 1604*0Sstevel@tonic-gate if (err1) { 1605*0Sstevel@tonic-gate err = err1; 1606*0Sstevel@tonic-gate goto out; 1607*0Sstevel@tonic-gate } 1608*0Sstevel@tonic-gate bp = pageio_setup(pp, xfersize, devvp, B_WRITE | flags); 1609*0Sstevel@tonic-gate bp->b_edev = devvp->v_rdev; 1610*0Sstevel@tonic-gate bp->b_dev = cmpdev(devvp->v_rdev); 1611*0Sstevel@tonic-gate bp->b_blkno = bn + 1612*0Sstevel@tonic-gate /* add a sector offset within the cluster */ 1613*0Sstevel@tonic-gate /* when the clustersize > PAGESIZE */ 1614*0Sstevel@tonic-gate (xferoffset - lbnoff) / fsp->pcfs_secsize; 1615*0Sstevel@tonic-gate bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff; 1616*0Sstevel@tonic-gate bp->b_file = vp; 1617*0Sstevel@tonic-gate bp->b_offset = (offset_t)(io_off + pgoff); 1618*0Sstevel@tonic-gate 1619*0Sstevel@tonic-gate (void) bdev_strategy(bp); 1620*0Sstevel@tonic-gate 1621*0Sstevel@tonic-gate lwp_stat_update(LWP_STAT_OUBLK, 1); 1622*0Sstevel@tonic-gate 1623*0Sstevel@tonic-gate if (err == 0) 1624*0Sstevel@tonic-gate err = biowait(bp); 1625*0Sstevel@tonic-gate else 1626*0Sstevel@tonic-gate (void) biowait(bp); 1627*0Sstevel@tonic-gate pageio_done(bp); 1628*0Sstevel@tonic-gate } 1629*0Sstevel@tonic-gate pvn_write_done(pp, ((err) ? B_ERROR : 0) | B_WRITE | flags); 1630*0Sstevel@tonic-gate pp = NULL; 1631*0Sstevel@tonic-gate 1632*0Sstevel@tonic-gate out: 1633*0Sstevel@tonic-gate if ((fsp->pcfs_flags & PCFS_IRRECOV) && pp != NULL) { 1634*0Sstevel@tonic-gate pvn_write_done(pp, B_WRITE | flags); 1635*0Sstevel@tonic-gate } else if (err != 0 && pp != NULL) { 1636*0Sstevel@tonic-gate pvn_write_done(pp, B_ERROR | B_WRITE | flags); 1637*0Sstevel@tonic-gate } 1638*0Sstevel@tonic-gate 1639*0Sstevel@tonic-gate if (offp) 1640*0Sstevel@tonic-gate *offp = io_off; 1641*0Sstevel@tonic-gate if (lenp) 1642*0Sstevel@tonic-gate *lenp = io_len; 1643*0Sstevel@tonic-gate PC_DPRINTF4(4, "pcfs_putapage: vp=%p pp=%p off=%lld len=%lu\n", 1644*0Sstevel@tonic-gate (void *)vp, (void *)pp, io_off, io_len); 1645*0Sstevel@tonic-gate if (err) { 1646*0Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_putapage err=%d", err); 1647*0Sstevel@tonic-gate } 1648*0Sstevel@tonic-gate return (err); 1649*0Sstevel@tonic-gate } 1650*0Sstevel@tonic-gate 1651*0Sstevel@tonic-gate /*ARGSUSED*/ 1652*0Sstevel@tonic-gate static int 1653*0Sstevel@tonic-gate pcfs_map( 1654*0Sstevel@tonic-gate struct vnode *vp, 1655*0Sstevel@tonic-gate offset_t off, 1656*0Sstevel@tonic-gate struct as *as, 1657*0Sstevel@tonic-gate caddr_t *addrp, 1658*0Sstevel@tonic-gate size_t len, 1659*0Sstevel@tonic-gate uchar_t prot, 1660*0Sstevel@tonic-gate uchar_t maxprot, 1661*0Sstevel@tonic-gate uint_t flags, 1662*0Sstevel@tonic-gate struct cred *cr) 1663*0Sstevel@tonic-gate { 1664*0Sstevel@tonic-gate struct segvn_crargs vn_a; 1665*0Sstevel@tonic-gate int error; 1666*0Sstevel@tonic-gate 1667*0Sstevel@tonic-gate PC_DPRINTF0(6, "pcfs_map\n"); 1668*0Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 1669*0Sstevel@tonic-gate return (ENOSYS); 1670*0Sstevel@tonic-gate 1671*0Sstevel@tonic-gate if (off > UINT32_MAX || off + len > UINT32_MAX) 1672*0Sstevel@tonic-gate return (ENXIO); 1673*0Sstevel@tonic-gate 1674*0Sstevel@tonic-gate as_rangelock(as); 1675*0Sstevel@tonic-gate if ((flags & MAP_FIXED) == 0) { 1676*0Sstevel@tonic-gate map_addr(addrp, len, off, 1, flags); 1677*0Sstevel@tonic-gate if (*addrp == NULL) { 1678*0Sstevel@tonic-gate as_rangeunlock(as); 1679*0Sstevel@tonic-gate return (ENOMEM); 1680*0Sstevel@tonic-gate } 1681*0Sstevel@tonic-gate } else { 1682*0Sstevel@tonic-gate /* 1683*0Sstevel@tonic-gate * User specified address - blow away any previous mappings 1684*0Sstevel@tonic-gate */ 1685*0Sstevel@tonic-gate (void) as_unmap(as, *addrp, len); 1686*0Sstevel@tonic-gate } 1687*0Sstevel@tonic-gate 1688*0Sstevel@tonic-gate vn_a.vp = vp; 1689*0Sstevel@tonic-gate vn_a.offset = off; 1690*0Sstevel@tonic-gate vn_a.type = flags & MAP_TYPE; 1691*0Sstevel@tonic-gate vn_a.prot = prot; 1692*0Sstevel@tonic-gate vn_a.maxprot = maxprot; 1693*0Sstevel@tonic-gate vn_a.flags = flags & ~MAP_TYPE; 1694*0Sstevel@tonic-gate vn_a.cred = cr; 1695*0Sstevel@tonic-gate vn_a.amp = NULL; 1696*0Sstevel@tonic-gate vn_a.szc = 0; 1697*0Sstevel@tonic-gate vn_a.lgrp_mem_policy_flags = 0; 1698*0Sstevel@tonic-gate 1699*0Sstevel@tonic-gate error = as_map(as, *addrp, len, segvn_create, &vn_a); 1700*0Sstevel@tonic-gate as_rangeunlock(as); 1701*0Sstevel@tonic-gate return (error); 1702*0Sstevel@tonic-gate } 1703*0Sstevel@tonic-gate 1704*0Sstevel@tonic-gate /* ARGSUSED */ 1705*0Sstevel@tonic-gate static int 1706*0Sstevel@tonic-gate pcfs_seek( 1707*0Sstevel@tonic-gate struct vnode *vp, 1708*0Sstevel@tonic-gate offset_t ooff, 1709*0Sstevel@tonic-gate offset_t *noffp) 1710*0Sstevel@tonic-gate { 1711*0Sstevel@tonic-gate if (*noffp < 0) 1712*0Sstevel@tonic-gate return (EINVAL); 1713*0Sstevel@tonic-gate else if (*noffp > MAXOFFSET_T) 1714*0Sstevel@tonic-gate return (EINVAL); 1715*0Sstevel@tonic-gate else 1716*0Sstevel@tonic-gate return (0); 1717*0Sstevel@tonic-gate } 1718*0Sstevel@tonic-gate 1719*0Sstevel@tonic-gate /* ARGSUSED */ 1720*0Sstevel@tonic-gate static int 1721*0Sstevel@tonic-gate pcfs_addmap( 1722*0Sstevel@tonic-gate struct vnode *vp, 1723*0Sstevel@tonic-gate offset_t off, 1724*0Sstevel@tonic-gate struct as *as, 1725*0Sstevel@tonic-gate caddr_t addr, 1726*0Sstevel@tonic-gate size_t len, 1727*0Sstevel@tonic-gate uchar_t prot, 1728*0Sstevel@tonic-gate uchar_t maxprot, 1729*0Sstevel@tonic-gate uint_t flags, 1730*0Sstevel@tonic-gate struct cred *cr) 1731*0Sstevel@tonic-gate { 1732*0Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 1733*0Sstevel@tonic-gate return (ENOSYS); 1734*0Sstevel@tonic-gate return (0); 1735*0Sstevel@tonic-gate } 1736*0Sstevel@tonic-gate 1737*0Sstevel@tonic-gate /*ARGSUSED*/ 1738*0Sstevel@tonic-gate static int 1739*0Sstevel@tonic-gate pcfs_delmap( 1740*0Sstevel@tonic-gate struct vnode *vp, 1741*0Sstevel@tonic-gate offset_t off, 1742*0Sstevel@tonic-gate struct as *as, 1743*0Sstevel@tonic-gate caddr_t addr, 1744*0Sstevel@tonic-gate size_t len, 1745*0Sstevel@tonic-gate uint_t prot, 1746*0Sstevel@tonic-gate uint_t maxprot, 1747*0Sstevel@tonic-gate uint_t flags, 1748*0Sstevel@tonic-gate struct cred *cr) 1749*0Sstevel@tonic-gate { 1750*0Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 1751*0Sstevel@tonic-gate return (ENOSYS); 1752*0Sstevel@tonic-gate return (0); 1753*0Sstevel@tonic-gate } 1754*0Sstevel@tonic-gate 1755*0Sstevel@tonic-gate /* 1756*0Sstevel@tonic-gate * POSIX pathconf() support. 1757*0Sstevel@tonic-gate */ 1758*0Sstevel@tonic-gate /* ARGSUSED */ 1759*0Sstevel@tonic-gate static int 1760*0Sstevel@tonic-gate pcfs_pathconf( 1761*0Sstevel@tonic-gate struct vnode *vp, 1762*0Sstevel@tonic-gate int cmd, 1763*0Sstevel@tonic-gate ulong_t *valp, 1764*0Sstevel@tonic-gate struct cred *cr) 1765*0Sstevel@tonic-gate { 1766*0Sstevel@tonic-gate ulong_t val; 1767*0Sstevel@tonic-gate int error = 0; 1768*0Sstevel@tonic-gate struct statvfs64 vfsbuf; 1769*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 1770*0Sstevel@tonic-gate 1771*0Sstevel@tonic-gate switch (cmd) { 1772*0Sstevel@tonic-gate 1773*0Sstevel@tonic-gate case _PC_LINK_MAX: 1774*0Sstevel@tonic-gate val = 1; 1775*0Sstevel@tonic-gate break; 1776*0Sstevel@tonic-gate 1777*0Sstevel@tonic-gate case _PC_MAX_CANON: 1778*0Sstevel@tonic-gate val = MAX_CANON; 1779*0Sstevel@tonic-gate break; 1780*0Sstevel@tonic-gate 1781*0Sstevel@tonic-gate case _PC_MAX_INPUT: 1782*0Sstevel@tonic-gate val = MAX_INPUT; 1783*0Sstevel@tonic-gate break; 1784*0Sstevel@tonic-gate 1785*0Sstevel@tonic-gate case _PC_NAME_MAX: 1786*0Sstevel@tonic-gate bzero(&vfsbuf, sizeof (vfsbuf)); 1787*0Sstevel@tonic-gate if (error = VFS_STATVFS(vp->v_vfsp, &vfsbuf)) 1788*0Sstevel@tonic-gate break; 1789*0Sstevel@tonic-gate val = vfsbuf.f_namemax; 1790*0Sstevel@tonic-gate break; 1791*0Sstevel@tonic-gate 1792*0Sstevel@tonic-gate case _PC_PATH_MAX: 1793*0Sstevel@tonic-gate case _PC_SYMLINK_MAX: 1794*0Sstevel@tonic-gate val = PCMAXPATHLEN; 1795*0Sstevel@tonic-gate break; 1796*0Sstevel@tonic-gate 1797*0Sstevel@tonic-gate case _PC_PIPE_BUF: 1798*0Sstevel@tonic-gate val = PIPE_BUF; 1799*0Sstevel@tonic-gate break; 1800*0Sstevel@tonic-gate 1801*0Sstevel@tonic-gate case _PC_NO_TRUNC: 1802*0Sstevel@tonic-gate val = (ulong_t)-1; /* Will truncate long file name */ 1803*0Sstevel@tonic-gate break; 1804*0Sstevel@tonic-gate 1805*0Sstevel@tonic-gate case _PC_VDISABLE: 1806*0Sstevel@tonic-gate val = _POSIX_VDISABLE; 1807*0Sstevel@tonic-gate break; 1808*0Sstevel@tonic-gate 1809*0Sstevel@tonic-gate case _PC_CHOWN_RESTRICTED: 1810*0Sstevel@tonic-gate if (rstchown) 1811*0Sstevel@tonic-gate val = rstchown; /* chown restricted enabled */ 1812*0Sstevel@tonic-gate else 1813*0Sstevel@tonic-gate val = (ulong_t)-1; 1814*0Sstevel@tonic-gate break; 1815*0Sstevel@tonic-gate 1816*0Sstevel@tonic-gate case _PC_ACL_ENABLED: 1817*0Sstevel@tonic-gate val = 0; 1818*0Sstevel@tonic-gate break; 1819*0Sstevel@tonic-gate 1820*0Sstevel@tonic-gate case _PC_FILESIZEBITS: 1821*0Sstevel@tonic-gate /* 1822*0Sstevel@tonic-gate * Both FAT16 and FAT32 support 4GB - 1 byte for file size. 1823*0Sstevel@tonic-gate * FAT12 can only go up to the maximum filesystem capacity 1824*0Sstevel@tonic-gate * which is ~509MB. 1825*0Sstevel@tonic-gate */ 1826*0Sstevel@tonic-gate val = IS_FAT12(fsp) ? 30 : 33; 1827*0Sstevel@tonic-gate break; 1828*0Sstevel@tonic-gate default: 1829*0Sstevel@tonic-gate error = EINVAL; 1830*0Sstevel@tonic-gate break; 1831*0Sstevel@tonic-gate } 1832*0Sstevel@tonic-gate 1833*0Sstevel@tonic-gate if (error == 0) 1834*0Sstevel@tonic-gate *valp = val; 1835*0Sstevel@tonic-gate return (error); 1836*0Sstevel@tonic-gate } 1837*0Sstevel@tonic-gate 1838*0Sstevel@tonic-gate /* ARGSUSED */ 1839*0Sstevel@tonic-gate static int 1840*0Sstevel@tonic-gate pcfs_space( 1841*0Sstevel@tonic-gate struct vnode *vp, 1842*0Sstevel@tonic-gate int cmd, 1843*0Sstevel@tonic-gate struct flock64 *bfp, 1844*0Sstevel@tonic-gate int flag, 1845*0Sstevel@tonic-gate offset_t offset, 1846*0Sstevel@tonic-gate cred_t *cr, 1847*0Sstevel@tonic-gate caller_context_t *ct) 1848*0Sstevel@tonic-gate { 1849*0Sstevel@tonic-gate struct vattr vattr; 1850*0Sstevel@tonic-gate int error; 1851*0Sstevel@tonic-gate 1852*0Sstevel@tonic-gate if (cmd != F_FREESP) 1853*0Sstevel@tonic-gate return (EINVAL); 1854*0Sstevel@tonic-gate 1855*0Sstevel@tonic-gate if ((error = convoff(vp, bfp, 0, offset)) == 0) { 1856*0Sstevel@tonic-gate if ((bfp->l_start > UINT32_MAX) || (bfp->l_len > UINT32_MAX)) 1857*0Sstevel@tonic-gate return (EFBIG); 1858*0Sstevel@tonic-gate /* 1859*0Sstevel@tonic-gate * we only support the special case of l_len == 0, 1860*0Sstevel@tonic-gate * meaning free to end of file at this moment. 1861*0Sstevel@tonic-gate */ 1862*0Sstevel@tonic-gate if (bfp->l_len != 0) 1863*0Sstevel@tonic-gate return (EINVAL); 1864*0Sstevel@tonic-gate vattr.va_mask = AT_SIZE; 1865*0Sstevel@tonic-gate vattr.va_size = bfp->l_start; 1866*0Sstevel@tonic-gate error = VOP_SETATTR(vp, &vattr, 0, cr, ct); 1867*0Sstevel@tonic-gate } 1868*0Sstevel@tonic-gate return (error); 1869*0Sstevel@tonic-gate } 1870*0Sstevel@tonic-gate 1871*0Sstevel@tonic-gate /* 1872*0Sstevel@tonic-gate * Break up 'len' chars from 'buf' into a long file name chunk. 1873*0Sstevel@tonic-gate * Pad with '0xff' to make Norton Disk Doctor and Microsoft ScanDisk happy. 1874*0Sstevel@tonic-gate */ 1875*0Sstevel@tonic-gate void 1876*0Sstevel@tonic-gate set_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int len) 1877*0Sstevel@tonic-gate { 1878*0Sstevel@tonic-gate char *tmp = buf; 1879*0Sstevel@tonic-gate int i; 1880*0Sstevel@tonic-gate 1881*0Sstevel@tonic-gate 1882*0Sstevel@tonic-gate for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2) { 1883*0Sstevel@tonic-gate if (len > 0) { 1884*0Sstevel@tonic-gate ep->pcdl_firstfilename[i] = *tmp; 1885*0Sstevel@tonic-gate ep->pcdl_firstfilename[i+1] = 0; 1886*0Sstevel@tonic-gate len--; 1887*0Sstevel@tonic-gate tmp++; 1888*0Sstevel@tonic-gate } else { 1889*0Sstevel@tonic-gate ep->pcdl_firstfilename[i] = (uchar_t)0xff; 1890*0Sstevel@tonic-gate ep->pcdl_firstfilename[i+1] = (uchar_t)0xff; 1891*0Sstevel@tonic-gate } 1892*0Sstevel@tonic-gate } 1893*0Sstevel@tonic-gate 1894*0Sstevel@tonic-gate for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2) { 1895*0Sstevel@tonic-gate if (len > 0) { 1896*0Sstevel@tonic-gate ep->pcdl_secondfilename[i] = *tmp; 1897*0Sstevel@tonic-gate ep->pcdl_secondfilename[i+1] = 0; 1898*0Sstevel@tonic-gate len--; 1899*0Sstevel@tonic-gate tmp++; 1900*0Sstevel@tonic-gate } else { 1901*0Sstevel@tonic-gate ep->pcdl_secondfilename[i] = (uchar_t)0xff; 1902*0Sstevel@tonic-gate ep->pcdl_secondfilename[i+1] = (uchar_t)0xff; 1903*0Sstevel@tonic-gate } 1904*0Sstevel@tonic-gate } 1905*0Sstevel@tonic-gate for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2) { 1906*0Sstevel@tonic-gate if (len > 0) { 1907*0Sstevel@tonic-gate ep->pcdl_thirdfilename[i] = *tmp; 1908*0Sstevel@tonic-gate ep->pcdl_thirdfilename[i+1] = 0; 1909*0Sstevel@tonic-gate len--; 1910*0Sstevel@tonic-gate tmp++; 1911*0Sstevel@tonic-gate } else { 1912*0Sstevel@tonic-gate ep->pcdl_thirdfilename[i] = (uchar_t)0xff; 1913*0Sstevel@tonic-gate ep->pcdl_thirdfilename[i+1] = (uchar_t)0xff; 1914*0Sstevel@tonic-gate } 1915*0Sstevel@tonic-gate } 1916*0Sstevel@tonic-gate } 1917*0Sstevel@tonic-gate 1918*0Sstevel@tonic-gate /* 1919*0Sstevel@tonic-gate * Extract the characters from the long filename chunk into 'buf'. 1920*0Sstevel@tonic-gate * Return the number of characters extracted. 1921*0Sstevel@tonic-gate */ 1922*0Sstevel@tonic-gate static int 1923*0Sstevel@tonic-gate get_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int foldcase) 1924*0Sstevel@tonic-gate { 1925*0Sstevel@tonic-gate char *tmp = buf; 1926*0Sstevel@tonic-gate int i; 1927*0Sstevel@tonic-gate 1928*0Sstevel@tonic-gate for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2, tmp++) { 1929*0Sstevel@tonic-gate if (ep->pcdl_firstfilename[i+1] != '\0') 1930*0Sstevel@tonic-gate return (-1); 1931*0Sstevel@tonic-gate if (foldcase) 1932*0Sstevel@tonic-gate *tmp = tolower(ep->pcdl_firstfilename[i]); 1933*0Sstevel@tonic-gate else 1934*0Sstevel@tonic-gate *tmp = ep->pcdl_firstfilename[i]; 1935*0Sstevel@tonic-gate if (*tmp == '\0') 1936*0Sstevel@tonic-gate return (tmp - buf); 1937*0Sstevel@tonic-gate } 1938*0Sstevel@tonic-gate for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2, tmp++) { 1939*0Sstevel@tonic-gate if (ep->pcdl_secondfilename[i+1] != '\0') 1940*0Sstevel@tonic-gate return (-1); 1941*0Sstevel@tonic-gate if (foldcase) 1942*0Sstevel@tonic-gate *tmp = tolower(ep->pcdl_secondfilename[i]); 1943*0Sstevel@tonic-gate else 1944*0Sstevel@tonic-gate *tmp = ep->pcdl_secondfilename[i]; 1945*0Sstevel@tonic-gate if (*tmp == '\0') 1946*0Sstevel@tonic-gate return (tmp - buf); 1947*0Sstevel@tonic-gate } 1948*0Sstevel@tonic-gate for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2, tmp++) { 1949*0Sstevel@tonic-gate if (ep->pcdl_thirdfilename[i+1] != '\0') 1950*0Sstevel@tonic-gate return (-1); 1951*0Sstevel@tonic-gate if (foldcase) 1952*0Sstevel@tonic-gate *tmp = tolower(ep->pcdl_thirdfilename[i]); 1953*0Sstevel@tonic-gate else 1954*0Sstevel@tonic-gate *tmp = ep->pcdl_thirdfilename[i]; 1955*0Sstevel@tonic-gate if (*tmp == '\0') 1956*0Sstevel@tonic-gate return (tmp - buf); 1957*0Sstevel@tonic-gate } 1958*0Sstevel@tonic-gate *tmp = '\0'; 1959*0Sstevel@tonic-gate return (tmp - buf); 1960*0Sstevel@tonic-gate } 1961*0Sstevel@tonic-gate 1962*0Sstevel@tonic-gate 1963*0Sstevel@tonic-gate /* 1964*0Sstevel@tonic-gate * Checksum the passed in short filename. 1965*0Sstevel@tonic-gate * This is used to validate each component of the long name to make 1966*0Sstevel@tonic-gate * sure the long name is valid (it hasn't been "detached" from the 1967*0Sstevel@tonic-gate * short filename). This algorithm was found in FreeBSD. 1968*0Sstevel@tonic-gate * (sys/fs/msdosfs/msdosfs_conv.c:winChksum(), Wolfgang Solfrank) 1969*0Sstevel@tonic-gate */ 1970*0Sstevel@tonic-gate 1971*0Sstevel@tonic-gate uchar_t 1972*0Sstevel@tonic-gate pc_checksum_long_fn(char *name, char *ext) 1973*0Sstevel@tonic-gate { 1974*0Sstevel@tonic-gate uchar_t c; 1975*0Sstevel@tonic-gate char b[11]; 1976*0Sstevel@tonic-gate 1977*0Sstevel@tonic-gate bcopy(name, b, 8); 1978*0Sstevel@tonic-gate bcopy(ext, b+8, 3); 1979*0Sstevel@tonic-gate 1980*0Sstevel@tonic-gate c = b[0]; 1981*0Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[1]; 1982*0Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[2]; 1983*0Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[3]; 1984*0Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[4]; 1985*0Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[5]; 1986*0Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[6]; 1987*0Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[7]; 1988*0Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[8]; 1989*0Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[9]; 1990*0Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[10]; 1991*0Sstevel@tonic-gate 1992*0Sstevel@tonic-gate return (c); 1993*0Sstevel@tonic-gate } 1994*0Sstevel@tonic-gate 1995*0Sstevel@tonic-gate /* 1996*0Sstevel@tonic-gate * Read a chunk of long filename entries into 'namep'. 1997*0Sstevel@tonic-gate * Return with offset pointing to short entry (on success), or next 1998*0Sstevel@tonic-gate * entry to read (if this wasn't a valid lfn really). 1999*0Sstevel@tonic-gate * Uses the passed-in buffer if it can, otherwise kmem_allocs() room for 2000*0Sstevel@tonic-gate * a long filename. 2001*0Sstevel@tonic-gate * 2002*0Sstevel@tonic-gate * Can also be called with a NULL namep, in which case it just returns 2003*0Sstevel@tonic-gate * whether this was really a valid long filename and consumes it 2004*0Sstevel@tonic-gate * (used by pc_dirempty()). 2005*0Sstevel@tonic-gate */ 2006*0Sstevel@tonic-gate int 2007*0Sstevel@tonic-gate pc_extract_long_fn(struct pcnode *pcp, char *namep, 2008*0Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp) 2009*0Sstevel@tonic-gate { 2010*0Sstevel@tonic-gate struct pcdir *ep = *epp; 2011*0Sstevel@tonic-gate struct pcdir_lfn *lep = (struct pcdir_lfn *)ep; 2012*0Sstevel@tonic-gate struct vnode *dvp = PCTOV(pcp); 2013*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 2014*0Sstevel@tonic-gate char *lfn; 2015*0Sstevel@tonic-gate char *lfn_base; 2016*0Sstevel@tonic-gate int boff; 2017*0Sstevel@tonic-gate int i, cs; 2018*0Sstevel@tonic-gate char buf[20]; 2019*0Sstevel@tonic-gate uchar_t cksum; 2020*0Sstevel@tonic-gate int detached = 0; 2021*0Sstevel@tonic-gate int error = 0; 2022*0Sstevel@tonic-gate int foldcase; 2023*0Sstevel@tonic-gate 2024*0Sstevel@tonic-gate foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE); 2025*0Sstevel@tonic-gate /* use callers buffer unless we didn't get one */ 2026*0Sstevel@tonic-gate if (namep) 2027*0Sstevel@tonic-gate lfn_base = namep; 2028*0Sstevel@tonic-gate else 2029*0Sstevel@tonic-gate lfn_base = kmem_alloc(PCMAXNAMLEN+1, KM_SLEEP); 2030*0Sstevel@tonic-gate lfn = lfn_base + PCMAXNAMLEN - 1; 2031*0Sstevel@tonic-gate *lfn = '\0'; 2032*0Sstevel@tonic-gate cksum = lep->pcdl_checksum; 2033*0Sstevel@tonic-gate 2034*0Sstevel@tonic-gate for (i = (lep->pcdl_ordinal & ~0xc0); i > 0; i--) { 2035*0Sstevel@tonic-gate /* read next block if necessary */ 2036*0Sstevel@tonic-gate boff = pc_blkoff(fsp, *offset); 2037*0Sstevel@tonic-gate if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) { 2038*0Sstevel@tonic-gate if (*bp != NULL) { 2039*0Sstevel@tonic-gate brelse(*bp); 2040*0Sstevel@tonic-gate *bp = NULL; 2041*0Sstevel@tonic-gate } 2042*0Sstevel@tonic-gate error = pc_blkatoff(pcp, *offset, bp, &ep); 2043*0Sstevel@tonic-gate if (error) { 2044*0Sstevel@tonic-gate if (namep == NULL) 2045*0Sstevel@tonic-gate kmem_free(lfn_base, PCMAXNAMLEN+1); 2046*0Sstevel@tonic-gate return (error); 2047*0Sstevel@tonic-gate } 2048*0Sstevel@tonic-gate lep = (struct pcdir_lfn *)ep; 2049*0Sstevel@tonic-gate } 2050*0Sstevel@tonic-gate /* can this happen? Bad fs? */ 2051*0Sstevel@tonic-gate if (!PCDL_IS_LFN((struct pcdir *)lep)) { 2052*0Sstevel@tonic-gate detached = 1; 2053*0Sstevel@tonic-gate break; 2054*0Sstevel@tonic-gate } 2055*0Sstevel@tonic-gate if (cksum != lep->pcdl_checksum) 2056*0Sstevel@tonic-gate detached = 1; 2057*0Sstevel@tonic-gate /* process current entry */ 2058*0Sstevel@tonic-gate cs = get_long_fn_chunk(lep, buf, foldcase); 2059*0Sstevel@tonic-gate if (cs == -1) { 2060*0Sstevel@tonic-gate detached = 1; 2061*0Sstevel@tonic-gate } else { 2062*0Sstevel@tonic-gate for (; cs > 0; cs--) { 2063*0Sstevel@tonic-gate /* see if we underflow */ 2064*0Sstevel@tonic-gate if (lfn >= lfn_base) 2065*0Sstevel@tonic-gate *--lfn = buf[cs - 1]; 2066*0Sstevel@tonic-gate else 2067*0Sstevel@tonic-gate detached = 1; 2068*0Sstevel@tonic-gate } 2069*0Sstevel@tonic-gate } 2070*0Sstevel@tonic-gate lep++; 2071*0Sstevel@tonic-gate *offset += sizeof (struct pcdir); 2072*0Sstevel@tonic-gate } 2073*0Sstevel@tonic-gate /* read next block if necessary */ 2074*0Sstevel@tonic-gate boff = pc_blkoff(fsp, *offset); 2075*0Sstevel@tonic-gate ep = (struct pcdir *)lep; 2076*0Sstevel@tonic-gate if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) { 2077*0Sstevel@tonic-gate if (*bp != NULL) { 2078*0Sstevel@tonic-gate brelse(*bp); 2079*0Sstevel@tonic-gate *bp = NULL; 2080*0Sstevel@tonic-gate } 2081*0Sstevel@tonic-gate error = pc_blkatoff(pcp, *offset, bp, &ep); 2082*0Sstevel@tonic-gate if (error) { 2083*0Sstevel@tonic-gate if (namep == NULL) 2084*0Sstevel@tonic-gate kmem_free(lfn_base, PCMAXNAMLEN+1); 2085*0Sstevel@tonic-gate return (error); 2086*0Sstevel@tonic-gate } 2087*0Sstevel@tonic-gate } 2088*0Sstevel@tonic-gate /* should be on the short one */ 2089*0Sstevel@tonic-gate if (PCDL_IS_LFN(ep) || ((ep->pcd_filename[0] == PCD_UNUSED) || 2090*0Sstevel@tonic-gate (ep->pcd_filename[0] == PCD_ERASED))) { 2091*0Sstevel@tonic-gate detached = 1; 2092*0Sstevel@tonic-gate } 2093*0Sstevel@tonic-gate if (detached || 2094*0Sstevel@tonic-gate (cksum != pc_checksum_long_fn(ep->pcd_filename, ep->pcd_ext)) || 2095*0Sstevel@tonic-gate !pc_valid_long_fn(lfn)) { 2096*0Sstevel@tonic-gate /* 2097*0Sstevel@tonic-gate * process current entry again. This may end up another lfn 2098*0Sstevel@tonic-gate * or a short name. 2099*0Sstevel@tonic-gate */ 2100*0Sstevel@tonic-gate *epp = ep; 2101*0Sstevel@tonic-gate if (namep == NULL) 2102*0Sstevel@tonic-gate kmem_free(lfn_base, PCMAXNAMLEN+1); 2103*0Sstevel@tonic-gate return (EINVAL); 2104*0Sstevel@tonic-gate } 2105*0Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) { 2106*0Sstevel@tonic-gate /* 2107*0Sstevel@tonic-gate * Don't display label because it may contain 2108*0Sstevel@tonic-gate * funny characters. 2109*0Sstevel@tonic-gate */ 2110*0Sstevel@tonic-gate *offset += sizeof (struct pcdir); 2111*0Sstevel@tonic-gate ep++; 2112*0Sstevel@tonic-gate *epp = ep; 2113*0Sstevel@tonic-gate if (namep == NULL) 2114*0Sstevel@tonic-gate kmem_free(lfn_base, PCMAXNAMLEN+1); 2115*0Sstevel@tonic-gate return (EINVAL); 2116*0Sstevel@tonic-gate } 2117*0Sstevel@tonic-gate if (namep) { 2118*0Sstevel@tonic-gate /* lfn is part of namep, but shifted. shift it back */ 2119*0Sstevel@tonic-gate cs = strlen(lfn); 2120*0Sstevel@tonic-gate for (i = 0; i < cs; i++) 2121*0Sstevel@tonic-gate namep[i] = lfn[i]; 2122*0Sstevel@tonic-gate namep[i] = '\0'; 2123*0Sstevel@tonic-gate } else { 2124*0Sstevel@tonic-gate kmem_free(lfn_base, PCMAXNAMLEN+1); 2125*0Sstevel@tonic-gate } 2126*0Sstevel@tonic-gate *epp = ep; 2127*0Sstevel@tonic-gate return (0); 2128*0Sstevel@tonic-gate } 2129*0Sstevel@tonic-gate /* 2130*0Sstevel@tonic-gate * Read a long filename into the pc_dirent structure and copy it out. 2131*0Sstevel@tonic-gate */ 2132*0Sstevel@tonic-gate int 2133*0Sstevel@tonic-gate pc_read_long_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld, 2134*0Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp) 2135*0Sstevel@tonic-gate { 2136*0Sstevel@tonic-gate struct pcdir *ep; 2137*0Sstevel@tonic-gate struct pcnode *pcp = VTOPC(dvp); 2138*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 2139*0Sstevel@tonic-gate offset_t uiooffset = uiop->uio_loffset; 2140*0Sstevel@tonic-gate int error = 0; 2141*0Sstevel@tonic-gate offset_t oldoffset; 2142*0Sstevel@tonic-gate 2143*0Sstevel@tonic-gate oldoffset = *offset; 2144*0Sstevel@tonic-gate error = pc_extract_long_fn(pcp, ld->d_name, epp, offset, bp); 2145*0Sstevel@tonic-gate if (error) { 2146*0Sstevel@tonic-gate if (error == EINVAL) { 2147*0Sstevel@tonic-gate uiop->uio_loffset += *offset - oldoffset; 2148*0Sstevel@tonic-gate return (0); 2149*0Sstevel@tonic-gate } else 2150*0Sstevel@tonic-gate return (error); 2151*0Sstevel@tonic-gate } 2152*0Sstevel@tonic-gate 2153*0Sstevel@tonic-gate ep = *epp; 2154*0Sstevel@tonic-gate uiop->uio_loffset += *offset - oldoffset; 2155*0Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name)); 2156*0Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 2157*0Sstevel@tonic-gate uiop->uio_loffset = uiooffset; 2158*0Sstevel@tonic-gate return (ENOSPC); 2159*0Sstevel@tonic-gate } 2160*0Sstevel@tonic-gate ld->d_off = uiop->uio_loffset + sizeof (struct pcdir); 2161*0Sstevel@tonic-gate ld->d_ino = pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno), 2162*0Sstevel@tonic-gate pc_blkoff(fsp, *offset), ep->pcd_attr, 2163*0Sstevel@tonic-gate pc_getstartcluster(fsp, ep), fsp->pcfs_entps); 2164*0Sstevel@tonic-gate (void) uiomove((caddr_t)ld, ld->d_reclen, UIO_READ, uiop); 2165*0Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 2166*0Sstevel@tonic-gate *offset += sizeof (struct pcdir); 2167*0Sstevel@tonic-gate ep++; 2168*0Sstevel@tonic-gate *epp = ep; 2169*0Sstevel@tonic-gate return (0); 2170*0Sstevel@tonic-gate } 2171*0Sstevel@tonic-gate 2172*0Sstevel@tonic-gate /* 2173*0Sstevel@tonic-gate * Read a short filename into the pc_dirent structure and copy it out. 2174*0Sstevel@tonic-gate */ 2175*0Sstevel@tonic-gate int 2176*0Sstevel@tonic-gate pc_read_short_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld, 2177*0Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp) 2178*0Sstevel@tonic-gate { 2179*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 2180*0Sstevel@tonic-gate int boff = pc_blkoff(fsp, *offset); 2181*0Sstevel@tonic-gate struct pcdir *ep = *epp; 2182*0Sstevel@tonic-gate offset_t oldoffset = uiop->uio_loffset; 2183*0Sstevel@tonic-gate int error; 2184*0Sstevel@tonic-gate int foldcase; 2185*0Sstevel@tonic-gate 2186*0Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) { 2187*0Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir); 2188*0Sstevel@tonic-gate *offset += sizeof (struct pcdir); 2189*0Sstevel@tonic-gate ep++; 2190*0Sstevel@tonic-gate *epp = ep; 2191*0Sstevel@tonic-gate return (0); 2192*0Sstevel@tonic-gate } 2193*0Sstevel@tonic-gate ld->d_ino = (ino64_t)pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno), 2194*0Sstevel@tonic-gate boff, ep->pcd_attr, pc_getstartcluster(fsp, ep), fsp->pcfs_entps); 2195*0Sstevel@tonic-gate foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE); 2196*0Sstevel@tonic-gate error = pc_fname_ext_to_name(&ld->d_name[0], &ep->pcd_filename[0], 2197*0Sstevel@tonic-gate &ep->pcd_ext[0], foldcase); 2198*0Sstevel@tonic-gate if (error == 0) { 2199*0Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name)); 2200*0Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 2201*0Sstevel@tonic-gate uiop->uio_loffset = oldoffset; 2202*0Sstevel@tonic-gate return (ENOSPC); 2203*0Sstevel@tonic-gate } 2204*0Sstevel@tonic-gate ld->d_off = (off64_t)(uiop->uio_loffset + 2205*0Sstevel@tonic-gate sizeof (struct pcdir)); 2206*0Sstevel@tonic-gate (void) uiomove((caddr_t)ld, 2207*0Sstevel@tonic-gate ld->d_reclen, UIO_READ, uiop); 2208*0Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 2209*0Sstevel@tonic-gate } else { 2210*0Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir); 2211*0Sstevel@tonic-gate } 2212*0Sstevel@tonic-gate *offset += sizeof (struct pcdir); 2213*0Sstevel@tonic-gate ep++; 2214*0Sstevel@tonic-gate *epp = ep; 2215*0Sstevel@tonic-gate return (0); 2216*0Sstevel@tonic-gate } 2217*0Sstevel@tonic-gate 2218*0Sstevel@tonic-gate static int 2219*0Sstevel@tonic-gate pcfs_fid(struct vnode *vp, struct fid *fidp) 2220*0Sstevel@tonic-gate { 2221*0Sstevel@tonic-gate struct pc_fid *pcfid; 2222*0Sstevel@tonic-gate struct pcnode *pcp; 2223*0Sstevel@tonic-gate struct pcfs *fsp; 2224*0Sstevel@tonic-gate int error; 2225*0Sstevel@tonic-gate 2226*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 2227*0Sstevel@tonic-gate if (fsp == NULL) 2228*0Sstevel@tonic-gate return (EIO); 2229*0Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 2230*0Sstevel@tonic-gate if (error) 2231*0Sstevel@tonic-gate return (error); 2232*0Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) { 2233*0Sstevel@tonic-gate pc_unlockfs(fsp); 2234*0Sstevel@tonic-gate return (EIO); 2235*0Sstevel@tonic-gate } 2236*0Sstevel@tonic-gate if (fidp->fid_len < (sizeof (struct pc_fid) - sizeof (ushort_t))) { 2237*0Sstevel@tonic-gate fidp->fid_len = sizeof (struct pc_fid) - sizeof (ushort_t); 2238*0Sstevel@tonic-gate pc_unlockfs(fsp); 2239*0Sstevel@tonic-gate return (ENOSPC); 2240*0Sstevel@tonic-gate } 2241*0Sstevel@tonic-gate 2242*0Sstevel@tonic-gate pcfid = (struct pc_fid *)fidp; 2243*0Sstevel@tonic-gate bzero(pcfid, sizeof (struct pc_fid)); 2244*0Sstevel@tonic-gate pcfid->pcfid_len = sizeof (struct pc_fid) - sizeof (ushort_t); 2245*0Sstevel@tonic-gate if (vp->v_flag & VROOT) { 2246*0Sstevel@tonic-gate pcfid->pcfid_block = 0; 2247*0Sstevel@tonic-gate pcfid->pcfid_offset = 0; 2248*0Sstevel@tonic-gate pcfid->pcfid_ctime = 0; 2249*0Sstevel@tonic-gate } else { 2250*0Sstevel@tonic-gate pcfid->pcfid_block = pcp->pc_eblkno; 2251*0Sstevel@tonic-gate pcfid->pcfid_offset = pcp->pc_eoffset; 2252*0Sstevel@tonic-gate pcfid->pcfid_ctime = pcp->pc_entry.pcd_crtime.pct_time; 2253*0Sstevel@tonic-gate } 2254*0Sstevel@tonic-gate pc_unlockfs(fsp); 2255*0Sstevel@tonic-gate return (0); 2256*0Sstevel@tonic-gate } 2257