17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5264a6e74Sfrankho * Common Development and Distribution License (the "License"). 6264a6e74Sfrankho * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 213b862e9aSRoger A. Faulkner 227c478bd9Sstevel@tonic-gate /* 233b862e9aSRoger A. Faulkner * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 2772102e74SBryan Cantrill /* 2872102e74SBryan Cantrill * Copyright (c) 2013, Joyent, Inc. All rights reserved. 29*06e6833aSJosef 'Jeff' Sipek * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 3072102e74SBryan Cantrill */ 3172102e74SBryan Cantrill 327c478bd9Sstevel@tonic-gate #include <sys/param.h> 337c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 347c478bd9Sstevel@tonic-gate #include <sys/systm.h> 357c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 367c478bd9Sstevel@tonic-gate #include <sys/user.h> 377c478bd9Sstevel@tonic-gate #include <sys/buf.h> 387c478bd9Sstevel@tonic-gate #include <sys/stat.h> 397c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 40aa59c4cbSrsb #include <sys/vfs_opreg.h> 417c478bd9Sstevel@tonic-gate #include <sys/dirent.h> 427c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 437c478bd9Sstevel@tonic-gate #include <sys/proc.h> 447c478bd9Sstevel@tonic-gate #include <sys/file.h> 457c478bd9Sstevel@tonic-gate #include <sys/fcntl.h> 467c478bd9Sstevel@tonic-gate #include <sys/uio.h> 477c478bd9Sstevel@tonic-gate #include <sys/fs/pc_label.h> 487c478bd9Sstevel@tonic-gate #include <sys/fs/pc_fs.h> 497c478bd9Sstevel@tonic-gate #include <sys/fs/pc_dir.h> 507c478bd9Sstevel@tonic-gate #include <sys/fs/pc_node.h> 517c478bd9Sstevel@tonic-gate #include <sys/mman.h> 527c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 537c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h> 547c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 557c478bd9Sstevel@tonic-gate #include <sys/debug.h> 567c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 577c478bd9Sstevel@tonic-gate #include <sys/unistd.h> 587c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 597c478bd9Sstevel@tonic-gate #include <sys/conf.h> 607c478bd9Sstevel@tonic-gate #include <sys/flock.h> 617c478bd9Sstevel@tonic-gate #include <sys/policy.h> 62264a6e74Sfrankho #include <sys/sdt.h> 634a37d755Sksn #include <sys/sunddi.h> 645f079001SOwen Roberts #include <sys/types.h> 655f079001SOwen Roberts #include <sys/errno.h> 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate #include <vm/seg.h> 687c478bd9Sstevel@tonic-gate #include <vm/page.h> 697c478bd9Sstevel@tonic-gate #include <vm/pvn.h> 707c478bd9Sstevel@tonic-gate #include <vm/seg_map.h> 717c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h> 727c478bd9Sstevel@tonic-gate #include <vm/hat.h> 737c478bd9Sstevel@tonic-gate #include <vm/as.h> 747c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h> 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h> 777c478bd9Sstevel@tonic-gate 78da6c28aaSamw static int pcfs_open(struct vnode **, int, struct cred *, caller_context_t *ct); 79da6c28aaSamw static int pcfs_close(struct vnode *, int, int, offset_t, struct cred *, 80da6c28aaSamw caller_context_t *ct); 817c478bd9Sstevel@tonic-gate static int pcfs_read(struct vnode *, struct uio *, int, struct cred *, 82da6c28aaSamw caller_context_t *); 837c478bd9Sstevel@tonic-gate static int pcfs_write(struct vnode *, struct uio *, int, struct cred *, 84da6c28aaSamw caller_context_t *); 85da6c28aaSamw static int pcfs_getattr(struct vnode *, struct vattr *, int, struct cred *, 86da6c28aaSamw caller_context_t *ct); 877c478bd9Sstevel@tonic-gate static int pcfs_setattr(struct vnode *, struct vattr *, int, struct cred *, 887c478bd9Sstevel@tonic-gate caller_context_t *); 89da6c28aaSamw static int pcfs_access(struct vnode *, int, int, struct cred *, 90da6c28aaSamw caller_context_t *ct); 917c478bd9Sstevel@tonic-gate static int pcfs_lookup(struct vnode *, char *, struct vnode **, 92da6c28aaSamw struct pathname *, int, struct vnode *, struct cred *, 93da6c28aaSamw caller_context_t *, int *, pathname_t *); 947c478bd9Sstevel@tonic-gate static int pcfs_create(struct vnode *, char *, struct vattr *, 95da6c28aaSamw enum vcexcl, int mode, struct vnode **, struct cred *, int, 96da6c28aaSamw caller_context_t *, vsecattr_t *); 97da6c28aaSamw static int pcfs_remove(struct vnode *, char *, struct cred *, 98da6c28aaSamw caller_context_t *, int); 997c478bd9Sstevel@tonic-gate static int pcfs_rename(struct vnode *, char *, struct vnode *, char *, 100da6c28aaSamw struct cred *, caller_context_t *, int); 1017c478bd9Sstevel@tonic-gate static int pcfs_mkdir(struct vnode *, char *, struct vattr *, struct vnode **, 102da6c28aaSamw struct cred *, caller_context_t *, int, vsecattr_t *); 103da6c28aaSamw static int pcfs_rmdir(struct vnode *, char *, struct vnode *, struct cred *, 104da6c28aaSamw caller_context_t *, int); 105da6c28aaSamw static int pcfs_readdir(struct vnode *, struct uio *, struct cred *, int *, 106da6c28aaSamw caller_context_t *, int); 107da6c28aaSamw static int pcfs_fsync(struct vnode *, int, struct cred *, caller_context_t *); 108da6c28aaSamw static void pcfs_inactive(struct vnode *, struct cred *, caller_context_t *); 109da6c28aaSamw static int pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *); 1107c478bd9Sstevel@tonic-gate static int pcfs_space(struct vnode *, int, struct flock64 *, int, 1117c478bd9Sstevel@tonic-gate offset_t, cred_t *, caller_context_t *); 1127c478bd9Sstevel@tonic-gate static int pcfs_getpage(struct vnode *, offset_t, size_t, uint_t *, page_t *[], 113da6c28aaSamw size_t, struct seg *, caddr_t, enum seg_rw, struct cred *, 114da6c28aaSamw caller_context_t *); 1157c478bd9Sstevel@tonic-gate static int pcfs_getapage(struct vnode *, u_offset_t, size_t, uint_t *, 1167c478bd9Sstevel@tonic-gate page_t *[], size_t, struct seg *, caddr_t, enum seg_rw, struct cred *); 117da6c28aaSamw static int pcfs_putpage(struct vnode *, offset_t, size_t, int, struct cred *, 118da6c28aaSamw caller_context_t *); 1197c478bd9Sstevel@tonic-gate static int pcfs_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t, 120da6c28aaSamw uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *); 1217c478bd9Sstevel@tonic-gate static int pcfs_addmap(struct vnode *, offset_t, struct as *, caddr_t, 122da6c28aaSamw size_t, uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *); 1237c478bd9Sstevel@tonic-gate static int pcfs_delmap(struct vnode *, offset_t, struct as *, caddr_t, 124da6c28aaSamw size_t, uint_t, uint_t, uint_t, struct cred *, caller_context_t *); 125da6c28aaSamw static int pcfs_seek(struct vnode *, offset_t, offset_t *, 126da6c28aaSamw caller_context_t *); 127da6c28aaSamw static int pcfs_pathconf(struct vnode *, int, ulong_t *, struct cred *, 128da6c28aaSamw caller_context_t *); 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate int pcfs_putapage(struct vnode *, page_t *, u_offset_t *, size_t *, int, 1317c478bd9Sstevel@tonic-gate struct cred *); 1327c478bd9Sstevel@tonic-gate static int rwpcp(struct pcnode *, struct uio *, enum uio_rw, int); 1335f079001SOwen Roberts static int get_long_fn_chunk(struct pcdir_lfn *ep, char *buf); 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate extern krwlock_t pcnodes_lock; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate #define lround(r) (((r)+sizeof (long long)-1)&(~(sizeof (long long)-1))) 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate /* 1407c478bd9Sstevel@tonic-gate * vnode op vectors for files and directories. 1417c478bd9Sstevel@tonic-gate */ 1427c478bd9Sstevel@tonic-gate struct vnodeops *pcfs_fvnodeops; 1437c478bd9Sstevel@tonic-gate struct vnodeops *pcfs_dvnodeops; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate const fs_operation_def_t pcfs_fvnodeops_template[] = { 146aa59c4cbSrsb VOPNAME_OPEN, { .vop_open = pcfs_open }, 147aa59c4cbSrsb VOPNAME_CLOSE, { .vop_close = pcfs_close }, 148aa59c4cbSrsb VOPNAME_READ, { .vop_read = pcfs_read }, 149aa59c4cbSrsb VOPNAME_WRITE, { .vop_write = pcfs_write }, 150aa59c4cbSrsb VOPNAME_GETATTR, { .vop_getattr = pcfs_getattr }, 151aa59c4cbSrsb VOPNAME_SETATTR, { .vop_setattr = pcfs_setattr }, 152aa59c4cbSrsb VOPNAME_ACCESS, { .vop_access = pcfs_access }, 153aa59c4cbSrsb VOPNAME_FSYNC, { .vop_fsync = pcfs_fsync }, 154aa59c4cbSrsb VOPNAME_INACTIVE, { .vop_inactive = pcfs_inactive }, 155aa59c4cbSrsb VOPNAME_FID, { .vop_fid = pcfs_fid }, 156aa59c4cbSrsb VOPNAME_SEEK, { .vop_seek = pcfs_seek }, 157aa59c4cbSrsb VOPNAME_SPACE, { .vop_space = pcfs_space }, 158aa59c4cbSrsb VOPNAME_GETPAGE, { .vop_getpage = pcfs_getpage }, 159aa59c4cbSrsb VOPNAME_PUTPAGE, { .vop_putpage = pcfs_putpage }, 160aa59c4cbSrsb VOPNAME_MAP, { .vop_map = pcfs_map }, 161aa59c4cbSrsb VOPNAME_ADDMAP, { .vop_addmap = pcfs_addmap }, 162aa59c4cbSrsb VOPNAME_DELMAP, { .vop_delmap = pcfs_delmap }, 163aa59c4cbSrsb VOPNAME_PATHCONF, { .vop_pathconf = pcfs_pathconf }, 164aa59c4cbSrsb VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, 1657c478bd9Sstevel@tonic-gate NULL, NULL 1667c478bd9Sstevel@tonic-gate }; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate const fs_operation_def_t pcfs_dvnodeops_template[] = { 169aa59c4cbSrsb VOPNAME_OPEN, { .vop_open = pcfs_open }, 170aa59c4cbSrsb VOPNAME_CLOSE, { .vop_close = pcfs_close }, 171aa59c4cbSrsb VOPNAME_GETATTR, { .vop_getattr = pcfs_getattr }, 172aa59c4cbSrsb VOPNAME_SETATTR, { .vop_setattr = pcfs_setattr }, 173aa59c4cbSrsb VOPNAME_ACCESS, { .vop_access = pcfs_access }, 174aa59c4cbSrsb VOPNAME_LOOKUP, { .vop_lookup = pcfs_lookup }, 175aa59c4cbSrsb VOPNAME_CREATE, { .vop_create = pcfs_create }, 176aa59c4cbSrsb VOPNAME_REMOVE, { .vop_remove = pcfs_remove }, 177aa59c4cbSrsb VOPNAME_RENAME, { .vop_rename = pcfs_rename }, 178aa59c4cbSrsb VOPNAME_MKDIR, { .vop_mkdir = pcfs_mkdir }, 179aa59c4cbSrsb VOPNAME_RMDIR, { .vop_rmdir = pcfs_rmdir }, 180aa59c4cbSrsb VOPNAME_READDIR, { .vop_readdir = pcfs_readdir }, 181aa59c4cbSrsb VOPNAME_FSYNC, { .vop_fsync = pcfs_fsync }, 182aa59c4cbSrsb VOPNAME_INACTIVE, { .vop_inactive = pcfs_inactive }, 183aa59c4cbSrsb VOPNAME_FID, { .vop_fid = pcfs_fid }, 184aa59c4cbSrsb VOPNAME_SEEK, { .vop_seek = pcfs_seek }, 185aa59c4cbSrsb VOPNAME_PATHCONF, { .vop_pathconf = pcfs_pathconf }, 186aa59c4cbSrsb VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, 1877c478bd9Sstevel@tonic-gate NULL, NULL 1887c478bd9Sstevel@tonic-gate }; 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1927c478bd9Sstevel@tonic-gate static int 1937c478bd9Sstevel@tonic-gate pcfs_open( 1947c478bd9Sstevel@tonic-gate struct vnode **vpp, 1957c478bd9Sstevel@tonic-gate int flag, 196da6c28aaSamw struct cred *cr, 197da6c28aaSamw caller_context_t *ct) 1987c478bd9Sstevel@tonic-gate { 1997c478bd9Sstevel@tonic-gate return (0); 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate /* 2037c478bd9Sstevel@tonic-gate * files are sync'ed on close to keep floppy up to date 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2077c478bd9Sstevel@tonic-gate static int 2087c478bd9Sstevel@tonic-gate pcfs_close( 2097c478bd9Sstevel@tonic-gate struct vnode *vp, 2107c478bd9Sstevel@tonic-gate int flag, 2117c478bd9Sstevel@tonic-gate int count, 2127c478bd9Sstevel@tonic-gate offset_t offset, 213da6c28aaSamw struct cred *cr, 214da6c28aaSamw caller_context_t *ct) 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate return (0); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2207c478bd9Sstevel@tonic-gate static int 2217c478bd9Sstevel@tonic-gate pcfs_read( 2227c478bd9Sstevel@tonic-gate struct vnode *vp, 2237c478bd9Sstevel@tonic-gate struct uio *uiop, 2247c478bd9Sstevel@tonic-gate int ioflag, 2257c478bd9Sstevel@tonic-gate struct cred *cr, 2267c478bd9Sstevel@tonic-gate struct caller_context *ct) 2277c478bd9Sstevel@tonic-gate { 2287c478bd9Sstevel@tonic-gate struct pcfs *fsp; 2297c478bd9Sstevel@tonic-gate struct pcnode *pcp; 2307c478bd9Sstevel@tonic-gate int error; 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 2337c478bd9Sstevel@tonic-gate if (error = pc_verify(fsp)) 2347c478bd9Sstevel@tonic-gate return (error); 2357c478bd9Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 2367c478bd9Sstevel@tonic-gate if (error) 2377c478bd9Sstevel@tonic-gate return (error); 2389bd42341Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 2397c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 2407c478bd9Sstevel@tonic-gate return (EIO); 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate error = rwpcp(pcp, uiop, UIO_READ, ioflag); 2437c478bd9Sstevel@tonic-gate if ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0) { 244f127cb91Sfrankho pc_mark_acc(fsp, pcp); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 2477c478bd9Sstevel@tonic-gate if (error) { 2487c478bd9Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_read: io error = %d\n", error); 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate return (error); 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2547c478bd9Sstevel@tonic-gate static int 2557c478bd9Sstevel@tonic-gate pcfs_write( 2567c478bd9Sstevel@tonic-gate struct vnode *vp, 2577c478bd9Sstevel@tonic-gate struct uio *uiop, 2587c478bd9Sstevel@tonic-gate int ioflag, 2597c478bd9Sstevel@tonic-gate struct cred *cr, 2607c478bd9Sstevel@tonic-gate struct caller_context *ct) 2617c478bd9Sstevel@tonic-gate { 2627c478bd9Sstevel@tonic-gate struct pcfs *fsp; 2637c478bd9Sstevel@tonic-gate struct pcnode *pcp; 2647c478bd9Sstevel@tonic-gate int error; 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 2677c478bd9Sstevel@tonic-gate if (error = pc_verify(fsp)) 2687c478bd9Sstevel@tonic-gate return (error); 2697c478bd9Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 2707c478bd9Sstevel@tonic-gate if (error) 2717c478bd9Sstevel@tonic-gate return (error); 2729bd42341Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 2737c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 2747c478bd9Sstevel@tonic-gate return (EIO); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate if (ioflag & FAPPEND) { 2777c478bd9Sstevel@tonic-gate /* 2787c478bd9Sstevel@tonic-gate * in append mode start at end of file. 2797c478bd9Sstevel@tonic-gate */ 2807c478bd9Sstevel@tonic-gate uiop->uio_loffset = pcp->pc_size; 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate error = rwpcp(pcp, uiop, UIO_WRITE, ioflag); 2837c478bd9Sstevel@tonic-gate pcp->pc_flags |= PC_MOD; 284f127cb91Sfrankho pc_mark_mod(fsp, pcp); 2857c478bd9Sstevel@tonic-gate if (ioflag & (FSYNC|FDSYNC)) 2867c478bd9Sstevel@tonic-gate (void) pc_nodeupdate(pcp); 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 2897c478bd9Sstevel@tonic-gate if (error) { 2907c478bd9Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_write: io error = %d\n", error); 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate return (error); 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate /* 2967c478bd9Sstevel@tonic-gate * read or write a vnode 2977c478bd9Sstevel@tonic-gate */ 2987c478bd9Sstevel@tonic-gate static int 2997c478bd9Sstevel@tonic-gate rwpcp( 3007c478bd9Sstevel@tonic-gate struct pcnode *pcp, 3017c478bd9Sstevel@tonic-gate struct uio *uio, 3027c478bd9Sstevel@tonic-gate enum uio_rw rw, 3037c478bd9Sstevel@tonic-gate int ioflag) 3047c478bd9Sstevel@tonic-gate { 3057c478bd9Sstevel@tonic-gate struct vnode *vp = PCTOV(pcp); 3067c478bd9Sstevel@tonic-gate struct pcfs *fsp; 3077c478bd9Sstevel@tonic-gate daddr_t bn; /* phys block number */ 3087c478bd9Sstevel@tonic-gate int n; 3097c478bd9Sstevel@tonic-gate offset_t off; 3107c478bd9Sstevel@tonic-gate caddr_t base; 3117c478bd9Sstevel@tonic-gate int mapon, pagecreate; 3127c478bd9Sstevel@tonic-gate int newpage; 3137c478bd9Sstevel@tonic-gate int error = 0; 3147c478bd9Sstevel@tonic-gate rlim64_t limit = uio->uio_llimit; 3157c478bd9Sstevel@tonic-gate int oresid = uio->uio_resid; 3167c478bd9Sstevel@tonic-gate 317264a6e74Sfrankho /* 318264a6e74Sfrankho * If the filesystem was umounted by force, return immediately. 319264a6e74Sfrankho */ 320264a6e74Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 321264a6e74Sfrankho return (EIO); 322264a6e74Sfrankho 3237c478bd9Sstevel@tonic-gate PC_DPRINTF4(5, "rwpcp pcp=%p off=%lld resid=%ld size=%u\n", (void *)pcp, 3247c478bd9Sstevel@tonic-gate uio->uio_loffset, uio->uio_resid, pcp->pc_size); 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate ASSERT(rw == UIO_READ || rw == UIO_WRITE); 3277c478bd9Sstevel@tonic-gate ASSERT(vp->v_type == VREG); 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate if (uio->uio_loffset >= UINT32_MAX && rw == UIO_READ) { 3307c478bd9Sstevel@tonic-gate return (0); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate if (uio->uio_loffset < 0) 3347c478bd9Sstevel@tonic-gate return (EINVAL); 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T) 3377c478bd9Sstevel@tonic-gate limit = MAXOFFSET_T; 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate if (uio->uio_loffset >= limit && rw == UIO_WRITE) { 3407c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 3437c478bd9Sstevel@tonic-gate (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], p->p_rctls, 3447c478bd9Sstevel@tonic-gate p, RCA_UNSAFE_SIGINFO); 3457c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 3467c478bd9Sstevel@tonic-gate return (EFBIG); 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate /* the following condition will occur only for write */ 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate if (uio->uio_loffset >= UINT32_MAX) 3527c478bd9Sstevel@tonic-gate return (EFBIG); 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate if (uio->uio_resid == 0) 3557c478bd9Sstevel@tonic-gate return (0); 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate if (limit > UINT32_MAX) 3587c478bd9Sstevel@tonic-gate limit = UINT32_MAX; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 3617c478bd9Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_IRRECOV) 3627c478bd9Sstevel@tonic-gate return (EIO); 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate do { 3657c478bd9Sstevel@tonic-gate /* 3667c478bd9Sstevel@tonic-gate * Assignments to "n" in this block may appear 3677c478bd9Sstevel@tonic-gate * to overflow in some cases. However, after careful 3687c478bd9Sstevel@tonic-gate * analysis it was determined that all assignments to 3697c478bd9Sstevel@tonic-gate * "n" serve only to make "n" smaller. Since "n" 3707c478bd9Sstevel@tonic-gate * starts out as no larger than MAXBSIZE, "int" is 3717c478bd9Sstevel@tonic-gate * safe. 3727c478bd9Sstevel@tonic-gate */ 3737c478bd9Sstevel@tonic-gate off = uio->uio_loffset & MAXBMASK; 3747c478bd9Sstevel@tonic-gate mapon = (int)(uio->uio_loffset & MAXBOFFSET); 3757c478bd9Sstevel@tonic-gate n = MIN(MAXBSIZE - mapon, uio->uio_resid); 3767c478bd9Sstevel@tonic-gate if (rw == UIO_READ) { 3777c478bd9Sstevel@tonic-gate offset_t diff; 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate diff = pcp->pc_size - uio->uio_loffset; 3807c478bd9Sstevel@tonic-gate if (diff <= 0) 3817c478bd9Sstevel@tonic-gate return (0); 3827c478bd9Sstevel@tonic-gate if (diff < n) 3837c478bd9Sstevel@tonic-gate n = (int)diff; 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * Compare limit with the actual offset + n, not the 3877c478bd9Sstevel@tonic-gate * rounded down offset "off" or we will overflow 3887c478bd9Sstevel@tonic-gate * the maximum file size after all. 3897c478bd9Sstevel@tonic-gate */ 3907c478bd9Sstevel@tonic-gate if (rw == UIO_WRITE && uio->uio_loffset + n >= limit) { 3917c478bd9Sstevel@tonic-gate if (uio->uio_loffset >= limit) { 3927c478bd9Sstevel@tonic-gate error = EFBIG; 3937c478bd9Sstevel@tonic-gate break; 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate n = (int)(limit - uio->uio_loffset); 3967c478bd9Sstevel@tonic-gate } 3976f5f1c63SDonghai Qiao 3986f5f1c63SDonghai Qiao /* 3996f5f1c63SDonghai Qiao * Touch the page and fault it in if it is not in 4006f5f1c63SDonghai Qiao * core before segmap_getmapflt can lock it. This 4016f5f1c63SDonghai Qiao * is to avoid the deadlock if the buffer is mapped 4026f5f1c63SDonghai Qiao * to the same file through mmap which we want to 4036f5f1c63SDonghai Qiao * write to. 4046f5f1c63SDonghai Qiao */ 4056f5f1c63SDonghai Qiao uio_prefaultpages((long)n, uio); 4066f5f1c63SDonghai Qiao 4077c478bd9Sstevel@tonic-gate base = segmap_getmap(segkmap, vp, (u_offset_t)off); 4087c478bd9Sstevel@tonic-gate pagecreate = 0; 4097c478bd9Sstevel@tonic-gate newpage = 0; 4107c478bd9Sstevel@tonic-gate if (rw == UIO_WRITE) { 4117c478bd9Sstevel@tonic-gate /* 4127c478bd9Sstevel@tonic-gate * If PAGESIZE < MAXBSIZE, perhaps we ought to deal 4137c478bd9Sstevel@tonic-gate * with one page at a time, instead of one MAXBSIZE 4147c478bd9Sstevel@tonic-gate * at a time, so we can fully explore pagecreate 4157c478bd9Sstevel@tonic-gate * optimization?? 4167c478bd9Sstevel@tonic-gate */ 4177c478bd9Sstevel@tonic-gate if (uio->uio_loffset + n > pcp->pc_size) { 4187c478bd9Sstevel@tonic-gate uint_t ncl, lcn; 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate ncl = (uint_t)howmany((offset_t)pcp->pc_size, 4217c478bd9Sstevel@tonic-gate fsp->pcfs_clsize); 4227c478bd9Sstevel@tonic-gate if (uio->uio_loffset > pcp->pc_size && 4237c478bd9Sstevel@tonic-gate ncl < (uint_t)howmany(uio->uio_loffset, 4247c478bd9Sstevel@tonic-gate fsp->pcfs_clsize)) { 4257c478bd9Sstevel@tonic-gate /* 4267c478bd9Sstevel@tonic-gate * Allocate and zerofill skipped 4277c478bd9Sstevel@tonic-gate * clusters. This may not be worth the 4287c478bd9Sstevel@tonic-gate * effort since a small lseek beyond 4297c478bd9Sstevel@tonic-gate * eof but still within the cluster 4307c478bd9Sstevel@tonic-gate * will not be zeroed out. 4317c478bd9Sstevel@tonic-gate */ 4327c478bd9Sstevel@tonic-gate lcn = pc_lblkno(fsp, uio->uio_loffset); 4337c478bd9Sstevel@tonic-gate error = pc_balloc(pcp, (daddr_t)lcn, 4347c478bd9Sstevel@tonic-gate 1, &bn); 4357c478bd9Sstevel@tonic-gate ncl = lcn + 1; 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate if (!error && 4387c478bd9Sstevel@tonic-gate ncl < (uint_t)howmany(uio->uio_loffset + n, 4397c478bd9Sstevel@tonic-gate fsp->pcfs_clsize)) 4407c478bd9Sstevel@tonic-gate /* 4417c478bd9Sstevel@tonic-gate * allocate clusters w/o zerofill 4427c478bd9Sstevel@tonic-gate */ 4437c478bd9Sstevel@tonic-gate error = pc_balloc(pcp, 4447c478bd9Sstevel@tonic-gate (daddr_t)pc_lblkno(fsp, 4457c478bd9Sstevel@tonic-gate uio->uio_loffset + n - 1), 4467c478bd9Sstevel@tonic-gate 0, &bn); 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate if (error) { 4519bd42341Sfrankho pc_cluster32_t ncl; 4529bd42341Sfrankho int nerror; 4539bd42341Sfrankho 4549bd42341Sfrankho /* 4559bd42341Sfrankho * figure out new file size from 4569bd42341Sfrankho * cluster chain length. If this 4579bd42341Sfrankho * is detected to loop, the chain 4589bd42341Sfrankho * is corrupted and we'd better 4599bd42341Sfrankho * keep our fingers off that file. 4609bd42341Sfrankho */ 4619bd42341Sfrankho nerror = pc_fileclsize(fsp, 4629bd42341Sfrankho pcp->pc_scluster, &ncl); 4639bd42341Sfrankho if (nerror) { 4649bd42341Sfrankho PC_DPRINTF1(2, 4659bd42341Sfrankho "cluster chain " 4669bd42341Sfrankho "corruption, " 4679bd42341Sfrankho "scluster=%d\n", 4687c478bd9Sstevel@tonic-gate pcp->pc_scluster); 4699bd42341Sfrankho pcp->pc_size = 0; 4709bd42341Sfrankho pcp->pc_flags |= PC_INVAL; 4719bd42341Sfrankho error = nerror; 4729bd42341Sfrankho (void) segmap_release(segkmap, 4739bd42341Sfrankho base, 0); 4749bd42341Sfrankho break; 4759bd42341Sfrankho } 4769bd42341Sfrankho pcp->pc_size = fsp->pcfs_clsize * ncl; 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate if (error == ENOSPC && 4797c478bd9Sstevel@tonic-gate (pcp->pc_size - uio->uio_loffset) 4807c478bd9Sstevel@tonic-gate > 0) { 4817c478bd9Sstevel@tonic-gate PC_DPRINTF3(2, "rwpcp ENOSPC " 4827c478bd9Sstevel@tonic-gate "off=%lld n=%d size=%d\n", 4837c478bd9Sstevel@tonic-gate uio->uio_loffset, 4847c478bd9Sstevel@tonic-gate n, pcp->pc_size); 4857c478bd9Sstevel@tonic-gate n = (int)(pcp->pc_size - 4867c478bd9Sstevel@tonic-gate uio->uio_loffset); 4877c478bd9Sstevel@tonic-gate } else { 4887c478bd9Sstevel@tonic-gate PC_DPRINTF1(1, 4897c478bd9Sstevel@tonic-gate "rwpcp error1=%d\n", error); 4907c478bd9Sstevel@tonic-gate (void) segmap_release(segkmap, 4917c478bd9Sstevel@tonic-gate base, 0); 4927c478bd9Sstevel@tonic-gate break; 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate } else { 4957c478bd9Sstevel@tonic-gate pcp->pc_size = 4967c478bd9Sstevel@tonic-gate (uint_t)(uio->uio_loffset + n); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate if (mapon == 0) { 4997c478bd9Sstevel@tonic-gate newpage = segmap_pagecreate(segkmap, 5007c478bd9Sstevel@tonic-gate base, (size_t)n, 0); 5017c478bd9Sstevel@tonic-gate pagecreate = 1; 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate } else if (n == MAXBSIZE) { 5047c478bd9Sstevel@tonic-gate newpage = segmap_pagecreate(segkmap, base, 5057c478bd9Sstevel@tonic-gate (size_t)n, 0); 5067c478bd9Sstevel@tonic-gate pagecreate = 1; 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate error = uiomove(base + mapon, (size_t)n, rw, uio); 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate if (pagecreate && uio->uio_loffset < 5127c478bd9Sstevel@tonic-gate roundup(off + mapon + n, PAGESIZE)) { 5137c478bd9Sstevel@tonic-gate offset_t nzero, nmoved; 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate nmoved = uio->uio_loffset - (off + mapon); 5167c478bd9Sstevel@tonic-gate nzero = roundup(mapon + n, PAGESIZE) - nmoved; 5177c478bd9Sstevel@tonic-gate (void) kzero(base + mapon + nmoved, (size_t)nzero); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate /* 5217c478bd9Sstevel@tonic-gate * Unlock the pages which have been allocated by 5227c478bd9Sstevel@tonic-gate * page_create_va() in segmap_pagecreate(). 5237c478bd9Sstevel@tonic-gate */ 524f127cb91Sfrankho if (newpage) { 5257c478bd9Sstevel@tonic-gate segmap_pageunlock(segkmap, base, (size_t)n, 5267c478bd9Sstevel@tonic-gate rw == UIO_WRITE ? S_WRITE : S_READ); 527f127cb91Sfrankho } 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate if (error) { 5307c478bd9Sstevel@tonic-gate PC_DPRINTF1(1, "rwpcp error2=%d\n", error); 5317c478bd9Sstevel@tonic-gate /* 5327c478bd9Sstevel@tonic-gate * If we failed on a write, we may have already 5337c478bd9Sstevel@tonic-gate * allocated file blocks as well as pages. It's hard 5347c478bd9Sstevel@tonic-gate * to undo the block allocation, but we must be sure 5357c478bd9Sstevel@tonic-gate * to invalidate any pages that may have been 5367c478bd9Sstevel@tonic-gate * allocated. 5377c478bd9Sstevel@tonic-gate */ 5387c478bd9Sstevel@tonic-gate if (rw == UIO_WRITE) 5397c478bd9Sstevel@tonic-gate (void) segmap_release(segkmap, base, SM_INVAL); 5407c478bd9Sstevel@tonic-gate else 5417c478bd9Sstevel@tonic-gate (void) segmap_release(segkmap, base, 0); 5427c478bd9Sstevel@tonic-gate } else { 5437c478bd9Sstevel@tonic-gate uint_t flags = 0; 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate if (rw == UIO_READ) { 5467c478bd9Sstevel@tonic-gate if (n + mapon == MAXBSIZE || 5477c478bd9Sstevel@tonic-gate uio->uio_loffset == pcp->pc_size) 5487c478bd9Sstevel@tonic-gate flags = SM_DONTNEED; 5497c478bd9Sstevel@tonic-gate } else if (ioflag & (FSYNC|FDSYNC)) { 5507c478bd9Sstevel@tonic-gate flags = SM_WRITE; 5517c478bd9Sstevel@tonic-gate } else if (n + mapon == MAXBSIZE) { 5527c478bd9Sstevel@tonic-gate flags = SM_WRITE|SM_ASYNC|SM_DONTNEED; 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate error = segmap_release(segkmap, base, flags); 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate } while (error == 0 && uio->uio_resid > 0 && n != 0); 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate if (oresid != uio->uio_resid) 5607c478bd9Sstevel@tonic-gate error = 0; 5617c478bd9Sstevel@tonic-gate return (error); 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5657c478bd9Sstevel@tonic-gate static int 5667c478bd9Sstevel@tonic-gate pcfs_getattr( 5677c478bd9Sstevel@tonic-gate struct vnode *vp, 5687c478bd9Sstevel@tonic-gate struct vattr *vap, 5697c478bd9Sstevel@tonic-gate int flags, 570da6c28aaSamw struct cred *cr, 571da6c28aaSamw caller_context_t *ct) 5727c478bd9Sstevel@tonic-gate { 5737c478bd9Sstevel@tonic-gate struct pcnode *pcp; 5747c478bd9Sstevel@tonic-gate struct pcfs *fsp; 5757c478bd9Sstevel@tonic-gate int error; 5767c478bd9Sstevel@tonic-gate char attr; 5777c478bd9Sstevel@tonic-gate struct pctime atime; 578264a6e74Sfrankho int64_t unixtime; 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate PC_DPRINTF1(8, "pcfs_getattr: vp=%p\n", (void *)vp); 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 5837c478bd9Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 5847c478bd9Sstevel@tonic-gate if (error) 5857c478bd9Sstevel@tonic-gate return (error); 5869bd42341Sfrankho 5879bd42341Sfrankho /* 5889bd42341Sfrankho * Note that we don't check for "invalid node" (PC_INVAL) here 5899bd42341Sfrankho * only in order to make stat() succeed. We allow no I/O on such 590da6c28aaSamw * a node, but do allow to check for its existence. 5919bd42341Sfrankho */ 5927c478bd9Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) { 5937c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 5947c478bd9Sstevel@tonic-gate return (EIO); 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate /* 5977c478bd9Sstevel@tonic-gate * Copy from pcnode. 5987c478bd9Sstevel@tonic-gate */ 5997c478bd9Sstevel@tonic-gate vap->va_type = vp->v_type; 6007c478bd9Sstevel@tonic-gate attr = pcp->pc_entry.pcd_attr; 6017c478bd9Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, attr)) 6027c478bd9Sstevel@tonic-gate vap->va_mode = 0; 6037c478bd9Sstevel@tonic-gate else if (attr & PCA_LABEL) 6047c478bd9Sstevel@tonic-gate vap->va_mode = 0444; 6057c478bd9Sstevel@tonic-gate else if (attr & PCA_RDONLY) 6067c478bd9Sstevel@tonic-gate vap->va_mode = 0555; 6077c478bd9Sstevel@tonic-gate else if (fsp->pcfs_flags & PCFS_BOOTPART) { 6087c478bd9Sstevel@tonic-gate vap->va_mode = 0755; 6097c478bd9Sstevel@tonic-gate } else { 6107c478bd9Sstevel@tonic-gate vap->va_mode = 0777; 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate if (attr & PCA_DIR) 6147c478bd9Sstevel@tonic-gate vap->va_mode |= S_IFDIR; 6157c478bd9Sstevel@tonic-gate else 6167c478bd9Sstevel@tonic-gate vap->va_mode |= S_IFREG; 6177c478bd9Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 6187c478bd9Sstevel@tonic-gate vap->va_uid = 0; 6197c478bd9Sstevel@tonic-gate vap->va_gid = 0; 6207c478bd9Sstevel@tonic-gate } else { 6217c478bd9Sstevel@tonic-gate vap->va_uid = crgetuid(cr); 6227c478bd9Sstevel@tonic-gate vap->va_gid = crgetgid(cr); 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate vap->va_fsid = vp->v_vfsp->vfs_dev; 6257c478bd9Sstevel@tonic-gate vap->va_nodeid = (ino64_t)pc_makenodeid(pcp->pc_eblkno, 6267c478bd9Sstevel@tonic-gate pcp->pc_eoffset, pcp->pc_entry.pcd_attr, 627f127cb91Sfrankho pc_getstartcluster(fsp, &pcp->pc_entry), pc_direntpersec(fsp)); 6287c478bd9Sstevel@tonic-gate vap->va_nlink = 1; 6297c478bd9Sstevel@tonic-gate vap->va_size = (u_offset_t)pcp->pc_size; 630f127cb91Sfrankho vap->va_rdev = 0; 631f127cb91Sfrankho vap->va_nblocks = 632f127cb91Sfrankho (fsblkcnt64_t)howmany((offset_t)pcp->pc_size, DEV_BSIZE); 633f127cb91Sfrankho vap->va_blksize = fsp->pcfs_clsize; 634f127cb91Sfrankho 635f127cb91Sfrankho /* 636f127cb91Sfrankho * FAT root directories have no timestamps. In order not to return 637f127cb91Sfrankho * "time zero" (1/1/1970), we record the time of the mount and give 638f127cb91Sfrankho * that. This breaks less expectations. 639f127cb91Sfrankho */ 640f127cb91Sfrankho if (vp->v_flag & VROOT) { 641f127cb91Sfrankho vap->va_mtime = fsp->pcfs_mounttime; 642f127cb91Sfrankho vap->va_atime = fsp->pcfs_mounttime; 643f127cb91Sfrankho vap->va_ctime = fsp->pcfs_mounttime; 644f127cb91Sfrankho pc_unlockfs(fsp); 645f127cb91Sfrankho return (0); 646f127cb91Sfrankho } 647264a6e74Sfrankho 648264a6e74Sfrankho pc_pcttotv(&pcp->pc_entry.pcd_mtime, &unixtime); 649264a6e74Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) { 650264a6e74Sfrankho if (unixtime > INT32_MAX) 651264a6e74Sfrankho DTRACE_PROBE1(pcfs__mtimeclamped, int64_t, unixtime); 652264a6e74Sfrankho unixtime = MIN(unixtime, INT32_MAX); 653264a6e74Sfrankho } else if (unixtime > INT32_MAX && 654264a6e74Sfrankho get_udatamodel() == DATAMODEL_ILP32) { 655264a6e74Sfrankho pc_unlockfs(fsp); 656264a6e74Sfrankho DTRACE_PROBE1(pcfs__mtimeoverflowed, int64_t, unixtime); 657264a6e74Sfrankho return (EOVERFLOW); 658264a6e74Sfrankho } 659264a6e74Sfrankho 660264a6e74Sfrankho vap->va_mtime.tv_sec = (time_t)unixtime; 661264a6e74Sfrankho vap->va_mtime.tv_nsec = 0; 662264a6e74Sfrankho 663264a6e74Sfrankho /* 664264a6e74Sfrankho * FAT doesn't know about POSIX ctime. 665264a6e74Sfrankho * Best approximation is to always set it to mtime. 666264a6e74Sfrankho */ 6677c478bd9Sstevel@tonic-gate vap->va_ctime = vap->va_mtime; 668264a6e74Sfrankho 669264a6e74Sfrankho /* 670264a6e74Sfrankho * FAT only stores "last access date". If that's the 671264a6e74Sfrankho * same as the date of last modification then the time 672264a6e74Sfrankho * of last access is known. Otherwise, use midnight. 673264a6e74Sfrankho */ 6747c478bd9Sstevel@tonic-gate atime.pct_date = pcp->pc_entry.pcd_ladate; 675264a6e74Sfrankho if (atime.pct_date == pcp->pc_entry.pcd_mtime.pct_date) 676264a6e74Sfrankho atime.pct_time = pcp->pc_entry.pcd_mtime.pct_time; 677264a6e74Sfrankho else 678264a6e74Sfrankho atime.pct_time = 0; 679264a6e74Sfrankho pc_pcttotv(&atime, &unixtime); 680264a6e74Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) { 681264a6e74Sfrankho if (unixtime > INT32_MAX) 682264a6e74Sfrankho DTRACE_PROBE1(pcfs__atimeclamped, int64_t, unixtime); 683264a6e74Sfrankho unixtime = MIN(unixtime, INT32_MAX); 684264a6e74Sfrankho } else if (unixtime > INT32_MAX && 685264a6e74Sfrankho get_udatamodel() == DATAMODEL_ILP32) { 686264a6e74Sfrankho pc_unlockfs(fsp); 687264a6e74Sfrankho DTRACE_PROBE1(pcfs__atimeoverflowed, int64_t, unixtime); 688264a6e74Sfrankho return (EOVERFLOW); 689264a6e74Sfrankho } 690264a6e74Sfrankho 691264a6e74Sfrankho vap->va_atime.tv_sec = (time_t)unixtime; 692264a6e74Sfrankho vap->va_atime.tv_nsec = 0; 693264a6e74Sfrankho 6947c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 6957c478bd9Sstevel@tonic-gate return (0); 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7007c478bd9Sstevel@tonic-gate static int 7017c478bd9Sstevel@tonic-gate pcfs_setattr( 7027c478bd9Sstevel@tonic-gate struct vnode *vp, 7037c478bd9Sstevel@tonic-gate struct vattr *vap, 7047c478bd9Sstevel@tonic-gate int flags, 7057c478bd9Sstevel@tonic-gate struct cred *cr, 7067c478bd9Sstevel@tonic-gate caller_context_t *ct) 7077c478bd9Sstevel@tonic-gate { 7087c478bd9Sstevel@tonic-gate struct pcnode *pcp; 7097c478bd9Sstevel@tonic-gate mode_t mask = vap->va_mask; 7107c478bd9Sstevel@tonic-gate int error; 7117c478bd9Sstevel@tonic-gate struct pcfs *fsp; 712264a6e74Sfrankho timestruc_t now, *timep; 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate PC_DPRINTF2(6, "pcfs_setattr: vp=%p mask=%x\n", (void *)vp, (int)mask); 7157c478bd9Sstevel@tonic-gate /* 7167c478bd9Sstevel@tonic-gate * cannot set these attributes 7177c478bd9Sstevel@tonic-gate */ 7187c478bd9Sstevel@tonic-gate if (mask & (AT_NOSET | AT_UID | AT_GID)) { 7197c478bd9Sstevel@tonic-gate return (EINVAL); 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate /* 722264a6e74Sfrankho * pcfs_setattr is now allowed on directories to avoid silly warnings 7237c478bd9Sstevel@tonic-gate * from 'tar' when it tries to set times on a directory, and console 7247c478bd9Sstevel@tonic-gate * printf's on the NFS server when it gets EINVAL back on such a 7257c478bd9Sstevel@tonic-gate * request. One possible problem with that since a directory entry 7267c478bd9Sstevel@tonic-gate * identifies a file, '.' and all the '..' entries in subdirectories 7277c478bd9Sstevel@tonic-gate * may get out of sync when the directory is updated since they're 7287c478bd9Sstevel@tonic-gate * treated like separate files. We could fix that by looking for 7297c478bd9Sstevel@tonic-gate * '.' and giving it the same attributes, and then looking for 7307c478bd9Sstevel@tonic-gate * all the subdirectories and updating '..', but that's pretty 7317c478bd9Sstevel@tonic-gate * expensive for something that doesn't seem likely to matter. 7327c478bd9Sstevel@tonic-gate */ 7337c478bd9Sstevel@tonic-gate /* can't do some ops on directories anyway */ 7347c478bd9Sstevel@tonic-gate if ((vp->v_type == VDIR) && 7357c478bd9Sstevel@tonic-gate (mask & AT_SIZE)) { 7367c478bd9Sstevel@tonic-gate return (EINVAL); 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 7407c478bd9Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 7417c478bd9Sstevel@tonic-gate if (error) 7427c478bd9Sstevel@tonic-gate return (error); 7439bd42341Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 7447c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 7457c478bd9Sstevel@tonic-gate return (EIO); 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 7497c478bd9Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 7507c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 7517c478bd9Sstevel@tonic-gate return (EACCES); 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate /* 7567c478bd9Sstevel@tonic-gate * Change file access modes. 7577c478bd9Sstevel@tonic-gate * If nobody has write permission, file is marked readonly. 7587c478bd9Sstevel@tonic-gate * Otherwise file is writable by anyone. 7597c478bd9Sstevel@tonic-gate */ 7607c478bd9Sstevel@tonic-gate if ((mask & AT_MODE) && (vap->va_mode != (mode_t)-1)) { 7617c478bd9Sstevel@tonic-gate if ((vap->va_mode & 0222) == 0) 7627c478bd9Sstevel@tonic-gate pcp->pc_entry.pcd_attr |= PCA_RDONLY; 7637c478bd9Sstevel@tonic-gate else 7647c478bd9Sstevel@tonic-gate pcp->pc_entry.pcd_attr &= ~PCA_RDONLY; 7657c478bd9Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate /* 7687c478bd9Sstevel@tonic-gate * Truncate file. Must have write permission. 7697c478bd9Sstevel@tonic-gate */ 7707c478bd9Sstevel@tonic-gate if ((mask & AT_SIZE) && (vap->va_size != (u_offset_t)-1)) { 7717c478bd9Sstevel@tonic-gate if (pcp->pc_entry.pcd_attr & PCA_RDONLY) { 7727c478bd9Sstevel@tonic-gate error = EACCES; 7737c478bd9Sstevel@tonic-gate goto out; 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate if (vap->va_size > UINT32_MAX) { 7767c478bd9Sstevel@tonic-gate error = EFBIG; 7777c478bd9Sstevel@tonic-gate goto out; 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate error = pc_truncate(pcp, (uint_t)vap->va_size); 78072102e74SBryan Cantrill 7817c478bd9Sstevel@tonic-gate if (error) 7827c478bd9Sstevel@tonic-gate goto out; 78372102e74SBryan Cantrill 78472102e74SBryan Cantrill if (vap->va_size == 0) 78572102e74SBryan Cantrill vnevent_truncate(vp, ct); 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate /* 7887c478bd9Sstevel@tonic-gate * Change file modified times. 7897c478bd9Sstevel@tonic-gate */ 790264a6e74Sfrankho if (mask & (AT_MTIME | AT_CTIME)) { 7917c478bd9Sstevel@tonic-gate /* 7927c478bd9Sstevel@tonic-gate * If SysV-compatible option to set access and 7937c478bd9Sstevel@tonic-gate * modified times if privileged, owner, or write access, 7947c478bd9Sstevel@tonic-gate * use current time rather than va_mtime. 7957c478bd9Sstevel@tonic-gate * 7967c478bd9Sstevel@tonic-gate * XXX - va_mtime.tv_sec == -1 flags this. 7977c478bd9Sstevel@tonic-gate */ 798264a6e74Sfrankho timep = &vap->va_mtime; 7997c478bd9Sstevel@tonic-gate if (vap->va_mtime.tv_sec == -1) { 8007c478bd9Sstevel@tonic-gate gethrestime(&now); 801264a6e74Sfrankho timep = &now; 8027c478bd9Sstevel@tonic-gate } 803264a6e74Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 && 804264a6e74Sfrankho timep->tv_sec > INT32_MAX) { 805264a6e74Sfrankho error = EOVERFLOW; 806264a6e74Sfrankho goto out; 807264a6e74Sfrankho } 808264a6e74Sfrankho error = pc_tvtopct(timep, &pcp->pc_entry.pcd_mtime); 809264a6e74Sfrankho if (error) 810264a6e74Sfrankho goto out; 8117c478bd9Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate /* 8147c478bd9Sstevel@tonic-gate * Change file access times. 8157c478bd9Sstevel@tonic-gate */ 816264a6e74Sfrankho if (mask & AT_ATIME) { 8177c478bd9Sstevel@tonic-gate /* 8187c478bd9Sstevel@tonic-gate * If SysV-compatible option to set access and 8197c478bd9Sstevel@tonic-gate * modified times if privileged, owner, or write access, 8207c478bd9Sstevel@tonic-gate * use current time rather than va_mtime. 8217c478bd9Sstevel@tonic-gate * 8227c478bd9Sstevel@tonic-gate * XXX - va_atime.tv_sec == -1 flags this. 8237c478bd9Sstevel@tonic-gate */ 8247c478bd9Sstevel@tonic-gate struct pctime atime; 8257c478bd9Sstevel@tonic-gate 826264a6e74Sfrankho timep = &vap->va_atime; 8277c478bd9Sstevel@tonic-gate if (vap->va_atime.tv_sec == -1) { 8287c478bd9Sstevel@tonic-gate gethrestime(&now); 829264a6e74Sfrankho timep = &now; 8307c478bd9Sstevel@tonic-gate } 831264a6e74Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 && 832264a6e74Sfrankho timep->tv_sec > INT32_MAX) { 833264a6e74Sfrankho error = EOVERFLOW; 834264a6e74Sfrankho goto out; 835264a6e74Sfrankho } 836264a6e74Sfrankho error = pc_tvtopct(timep, &atime); 837264a6e74Sfrankho if (error) 838264a6e74Sfrankho goto out; 8397c478bd9Sstevel@tonic-gate pcp->pc_entry.pcd_ladate = atime.pct_date; 8407c478bd9Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 8417c478bd9Sstevel@tonic-gate } 8427c478bd9Sstevel@tonic-gate out: 8437c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 8447c478bd9Sstevel@tonic-gate return (error); 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8497c478bd9Sstevel@tonic-gate static int 8507c478bd9Sstevel@tonic-gate pcfs_access( 8517c478bd9Sstevel@tonic-gate struct vnode *vp, 8527c478bd9Sstevel@tonic-gate int mode, 8537c478bd9Sstevel@tonic-gate int flags, 854da6c28aaSamw struct cred *cr, 855da6c28aaSamw caller_context_t *ct) 8567c478bd9Sstevel@tonic-gate { 8577c478bd9Sstevel@tonic-gate struct pcnode *pcp; 8587c478bd9Sstevel@tonic-gate struct pcfs *fsp; 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 8627c478bd9Sstevel@tonic-gate 8639bd42341Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) 8647c478bd9Sstevel@tonic-gate return (EIO); 8657c478bd9Sstevel@tonic-gate if ((mode & VWRITE) && (pcp->pc_entry.pcd_attr & PCA_RDONLY)) 8667c478bd9Sstevel@tonic-gate return (EACCES); 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate /* 8697c478bd9Sstevel@tonic-gate * If this is a boot partition, privileged users have full access while 8707c478bd9Sstevel@tonic-gate * others have read-only access. 8717c478bd9Sstevel@tonic-gate */ 8727c478bd9Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 8737c478bd9Sstevel@tonic-gate if ((mode & VWRITE) && 8747c478bd9Sstevel@tonic-gate secpolicy_pcfs_modify_bootpartition(cr) != 0) 8757c478bd9Sstevel@tonic-gate return (EACCES); 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate return (0); 8787c478bd9Sstevel@tonic-gate } 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8827c478bd9Sstevel@tonic-gate static int 8837c478bd9Sstevel@tonic-gate pcfs_fsync( 8847c478bd9Sstevel@tonic-gate struct vnode *vp, 8857c478bd9Sstevel@tonic-gate int syncflag, 886da6c28aaSamw struct cred *cr, 887da6c28aaSamw caller_context_t *ct) 8887c478bd9Sstevel@tonic-gate { 8897c478bd9Sstevel@tonic-gate struct pcfs *fsp; 8907c478bd9Sstevel@tonic-gate struct pcnode *pcp; 8917c478bd9Sstevel@tonic-gate int error; 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 8947c478bd9Sstevel@tonic-gate if (error = pc_verify(fsp)) 8957c478bd9Sstevel@tonic-gate return (error); 8967c478bd9Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 8977c478bd9Sstevel@tonic-gate if (error) 8987c478bd9Sstevel@tonic-gate return (error); 8999bd42341Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 9007c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 9017c478bd9Sstevel@tonic-gate return (EIO); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_WRITER); 9047c478bd9Sstevel@tonic-gate error = pc_nodesync(pcp); 9057c478bd9Sstevel@tonic-gate rw_exit(&pcnodes_lock); 9067c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 9077c478bd9Sstevel@tonic-gate return (error); 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9127c478bd9Sstevel@tonic-gate static void 9137c478bd9Sstevel@tonic-gate pcfs_inactive( 9147c478bd9Sstevel@tonic-gate struct vnode *vp, 915da6c28aaSamw struct cred *cr, 916da6c28aaSamw caller_context_t *ct) 9177c478bd9Sstevel@tonic-gate { 9187c478bd9Sstevel@tonic-gate struct pcnode *pcp; 9197c478bd9Sstevel@tonic-gate struct pcfs *fsp; 9207c478bd9Sstevel@tonic-gate int error; 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 9237c478bd9Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 1); 9247c478bd9Sstevel@tonic-gate 925264a6e74Sfrankho /* 926264a6e74Sfrankho * If the filesystem was umounted by force, all dirty 927264a6e74Sfrankho * pages associated with this vnode are invalidated 928264a6e74Sfrankho * and then the vnode will be freed. 929264a6e74Sfrankho */ 930264a6e74Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) { 931264a6e74Sfrankho pcp = VTOPC(vp); 932264a6e74Sfrankho if (vn_has_cached_data(vp)) { 933264a6e74Sfrankho (void) pvn_vplist_dirty(vp, (u_offset_t)0, 934264a6e74Sfrankho pcfs_putapage, B_INVAL, (struct cred *)NULL); 935264a6e74Sfrankho } 936264a6e74Sfrankho remque(pcp); 937264a6e74Sfrankho if (error == 0) 938264a6e74Sfrankho pc_unlockfs(fsp); 939264a6e74Sfrankho vn_free(vp); 940264a6e74Sfrankho kmem_free(pcp, sizeof (struct pcnode)); 941264a6e74Sfrankho VFS_RELE(PCFSTOVFS(fsp)); 942264a6e74Sfrankho return; 943264a6e74Sfrankho } 944264a6e74Sfrankho 9457c478bd9Sstevel@tonic-gate mutex_enter(&vp->v_lock); 9467c478bd9Sstevel@tonic-gate ASSERT(vp->v_count >= 1); 9477c478bd9Sstevel@tonic-gate if (vp->v_count > 1) { 9487c478bd9Sstevel@tonic-gate vp->v_count--; /* release our hold from vn_rele */ 9497c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock); 9507c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 9517c478bd9Sstevel@tonic-gate return; 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock); 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate /* 9567c478bd9Sstevel@tonic-gate * Check again to confirm that no intervening I/O error 9577c478bd9Sstevel@tonic-gate * with a subsequent pc_diskchanged() call has released 9587c478bd9Sstevel@tonic-gate * the pcnode. If it has then release the vnode as above. 9597c478bd9Sstevel@tonic-gate */ 9609bd42341Sfrankho pcp = VTOPC(vp); 9619bd42341Sfrankho if (pcp == NULL || pcp->pc_flags & PC_INVAL) { 962264a6e74Sfrankho if (vn_has_cached_data(vp)) 963264a6e74Sfrankho (void) pvn_vplist_dirty(vp, (u_offset_t)0, 964264a6e74Sfrankho pcfs_putapage, B_INVAL | B_TRUNC, 965264a6e74Sfrankho (struct cred *)NULL); 9669bd42341Sfrankho } 9679bd42341Sfrankho 9689bd42341Sfrankho if (pcp == NULL) { 9697c478bd9Sstevel@tonic-gate vn_free(vp); 970264a6e74Sfrankho } else { 9717c478bd9Sstevel@tonic-gate pc_rele(pcp); 972264a6e74Sfrankho } 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate if (!error) 9757c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 9767c478bd9Sstevel@tonic-gate } 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9797c478bd9Sstevel@tonic-gate static int 9807c478bd9Sstevel@tonic-gate pcfs_lookup( 9817c478bd9Sstevel@tonic-gate struct vnode *dvp, 9827c478bd9Sstevel@tonic-gate char *nm, 9837c478bd9Sstevel@tonic-gate struct vnode **vpp, 9847c478bd9Sstevel@tonic-gate struct pathname *pnp, 9857c478bd9Sstevel@tonic-gate int flags, 9867c478bd9Sstevel@tonic-gate struct vnode *rdir, 987da6c28aaSamw struct cred *cr, 988da6c28aaSamw caller_context_t *ct, 989da6c28aaSamw int *direntflags, 990da6c28aaSamw pathname_t *realpnp) 9917c478bd9Sstevel@tonic-gate { 9927c478bd9Sstevel@tonic-gate struct pcfs *fsp; 9937c478bd9Sstevel@tonic-gate struct pcnode *pcp; 9947c478bd9Sstevel@tonic-gate int error; 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate /* 997264a6e74Sfrankho * If the filesystem was umounted by force, return immediately. 998264a6e74Sfrankho */ 999264a6e74Sfrankho if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 1000264a6e74Sfrankho return (EIO); 1001264a6e74Sfrankho 1002264a6e74Sfrankho /* 10037c478bd9Sstevel@tonic-gate * verify that the dvp is still valid on the disk 10047c478bd9Sstevel@tonic-gate */ 10057c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 10067c478bd9Sstevel@tonic-gate if (error = pc_verify(fsp)) 10077c478bd9Sstevel@tonic-gate return (error); 10087c478bd9Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 10097c478bd9Sstevel@tonic-gate if (error) 10107c478bd9Sstevel@tonic-gate return (error); 10119bd42341Sfrankho if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) { 10127c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 10137c478bd9Sstevel@tonic-gate return (EIO); 10147c478bd9Sstevel@tonic-gate } 10157c478bd9Sstevel@tonic-gate /* 10167c478bd9Sstevel@tonic-gate * Null component name is a synonym for directory being searched. 10177c478bd9Sstevel@tonic-gate */ 10187c478bd9Sstevel@tonic-gate if (*nm == '\0') { 10197c478bd9Sstevel@tonic-gate VN_HOLD(dvp); 10207c478bd9Sstevel@tonic-gate *vpp = dvp; 10217c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 10227c478bd9Sstevel@tonic-gate return (0); 10237c478bd9Sstevel@tonic-gate } 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate error = pc_dirlook(VTOPC(dvp), nm, &pcp); 10267c478bd9Sstevel@tonic-gate if (!error) { 10277c478bd9Sstevel@tonic-gate *vpp = PCTOV(pcp); 10287c478bd9Sstevel@tonic-gate pcp->pc_flags |= PC_EXTERNAL; 10297c478bd9Sstevel@tonic-gate } 10307c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 10317c478bd9Sstevel@tonic-gate return (error); 10327c478bd9Sstevel@tonic-gate } 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10367c478bd9Sstevel@tonic-gate static int 10377c478bd9Sstevel@tonic-gate pcfs_create( 10387c478bd9Sstevel@tonic-gate struct vnode *dvp, 10397c478bd9Sstevel@tonic-gate char *nm, 10407c478bd9Sstevel@tonic-gate struct vattr *vap, 10417c478bd9Sstevel@tonic-gate enum vcexcl exclusive, 10427c478bd9Sstevel@tonic-gate int mode, 10437c478bd9Sstevel@tonic-gate struct vnode **vpp, 10447c478bd9Sstevel@tonic-gate struct cred *cr, 1045da6c28aaSamw int flag, 1046da6c28aaSamw caller_context_t *ct, 1047da6c28aaSamw vsecattr_t *vsecp) 10487c478bd9Sstevel@tonic-gate { 10497c478bd9Sstevel@tonic-gate int error; 10507c478bd9Sstevel@tonic-gate struct pcnode *pcp; 10517c478bd9Sstevel@tonic-gate struct vnode *vp; 10527c478bd9Sstevel@tonic-gate struct pcfs *fsp; 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate /* 10557c478bd9Sstevel@tonic-gate * can't create directories. use pcfs_mkdir. 10567c478bd9Sstevel@tonic-gate * can't create anything other than files. 10577c478bd9Sstevel@tonic-gate */ 10587c478bd9Sstevel@tonic-gate if (vap->va_type == VDIR) 10597c478bd9Sstevel@tonic-gate return (EISDIR); 10607c478bd9Sstevel@tonic-gate else if (vap->va_type != VREG) 10617c478bd9Sstevel@tonic-gate return (EINVAL); 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate pcp = NULL; 10647c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 10657c478bd9Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 10667c478bd9Sstevel@tonic-gate if (error) 10677c478bd9Sstevel@tonic-gate return (error); 10689bd42341Sfrankho if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) { 10697c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 10707c478bd9Sstevel@tonic-gate return (EIO); 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 10747c478bd9Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 10757c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 10767c478bd9Sstevel@tonic-gate return (EACCES); 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate if (*nm == '\0') { 10817c478bd9Sstevel@tonic-gate /* 10827c478bd9Sstevel@tonic-gate * Null component name refers to the directory itself. 10837c478bd9Sstevel@tonic-gate */ 10847c478bd9Sstevel@tonic-gate VN_HOLD(dvp); 10857c478bd9Sstevel@tonic-gate pcp = VTOPC(dvp); 10867c478bd9Sstevel@tonic-gate error = EEXIST; 10877c478bd9Sstevel@tonic-gate } else { 10887c478bd9Sstevel@tonic-gate error = pc_direnter(VTOPC(dvp), nm, vap, &pcp); 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate /* 10917c478bd9Sstevel@tonic-gate * if file exists and this is a nonexclusive create, 10927c478bd9Sstevel@tonic-gate * check for access permissions 10937c478bd9Sstevel@tonic-gate */ 10947c478bd9Sstevel@tonic-gate if (error == EEXIST) { 10957c478bd9Sstevel@tonic-gate vp = PCTOV(pcp); 10967c478bd9Sstevel@tonic-gate if (exclusive == NONEXCL) { 10977c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 10987c478bd9Sstevel@tonic-gate error = EISDIR; 10997c478bd9Sstevel@tonic-gate } else if (mode) { 11007c478bd9Sstevel@tonic-gate error = pcfs_access(PCTOV(pcp), mode, 0, 1101da6c28aaSamw cr, ct); 11027c478bd9Sstevel@tonic-gate } else { 11037c478bd9Sstevel@tonic-gate error = 0; 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate if (error) { 11077c478bd9Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 11087c478bd9Sstevel@tonic-gate } else if ((vp->v_type == VREG) && (vap->va_mask & AT_SIZE) && 11097c478bd9Sstevel@tonic-gate (vap->va_size == 0)) { 11107c478bd9Sstevel@tonic-gate error = pc_truncate(pcp, 0L); 1111df2381bfSpraks if (error) { 11127c478bd9Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 1113df2381bfSpraks } else { 1114da6c28aaSamw vnevent_create(PCTOV(pcp), ct); 1115df2381bfSpraks } 11167c478bd9Sstevel@tonic-gate } 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate if (error) { 11197c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 11207c478bd9Sstevel@tonic-gate return (error); 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate *vpp = PCTOV(pcp); 11237c478bd9Sstevel@tonic-gate pcp->pc_flags |= PC_EXTERNAL; 11247c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 11257c478bd9Sstevel@tonic-gate return (error); 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11297c478bd9Sstevel@tonic-gate static int 11307c478bd9Sstevel@tonic-gate pcfs_remove( 11317c478bd9Sstevel@tonic-gate struct vnode *vp, 11327c478bd9Sstevel@tonic-gate char *nm, 1133da6c28aaSamw struct cred *cr, 1134da6c28aaSamw caller_context_t *ct, 1135da6c28aaSamw int flags) 11367c478bd9Sstevel@tonic-gate { 11377c478bd9Sstevel@tonic-gate struct pcfs *fsp; 11387c478bd9Sstevel@tonic-gate struct pcnode *pcp; 11397c478bd9Sstevel@tonic-gate int error; 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 11427c478bd9Sstevel@tonic-gate if (error = pc_verify(fsp)) 11437c478bd9Sstevel@tonic-gate return (error); 11447c478bd9Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 11457c478bd9Sstevel@tonic-gate if (error) 11467c478bd9Sstevel@tonic-gate return (error); 11479bd42341Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 11487c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 11497c478bd9Sstevel@tonic-gate return (EIO); 11507c478bd9Sstevel@tonic-gate } 11517c478bd9Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 11527c478bd9Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 11537c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 11547c478bd9Sstevel@tonic-gate return (EACCES); 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate } 1157da6c28aaSamw error = pc_dirremove(pcp, nm, (struct vnode *)0, VREG, ct); 11587c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 11597c478bd9Sstevel@tonic-gate return (error); 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate /* 11637c478bd9Sstevel@tonic-gate * Rename a file or directory 11647c478bd9Sstevel@tonic-gate * This rename is restricted to only rename files within a directory. 11657c478bd9Sstevel@tonic-gate * XX should make rename more general 11667c478bd9Sstevel@tonic-gate */ 11677c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11687c478bd9Sstevel@tonic-gate static int 11697c478bd9Sstevel@tonic-gate pcfs_rename( 11707c478bd9Sstevel@tonic-gate struct vnode *sdvp, /* old (source) parent vnode */ 11717c478bd9Sstevel@tonic-gate char *snm, /* old (source) entry name */ 11727c478bd9Sstevel@tonic-gate struct vnode *tdvp, /* new (target) parent vnode */ 11737c478bd9Sstevel@tonic-gate char *tnm, /* new (target) entry name */ 1174da6c28aaSamw struct cred *cr, 1175da6c28aaSamw caller_context_t *ct, 1176da6c28aaSamw int flags) 11777c478bd9Sstevel@tonic-gate { 11787c478bd9Sstevel@tonic-gate struct pcfs *fsp; 11797c478bd9Sstevel@tonic-gate struct pcnode *dp; /* parent pcnode */ 11807c478bd9Sstevel@tonic-gate struct pcnode *tdp; 11817c478bd9Sstevel@tonic-gate int error; 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(sdvp->v_vfsp); 11847c478bd9Sstevel@tonic-gate if (error = pc_verify(fsp)) 11857c478bd9Sstevel@tonic-gate return (error); 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate /* 11887c478bd9Sstevel@tonic-gate * make sure we can muck with this directory. 11897c478bd9Sstevel@tonic-gate */ 1190da6c28aaSamw error = pcfs_access(sdvp, VWRITE, 0, cr, ct); 11917c478bd9Sstevel@tonic-gate if (error) { 11927c478bd9Sstevel@tonic-gate return (error); 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 11957c478bd9Sstevel@tonic-gate if (error) 11967c478bd9Sstevel@tonic-gate return (error); 11979bd42341Sfrankho if (((dp = VTOPC(sdvp)) == NULL) || ((tdp = VTOPC(tdvp)) == NULL) || 11989bd42341Sfrankho (dp->pc_flags & PC_INVAL) || (tdp->pc_flags & PC_INVAL)) { 11997c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 12007c478bd9Sstevel@tonic-gate return (EIO); 12017c478bd9Sstevel@tonic-gate } 1202da6c28aaSamw error = pc_rename(dp, tdp, snm, tnm, ct); 12037c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 12047c478bd9Sstevel@tonic-gate return (error); 12057c478bd9Sstevel@tonic-gate } 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12087c478bd9Sstevel@tonic-gate static int 12097c478bd9Sstevel@tonic-gate pcfs_mkdir( 12107c478bd9Sstevel@tonic-gate struct vnode *dvp, 12117c478bd9Sstevel@tonic-gate char *nm, 12127c478bd9Sstevel@tonic-gate struct vattr *vap, 12137c478bd9Sstevel@tonic-gate struct vnode **vpp, 1214da6c28aaSamw struct cred *cr, 1215da6c28aaSamw caller_context_t *ct, 1216da6c28aaSamw int flags, 1217da6c28aaSamw vsecattr_t *vsecp) 12187c478bd9Sstevel@tonic-gate { 12197c478bd9Sstevel@tonic-gate struct pcfs *fsp; 12207c478bd9Sstevel@tonic-gate struct pcnode *pcp; 12217c478bd9Sstevel@tonic-gate int error; 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 12247c478bd9Sstevel@tonic-gate if (error = pc_verify(fsp)) 12257c478bd9Sstevel@tonic-gate return (error); 12267c478bd9Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 12277c478bd9Sstevel@tonic-gate if (error) 12287c478bd9Sstevel@tonic-gate return (error); 12299bd42341Sfrankho if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) { 12307c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 12317c478bd9Sstevel@tonic-gate return (EIO); 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 12357c478bd9Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 12367c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 12377c478bd9Sstevel@tonic-gate return (EACCES); 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate } 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate error = pc_direnter(VTOPC(dvp), nm, vap, &pcp); 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate if (!error) { 12447c478bd9Sstevel@tonic-gate pcp -> pc_flags |= PC_EXTERNAL; 12457c478bd9Sstevel@tonic-gate *vpp = PCTOV(pcp); 12467c478bd9Sstevel@tonic-gate } else if (error == EEXIST) { 12477c478bd9Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 12487c478bd9Sstevel@tonic-gate } 12497c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 12507c478bd9Sstevel@tonic-gate return (error); 12517c478bd9Sstevel@tonic-gate } 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12547c478bd9Sstevel@tonic-gate static int 12557c478bd9Sstevel@tonic-gate pcfs_rmdir( 12567c478bd9Sstevel@tonic-gate struct vnode *dvp, 12577c478bd9Sstevel@tonic-gate char *nm, 12587c478bd9Sstevel@tonic-gate struct vnode *cdir, 1259da6c28aaSamw struct cred *cr, 1260da6c28aaSamw caller_context_t *ct, 1261da6c28aaSamw int flags) 12627c478bd9Sstevel@tonic-gate { 12637c478bd9Sstevel@tonic-gate struct pcfs *fsp; 12647c478bd9Sstevel@tonic-gate struct pcnode *pcp; 12657c478bd9Sstevel@tonic-gate int error; 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(dvp -> v_vfsp); 12687c478bd9Sstevel@tonic-gate if (error = pc_verify(fsp)) 12697c478bd9Sstevel@tonic-gate return (error); 12707c478bd9Sstevel@tonic-gate if (error = pc_lockfs(fsp, 0, 0)) 12717c478bd9Sstevel@tonic-gate return (error); 12727c478bd9Sstevel@tonic-gate 12739bd42341Sfrankho if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) { 12747c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 12757c478bd9Sstevel@tonic-gate return (EIO); 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) { 12797c478bd9Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) { 12807c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 12817c478bd9Sstevel@tonic-gate return (EACCES); 12827c478bd9Sstevel@tonic-gate } 12837c478bd9Sstevel@tonic-gate } 12847c478bd9Sstevel@tonic-gate 1285da6c28aaSamw error = pc_dirremove(pcp, nm, cdir, VDIR, ct); 12867c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 12877c478bd9Sstevel@tonic-gate return (error); 12887c478bd9Sstevel@tonic-gate } 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate /* 12917c478bd9Sstevel@tonic-gate * read entries in a directory. 12927c478bd9Sstevel@tonic-gate * we must convert pc format to unix format 12937c478bd9Sstevel@tonic-gate */ 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12967c478bd9Sstevel@tonic-gate static int 12977c478bd9Sstevel@tonic-gate pcfs_readdir( 12987c478bd9Sstevel@tonic-gate struct vnode *dvp, 12997c478bd9Sstevel@tonic-gate struct uio *uiop, 13007c478bd9Sstevel@tonic-gate struct cred *cr, 1301da6c28aaSamw int *eofp, 1302da6c28aaSamw caller_context_t *ct, 1303da6c28aaSamw int flags) 13047c478bd9Sstevel@tonic-gate { 13057c478bd9Sstevel@tonic-gate struct pcnode *pcp; 13067c478bd9Sstevel@tonic-gate struct pcfs *fsp; 13077c478bd9Sstevel@tonic-gate struct pcdir *ep; 13087c478bd9Sstevel@tonic-gate struct buf *bp = NULL; 13097c478bd9Sstevel@tonic-gate offset_t offset; 13107c478bd9Sstevel@tonic-gate int boff; 13117c478bd9Sstevel@tonic-gate struct pc_dirent lbp; 13127c478bd9Sstevel@tonic-gate struct pc_dirent *ld = &lbp; 13137c478bd9Sstevel@tonic-gate int error; 13147c478bd9Sstevel@tonic-gate 1315264a6e74Sfrankho /* 1316264a6e74Sfrankho * If the filesystem was umounted by force, return immediately. 1317264a6e74Sfrankho */ 1318264a6e74Sfrankho if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 1319264a6e74Sfrankho return (EIO); 1320264a6e74Sfrankho 13217c478bd9Sstevel@tonic-gate if ((uiop->uio_iovcnt != 1) || 13227c478bd9Sstevel@tonic-gate (uiop->uio_loffset % sizeof (struct pcdir)) != 0) { 13237c478bd9Sstevel@tonic-gate return (EINVAL); 13247c478bd9Sstevel@tonic-gate } 13257c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp); 13267c478bd9Sstevel@tonic-gate /* 13277c478bd9Sstevel@tonic-gate * verify that the dp is still valid on the disk 13287c478bd9Sstevel@tonic-gate */ 13297c478bd9Sstevel@tonic-gate if (error = pc_verify(fsp)) { 13307c478bd9Sstevel@tonic-gate return (error); 13317c478bd9Sstevel@tonic-gate } 13327c478bd9Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 13337c478bd9Sstevel@tonic-gate if (error) 13347c478bd9Sstevel@tonic-gate return (error); 13359bd42341Sfrankho if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) { 13367c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 13377c478bd9Sstevel@tonic-gate return (EIO); 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate bzero(ld, sizeof (*ld)); 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate if (eofp != NULL) 13437c478bd9Sstevel@tonic-gate *eofp = 0; 13447c478bd9Sstevel@tonic-gate offset = uiop->uio_loffset; 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate if (dvp->v_flag & VROOT) { 13477c478bd9Sstevel@tonic-gate /* 13487c478bd9Sstevel@tonic-gate * kludge up entries for "." and ".." in the root. 13497c478bd9Sstevel@tonic-gate */ 13507c478bd9Sstevel@tonic-gate if (offset == 0) { 13517c478bd9Sstevel@tonic-gate (void) strcpy(ld->d_name, "."); 13527c478bd9Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(1); 13537c478bd9Sstevel@tonic-gate ld->d_off = (off64_t)sizeof (struct pcdir); 13547c478bd9Sstevel@tonic-gate ld->d_ino = (ino64_t)UINT_MAX; 13557c478bd9Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 13567c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 13577c478bd9Sstevel@tonic-gate return (ENOSPC); 13587c478bd9Sstevel@tonic-gate } 13597c478bd9Sstevel@tonic-gate (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop); 13607c478bd9Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 13617c478bd9Sstevel@tonic-gate offset = uiop->uio_loffset; 13627c478bd9Sstevel@tonic-gate } 13637c478bd9Sstevel@tonic-gate if (offset == sizeof (struct pcdir)) { 13647c478bd9Sstevel@tonic-gate (void) strcpy(ld->d_name, ".."); 13657c478bd9Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(2); 13667c478bd9Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 13677c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 13687c478bd9Sstevel@tonic-gate return (ENOSPC); 13697c478bd9Sstevel@tonic-gate } 13707c478bd9Sstevel@tonic-gate ld->d_off = (off64_t)(uiop->uio_loffset + 13717c478bd9Sstevel@tonic-gate sizeof (struct pcdir)); 13727c478bd9Sstevel@tonic-gate ld->d_ino = (ino64_t)UINT_MAX; 13737c478bd9Sstevel@tonic-gate (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop); 13747c478bd9Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 13757c478bd9Sstevel@tonic-gate offset = uiop->uio_loffset; 13767c478bd9Sstevel@tonic-gate } 13777c478bd9Sstevel@tonic-gate offset -= 2 * sizeof (struct pcdir); 13787c478bd9Sstevel@tonic-gate /* offset now has the real offset value into directory file */ 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate for (;;) { 13827c478bd9Sstevel@tonic-gate boff = pc_blkoff(fsp, offset); 13837c478bd9Sstevel@tonic-gate if (boff == 0 || bp == NULL || boff >= bp->b_bcount) { 13847c478bd9Sstevel@tonic-gate if (bp != NULL) { 13857c478bd9Sstevel@tonic-gate brelse(bp); 13867c478bd9Sstevel@tonic-gate bp = NULL; 13877c478bd9Sstevel@tonic-gate } 13887c478bd9Sstevel@tonic-gate error = pc_blkatoff(pcp, offset, &bp, &ep); 13897c478bd9Sstevel@tonic-gate if (error) { 13907c478bd9Sstevel@tonic-gate if (error == ENOENT) { 13917c478bd9Sstevel@tonic-gate error = 0; 13927c478bd9Sstevel@tonic-gate if (eofp) 13937c478bd9Sstevel@tonic-gate *eofp = 1; 13947c478bd9Sstevel@tonic-gate } 13957c478bd9Sstevel@tonic-gate break; 13967c478bd9Sstevel@tonic-gate } 13977c478bd9Sstevel@tonic-gate } 13987c478bd9Sstevel@tonic-gate if (ep->pcd_filename[0] == PCD_UNUSED) { 13997c478bd9Sstevel@tonic-gate if (eofp) 14007c478bd9Sstevel@tonic-gate *eofp = 1; 14017c478bd9Sstevel@tonic-gate break; 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate /* 14047c478bd9Sstevel@tonic-gate * Don't display label because it may contain funny characters. 14057c478bd9Sstevel@tonic-gate */ 14067c478bd9Sstevel@tonic-gate if (ep->pcd_filename[0] == PCD_ERASED) { 14077c478bd9Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir); 14087c478bd9Sstevel@tonic-gate offset += sizeof (struct pcdir); 14097c478bd9Sstevel@tonic-gate ep++; 14107c478bd9Sstevel@tonic-gate continue; 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate if (PCDL_IS_LFN(ep)) { 14137c478bd9Sstevel@tonic-gate if (pc_read_long_fn(dvp, uiop, ld, &ep, &offset, &bp) != 14147c478bd9Sstevel@tonic-gate 0) 14157c478bd9Sstevel@tonic-gate break; 14167c478bd9Sstevel@tonic-gate continue; 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate if (pc_read_short_fn(dvp, uiop, ld, &ep, &offset, &bp) != 0) 14207c478bd9Sstevel@tonic-gate break; 14217c478bd9Sstevel@tonic-gate } 14227c478bd9Sstevel@tonic-gate if (bp) 14237c478bd9Sstevel@tonic-gate brelse(bp); 14247c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 14257c478bd9Sstevel@tonic-gate return (error); 14267c478bd9Sstevel@tonic-gate } 14277c478bd9Sstevel@tonic-gate 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate /* 1430*06e6833aSJosef 'Jeff' Sipek * Called from pvn_getpages to get a particular page. When we are called 1431*06e6833aSJosef 'Jeff' Sipek * the pcfs is already locked. 14327c478bd9Sstevel@tonic-gate */ 14337c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14347c478bd9Sstevel@tonic-gate static int 14357c478bd9Sstevel@tonic-gate pcfs_getapage( 14367c478bd9Sstevel@tonic-gate struct vnode *vp, 14377c478bd9Sstevel@tonic-gate u_offset_t off, 14387c478bd9Sstevel@tonic-gate size_t len, 14397c478bd9Sstevel@tonic-gate uint_t *protp, 14407c478bd9Sstevel@tonic-gate page_t *pl[], /* NULL if async IO is requested */ 14417c478bd9Sstevel@tonic-gate size_t plsz, 14427c478bd9Sstevel@tonic-gate struct seg *seg, 14437c478bd9Sstevel@tonic-gate caddr_t addr, 14447c478bd9Sstevel@tonic-gate enum seg_rw rw, 14457c478bd9Sstevel@tonic-gate struct cred *cr) 14467c478bd9Sstevel@tonic-gate { 14477c478bd9Sstevel@tonic-gate struct pcnode *pcp; 14487c478bd9Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 14497c478bd9Sstevel@tonic-gate struct vnode *devvp; 14507c478bd9Sstevel@tonic-gate page_t *pp; 14517c478bd9Sstevel@tonic-gate page_t *pagefound; 14527c478bd9Sstevel@tonic-gate int err; 14537c478bd9Sstevel@tonic-gate 1454264a6e74Sfrankho /* 1455264a6e74Sfrankho * If the filesystem was umounted by force, return immediately. 1456264a6e74Sfrankho */ 1457264a6e74Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 1458264a6e74Sfrankho return (EIO); 1459264a6e74Sfrankho 14607c478bd9Sstevel@tonic-gate PC_DPRINTF3(5, "pcfs_getapage: vp=%p off=%lld len=%lu\n", 14617c478bd9Sstevel@tonic-gate (void *)vp, off, len); 14627c478bd9Sstevel@tonic-gate 14639bd42341Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) 14647c478bd9Sstevel@tonic-gate return (EIO); 14657c478bd9Sstevel@tonic-gate devvp = fsp->pcfs_devvp; 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate /* pcfs doesn't do readaheads */ 14687c478bd9Sstevel@tonic-gate if (pl == NULL) 14697c478bd9Sstevel@tonic-gate return (0); 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate pl[0] = NULL; 14727c478bd9Sstevel@tonic-gate err = 0; 14737c478bd9Sstevel@tonic-gate /* 14747c478bd9Sstevel@tonic-gate * If the accessed time on the pcnode has not already been 14757c478bd9Sstevel@tonic-gate * set elsewhere (e.g. for read/setattr) we set the time now. 14767c478bd9Sstevel@tonic-gate * This gives us approximate modified times for mmap'ed files 14777c478bd9Sstevel@tonic-gate * which are accessed via loads in the user address space. 14787c478bd9Sstevel@tonic-gate */ 14797c478bd9Sstevel@tonic-gate if ((pcp->pc_flags & PC_ACC) == 0 && 14807c478bd9Sstevel@tonic-gate ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0)) { 1481f127cb91Sfrankho pc_mark_acc(fsp, pcp); 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate reread: 14847c478bd9Sstevel@tonic-gate if ((pagefound = page_exists(vp, off)) == NULL) { 14857c478bd9Sstevel@tonic-gate /* 14867c478bd9Sstevel@tonic-gate * Need to really do disk IO to get the page(s). 14877c478bd9Sstevel@tonic-gate */ 14887c478bd9Sstevel@tonic-gate struct buf *bp; 14897c478bd9Sstevel@tonic-gate daddr_t lbn, bn; 14907c478bd9Sstevel@tonic-gate u_offset_t io_off; 14917c478bd9Sstevel@tonic-gate size_t io_len; 14927c478bd9Sstevel@tonic-gate u_offset_t lbnoff, xferoffset; 14937c478bd9Sstevel@tonic-gate u_offset_t pgoff; 14947c478bd9Sstevel@tonic-gate uint_t xfersize; 14957c478bd9Sstevel@tonic-gate int err1; 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate lbn = pc_lblkno(fsp, off); 14987c478bd9Sstevel@tonic-gate lbnoff = off & ~(fsp->pcfs_clsize - 1); 14997c478bd9Sstevel@tonic-gate xferoffset = off & ~(fsp->pcfs_secsize - 1); 15007c478bd9Sstevel@tonic-gate 15017c478bd9Sstevel@tonic-gate pp = pvn_read_kluster(vp, off, seg, addr, &io_off, &io_len, 15027c478bd9Sstevel@tonic-gate off, (size_t)MIN(pc_blksize(fsp, pcp, off), PAGESIZE), 0); 15037c478bd9Sstevel@tonic-gate if (pp == NULL) 15047c478bd9Sstevel@tonic-gate /* 15057c478bd9Sstevel@tonic-gate * XXX - If pcfs is made MT-hot, this should go 15067c478bd9Sstevel@tonic-gate * back to reread. 15077c478bd9Sstevel@tonic-gate */ 15087c478bd9Sstevel@tonic-gate panic("pcfs_getapage pvn_read_kluster"); 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate for (pgoff = 0; pgoff < PAGESIZE && xferoffset < pcp->pc_size; 15117c478bd9Sstevel@tonic-gate pgoff += xfersize, 15127c478bd9Sstevel@tonic-gate lbn += howmany(xfersize, fsp->pcfs_clsize), 15137c478bd9Sstevel@tonic-gate lbnoff += xfersize, xferoffset += xfersize) { 15147c478bd9Sstevel@tonic-gate /* 15157c478bd9Sstevel@tonic-gate * read as many contiguous blocks as possible to 15167c478bd9Sstevel@tonic-gate * fill this page 15177c478bd9Sstevel@tonic-gate */ 15187c478bd9Sstevel@tonic-gate xfersize = PAGESIZE - pgoff; 15197c478bd9Sstevel@tonic-gate err1 = pc_bmap(pcp, lbn, &bn, &xfersize); 15207c478bd9Sstevel@tonic-gate if (err1) { 15217c478bd9Sstevel@tonic-gate PC_DPRINTF1(1, "pc_getapage err=%d", err1); 15227c478bd9Sstevel@tonic-gate err = err1; 15237c478bd9Sstevel@tonic-gate goto out; 15247c478bd9Sstevel@tonic-gate } 15257c478bd9Sstevel@tonic-gate bp = pageio_setup(pp, xfersize, devvp, B_READ); 15267c478bd9Sstevel@tonic-gate bp->b_edev = devvp->v_rdev; 15277c478bd9Sstevel@tonic-gate bp->b_dev = cmpdev(devvp->v_rdev); 1528f127cb91Sfrankho bp->b_blkno = bn + btodt(xferoffset - lbnoff); 152924e9c58bSelowe bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff; 15307c478bd9Sstevel@tonic-gate bp->b_file = vp; 15317c478bd9Sstevel@tonic-gate bp->b_offset = (offset_t)(off + pgoff); 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate (void) bdev_strategy(bp); 15347c478bd9Sstevel@tonic-gate 15357c478bd9Sstevel@tonic-gate lwp_stat_update(LWP_STAT_INBLK, 1); 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate if (err == 0) 15387c478bd9Sstevel@tonic-gate err = biowait(bp); 15397c478bd9Sstevel@tonic-gate else 15407c478bd9Sstevel@tonic-gate (void) biowait(bp); 15417c478bd9Sstevel@tonic-gate pageio_done(bp); 15427c478bd9Sstevel@tonic-gate if (err) 15437c478bd9Sstevel@tonic-gate goto out; 15447c478bd9Sstevel@tonic-gate } 15457c478bd9Sstevel@tonic-gate if (pgoff < PAGESIZE) { 15467c478bd9Sstevel@tonic-gate pagezero(pp->p_prev, pgoff, PAGESIZE - pgoff); 15477c478bd9Sstevel@tonic-gate } 15487c478bd9Sstevel@tonic-gate pvn_plist_init(pp, pl, plsz, off, io_len, rw); 15497c478bd9Sstevel@tonic-gate } 15507c478bd9Sstevel@tonic-gate out: 15517c478bd9Sstevel@tonic-gate if (err) { 15527c478bd9Sstevel@tonic-gate if (pp != NULL) 15537c478bd9Sstevel@tonic-gate pvn_read_done(pp, B_ERROR); 15547c478bd9Sstevel@tonic-gate return (err); 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate if (pagefound) { 15587c478bd9Sstevel@tonic-gate /* 15597c478bd9Sstevel@tonic-gate * Page exists in the cache, acquire the "shared" 15607c478bd9Sstevel@tonic-gate * lock. If this fails, go back to reread. 15617c478bd9Sstevel@tonic-gate */ 15627c478bd9Sstevel@tonic-gate if ((pp = page_lookup(vp, off, SE_SHARED)) == NULL) { 15637c478bd9Sstevel@tonic-gate goto reread; 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate pl[0] = pp; 15667c478bd9Sstevel@tonic-gate pl[1] = NULL; 15677c478bd9Sstevel@tonic-gate } 15687c478bd9Sstevel@tonic-gate return (err); 15697c478bd9Sstevel@tonic-gate } 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate /* 15727c478bd9Sstevel@tonic-gate * Return all the pages from [off..off+len] in given file 15737c478bd9Sstevel@tonic-gate */ 1574da6c28aaSamw /* ARGSUSED */ 15757c478bd9Sstevel@tonic-gate static int 15767c478bd9Sstevel@tonic-gate pcfs_getpage( 15777c478bd9Sstevel@tonic-gate struct vnode *vp, 15787c478bd9Sstevel@tonic-gate offset_t off, 15797c478bd9Sstevel@tonic-gate size_t len, 15807c478bd9Sstevel@tonic-gate uint_t *protp, 15817c478bd9Sstevel@tonic-gate page_t *pl[], 15827c478bd9Sstevel@tonic-gate size_t plsz, 15837c478bd9Sstevel@tonic-gate struct seg *seg, 15847c478bd9Sstevel@tonic-gate caddr_t addr, 15857c478bd9Sstevel@tonic-gate enum seg_rw rw, 1586da6c28aaSamw struct cred *cr, 1587da6c28aaSamw caller_context_t *ct) 15887c478bd9Sstevel@tonic-gate { 15897c478bd9Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 15907c478bd9Sstevel@tonic-gate int err; 15917c478bd9Sstevel@tonic-gate 15927c478bd9Sstevel@tonic-gate PC_DPRINTF0(6, "pcfs_getpage\n"); 15937c478bd9Sstevel@tonic-gate if (err = pc_verify(fsp)) 15947c478bd9Sstevel@tonic-gate return (err); 15957c478bd9Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 15967c478bd9Sstevel@tonic-gate return (ENOSYS); 15977c478bd9Sstevel@tonic-gate ASSERT(off <= UINT32_MAX); 15987c478bd9Sstevel@tonic-gate err = pc_lockfs(fsp, 0, 0); 15997c478bd9Sstevel@tonic-gate if (err) 16007c478bd9Sstevel@tonic-gate return (err); 16017c478bd9Sstevel@tonic-gate if (protp != NULL) 16027c478bd9Sstevel@tonic-gate *protp = PROT_ALL; 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate ASSERT((off & PAGEOFFSET) == 0); 1605*06e6833aSJosef 'Jeff' Sipek err = pvn_getpages(pcfs_getapage, vp, off, len, protp, pl, plsz, 1606*06e6833aSJosef 'Jeff' Sipek seg, addr, rw, cr); 1607*06e6833aSJosef 'Jeff' Sipek 16087c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 16097c478bd9Sstevel@tonic-gate return (err); 16107c478bd9Sstevel@tonic-gate } 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate /* 16147c478bd9Sstevel@tonic-gate * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE} 16157c478bd9Sstevel@tonic-gate * If len == 0, do from off to EOF. 16167c478bd9Sstevel@tonic-gate * 16177c478bd9Sstevel@tonic-gate * The normal cases should be len == 0 & off == 0 (entire vp list), 16187c478bd9Sstevel@tonic-gate * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE 16197c478bd9Sstevel@tonic-gate * (from pageout). 16207c478bd9Sstevel@tonic-gate * 16217c478bd9Sstevel@tonic-gate */ 16227c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 16237c478bd9Sstevel@tonic-gate static int 16247c478bd9Sstevel@tonic-gate pcfs_putpage( 16257c478bd9Sstevel@tonic-gate struct vnode *vp, 16267c478bd9Sstevel@tonic-gate offset_t off, 16277c478bd9Sstevel@tonic-gate size_t len, 16287c478bd9Sstevel@tonic-gate int flags, 1629da6c28aaSamw struct cred *cr, 1630da6c28aaSamw caller_context_t *ct) 16317c478bd9Sstevel@tonic-gate { 16327c478bd9Sstevel@tonic-gate struct pcnode *pcp; 16337c478bd9Sstevel@tonic-gate page_t *pp; 16347c478bd9Sstevel@tonic-gate struct pcfs *fsp; 16357c478bd9Sstevel@tonic-gate u_offset_t io_off; 16367c478bd9Sstevel@tonic-gate size_t io_len; 16377c478bd9Sstevel@tonic-gate offset_t eoff; 16387c478bd9Sstevel@tonic-gate int err; 16397c478bd9Sstevel@tonic-gate 1640264a6e74Sfrankho /* 1641264a6e74Sfrankho * If the filesystem was umounted by force, return immediately. 1642264a6e74Sfrankho */ 1643264a6e74Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 1644264a6e74Sfrankho return (EIO); 1645264a6e74Sfrankho 16467c478bd9Sstevel@tonic-gate PC_DPRINTF1(6, "pcfs_putpage vp=0x%p\n", (void *)vp); 16477c478bd9Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 16487c478bd9Sstevel@tonic-gate return (ENOSYS); 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate if (err = pc_verify(fsp)) 16537c478bd9Sstevel@tonic-gate return (err); 16547c478bd9Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) { 16557c478bd9Sstevel@tonic-gate PC_DPRINTF1(3, "pcfs_putpage NULL vp=0x%p\n", (void *)vp); 16567c478bd9Sstevel@tonic-gate return (EIO); 16577c478bd9Sstevel@tonic-gate } 16589bd42341Sfrankho if (pcp->pc_flags & PC_INVAL) 16599bd42341Sfrankho return (EIO); 16607c478bd9Sstevel@tonic-gate 16617c478bd9Sstevel@tonic-gate if (curproc == proc_pageout) { 16627c478bd9Sstevel@tonic-gate /* 16637c478bd9Sstevel@tonic-gate * XXX - This is a quick hack to avoid blocking 16647c478bd9Sstevel@tonic-gate * pageout. Also to avoid pcfs_getapage deadlocking 16657c478bd9Sstevel@tonic-gate * with putpage when memory is running out, 16667c478bd9Sstevel@tonic-gate * since we only have one global lock and we don't 16677c478bd9Sstevel@tonic-gate * support async putpage. 16687c478bd9Sstevel@tonic-gate * It should be fixed someday. 16697c478bd9Sstevel@tonic-gate * 16707c478bd9Sstevel@tonic-gate * Interestingly, this used to be a test of NOMEMWAIT(). 16717c478bd9Sstevel@tonic-gate * We only ever got here once pcfs started supporting 16727c478bd9Sstevel@tonic-gate * NFS sharing, and then only because the NFS server 16737c478bd9Sstevel@tonic-gate * threads seem to do writes in sched's process context. 16747c478bd9Sstevel@tonic-gate * Since everyone else seems to just care about pageout, 16757c478bd9Sstevel@tonic-gate * the test was changed to look for pageout directly. 16767c478bd9Sstevel@tonic-gate */ 16777c478bd9Sstevel@tonic-gate return (ENOMEM); 16787c478bd9Sstevel@tonic-gate } 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate ASSERT(off <= UINT32_MAX); 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate flags &= ~B_ASYNC; /* XXX should fix this later */ 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate err = pc_lockfs(fsp, 0, 0); 16857c478bd9Sstevel@tonic-gate if (err) 16867c478bd9Sstevel@tonic-gate return (err); 16877c478bd9Sstevel@tonic-gate if (!vn_has_cached_data(vp) || off >= pcp->pc_size) { 16887c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 16897c478bd9Sstevel@tonic-gate return (0); 16907c478bd9Sstevel@tonic-gate } 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate if (len == 0) { 16937c478bd9Sstevel@tonic-gate /* 16947c478bd9Sstevel@tonic-gate * Search the entire vp list for pages >= off 16957c478bd9Sstevel@tonic-gate */ 16967c478bd9Sstevel@tonic-gate err = pvn_vplist_dirty(vp, off, 16977c478bd9Sstevel@tonic-gate pcfs_putapage, flags, cr); 16987c478bd9Sstevel@tonic-gate } else { 16997c478bd9Sstevel@tonic-gate eoff = off + len; 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate for (io_off = off; io_off < eoff && 17027c478bd9Sstevel@tonic-gate io_off < pcp->pc_size; io_off += io_len) { 17037c478bd9Sstevel@tonic-gate /* 17047c478bd9Sstevel@tonic-gate * If we are not invalidating, synchronously 17057c478bd9Sstevel@tonic-gate * freeing or writing pages use the routine 17067c478bd9Sstevel@tonic-gate * page_lookup_nowait() to prevent reclaiming 17077c478bd9Sstevel@tonic-gate * them from the free list. 17087c478bd9Sstevel@tonic-gate */ 17097c478bd9Sstevel@tonic-gate if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) { 17107c478bd9Sstevel@tonic-gate pp = page_lookup(vp, io_off, 17117c478bd9Sstevel@tonic-gate (flags & (B_INVAL | B_FREE)) ? 17127c478bd9Sstevel@tonic-gate SE_EXCL : SE_SHARED); 17137c478bd9Sstevel@tonic-gate } else { 17147c478bd9Sstevel@tonic-gate pp = page_lookup_nowait(vp, io_off, 17157c478bd9Sstevel@tonic-gate (flags & B_FREE) ? SE_EXCL : SE_SHARED); 17167c478bd9Sstevel@tonic-gate } 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate if (pp == NULL || pvn_getdirty(pp, flags) == 0) 17197c478bd9Sstevel@tonic-gate io_len = PAGESIZE; 17207c478bd9Sstevel@tonic-gate else { 17217c478bd9Sstevel@tonic-gate err = pcfs_putapage(vp, pp, &io_off, &io_len, 17227c478bd9Sstevel@tonic-gate flags, cr); 17237c478bd9Sstevel@tonic-gate if (err != 0) 17247c478bd9Sstevel@tonic-gate break; 17257c478bd9Sstevel@tonic-gate /* 17267c478bd9Sstevel@tonic-gate * "io_off" and "io_len" are returned as 17277c478bd9Sstevel@tonic-gate * the range of pages we actually wrote. 17287c478bd9Sstevel@tonic-gate * This allows us to skip ahead more quickly 17297c478bd9Sstevel@tonic-gate * since several pages may've been dealt 17307c478bd9Sstevel@tonic-gate * with by this iteration of the loop. 17317c478bd9Sstevel@tonic-gate */ 17327c478bd9Sstevel@tonic-gate } 17337c478bd9Sstevel@tonic-gate } 17347c478bd9Sstevel@tonic-gate } 17357c478bd9Sstevel@tonic-gate if (err == 0 && (flags & B_INVAL) && 17367c478bd9Sstevel@tonic-gate off == 0 && len == 0 && vn_has_cached_data(vp)) { 17377c478bd9Sstevel@tonic-gate /* 17387c478bd9Sstevel@tonic-gate * If doing "invalidation", make sure that 17397c478bd9Sstevel@tonic-gate * all pages on the vnode list are actually 17407c478bd9Sstevel@tonic-gate * gone. 17417c478bd9Sstevel@tonic-gate */ 17427c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, 17437c478bd9Sstevel@tonic-gate "pcfs_putpage: B_INVAL, pages not gone"); 17447c478bd9Sstevel@tonic-gate } else if (err) { 17457c478bd9Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_putpage err=%d\n", err); 17467c478bd9Sstevel@tonic-gate } 17477c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 17487c478bd9Sstevel@tonic-gate return (err); 17497c478bd9Sstevel@tonic-gate } 17507c478bd9Sstevel@tonic-gate 17517c478bd9Sstevel@tonic-gate /* 17527c478bd9Sstevel@tonic-gate * Write out a single page, possibly klustering adjacent dirty pages. 17537c478bd9Sstevel@tonic-gate */ 17547c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17557c478bd9Sstevel@tonic-gate int 17567c478bd9Sstevel@tonic-gate pcfs_putapage( 17577c478bd9Sstevel@tonic-gate struct vnode *vp, 17587c478bd9Sstevel@tonic-gate page_t *pp, 17597c478bd9Sstevel@tonic-gate u_offset_t *offp, 17607c478bd9Sstevel@tonic-gate size_t *lenp, 17617c478bd9Sstevel@tonic-gate int flags, 17627c478bd9Sstevel@tonic-gate struct cred *cr) 17637c478bd9Sstevel@tonic-gate { 17647c478bd9Sstevel@tonic-gate struct pcnode *pcp; 17657c478bd9Sstevel@tonic-gate struct pcfs *fsp; 17667c478bd9Sstevel@tonic-gate struct vnode *devvp; 17677c478bd9Sstevel@tonic-gate size_t io_len; 17687c478bd9Sstevel@tonic-gate daddr_t bn; 17697c478bd9Sstevel@tonic-gate u_offset_t lbn, lbnoff, xferoffset; 17707c478bd9Sstevel@tonic-gate uint_t pgoff, xfersize; 17717c478bd9Sstevel@tonic-gate int err = 0; 17727c478bd9Sstevel@tonic-gate u_offset_t io_off; 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate pcp = VTOPC(vp); 17757c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 17767c478bd9Sstevel@tonic-gate devvp = fsp->pcfs_devvp; 17777c478bd9Sstevel@tonic-gate 17787c478bd9Sstevel@tonic-gate /* 17797c478bd9Sstevel@tonic-gate * If the modified time on the inode has not already been 17807c478bd9Sstevel@tonic-gate * set elsewhere (e.g. for write/setattr) and this is not 17817c478bd9Sstevel@tonic-gate * a call from msync (B_FORCE) we set the time now. 17827c478bd9Sstevel@tonic-gate * This gives us approximate modified times for mmap'ed files 17837c478bd9Sstevel@tonic-gate * which are modified via stores in the user address space. 17847c478bd9Sstevel@tonic-gate */ 17857c478bd9Sstevel@tonic-gate if ((pcp->pc_flags & PC_MOD) == 0 || (flags & B_FORCE)) { 17867c478bd9Sstevel@tonic-gate pcp->pc_flags |= PC_MOD; 1787f127cb91Sfrankho pc_mark_mod(fsp, pcp); 17887c478bd9Sstevel@tonic-gate } 17897c478bd9Sstevel@tonic-gate pp = pvn_write_kluster(vp, pp, &io_off, &io_len, pp->p_offset, 17907c478bd9Sstevel@tonic-gate PAGESIZE, flags); 17917c478bd9Sstevel@tonic-gate 17927c478bd9Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_IRRECOV) { 17937c478bd9Sstevel@tonic-gate goto out; 17947c478bd9Sstevel@tonic-gate } 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate PC_DPRINTF1(7, "pc_putpage writing dirty page off=%llu\n", io_off); 17977c478bd9Sstevel@tonic-gate 17987c478bd9Sstevel@tonic-gate lbn = pc_lblkno(fsp, io_off); 17997c478bd9Sstevel@tonic-gate lbnoff = io_off & ~(fsp->pcfs_clsize - 1); 18007c478bd9Sstevel@tonic-gate xferoffset = io_off & ~(fsp->pcfs_secsize - 1); 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate for (pgoff = 0; pgoff < io_len && xferoffset < pcp->pc_size; 18037c478bd9Sstevel@tonic-gate pgoff += xfersize, 18047c478bd9Sstevel@tonic-gate lbn += howmany(xfersize, fsp->pcfs_clsize), 18057c478bd9Sstevel@tonic-gate lbnoff += xfersize, xferoffset += xfersize) { 18067c478bd9Sstevel@tonic-gate 18077c478bd9Sstevel@tonic-gate struct buf *bp; 18087c478bd9Sstevel@tonic-gate int err1; 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate /* 18117c478bd9Sstevel@tonic-gate * write as many contiguous blocks as possible from this page 18127c478bd9Sstevel@tonic-gate */ 18137c478bd9Sstevel@tonic-gate xfersize = io_len - pgoff; 18147c478bd9Sstevel@tonic-gate err1 = pc_bmap(pcp, (daddr_t)lbn, &bn, &xfersize); 18157c478bd9Sstevel@tonic-gate if (err1) { 18167c478bd9Sstevel@tonic-gate err = err1; 18177c478bd9Sstevel@tonic-gate goto out; 18187c478bd9Sstevel@tonic-gate } 18197c478bd9Sstevel@tonic-gate bp = pageio_setup(pp, xfersize, devvp, B_WRITE | flags); 18207c478bd9Sstevel@tonic-gate bp->b_edev = devvp->v_rdev; 18217c478bd9Sstevel@tonic-gate bp->b_dev = cmpdev(devvp->v_rdev); 1822f127cb91Sfrankho bp->b_blkno = bn + btodt(xferoffset - lbnoff); 18237c478bd9Sstevel@tonic-gate bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff; 18247c478bd9Sstevel@tonic-gate bp->b_file = vp; 18257c478bd9Sstevel@tonic-gate bp->b_offset = (offset_t)(io_off + pgoff); 18267c478bd9Sstevel@tonic-gate 18277c478bd9Sstevel@tonic-gate (void) bdev_strategy(bp); 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate lwp_stat_update(LWP_STAT_OUBLK, 1); 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate if (err == 0) 18327c478bd9Sstevel@tonic-gate err = biowait(bp); 18337c478bd9Sstevel@tonic-gate else 18347c478bd9Sstevel@tonic-gate (void) biowait(bp); 18357c478bd9Sstevel@tonic-gate pageio_done(bp); 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate pvn_write_done(pp, ((err) ? B_ERROR : 0) | B_WRITE | flags); 18387c478bd9Sstevel@tonic-gate pp = NULL; 18397c478bd9Sstevel@tonic-gate 18407c478bd9Sstevel@tonic-gate out: 18417c478bd9Sstevel@tonic-gate if ((fsp->pcfs_flags & PCFS_IRRECOV) && pp != NULL) { 18427c478bd9Sstevel@tonic-gate pvn_write_done(pp, B_WRITE | flags); 18437c478bd9Sstevel@tonic-gate } else if (err != 0 && pp != NULL) { 18447c478bd9Sstevel@tonic-gate pvn_write_done(pp, B_ERROR | B_WRITE | flags); 18457c478bd9Sstevel@tonic-gate } 18467c478bd9Sstevel@tonic-gate 18477c478bd9Sstevel@tonic-gate if (offp) 18487c478bd9Sstevel@tonic-gate *offp = io_off; 18497c478bd9Sstevel@tonic-gate if (lenp) 18507c478bd9Sstevel@tonic-gate *lenp = io_len; 18517c478bd9Sstevel@tonic-gate PC_DPRINTF4(4, "pcfs_putapage: vp=%p pp=%p off=%lld len=%lu\n", 18527c478bd9Sstevel@tonic-gate (void *)vp, (void *)pp, io_off, io_len); 18537c478bd9Sstevel@tonic-gate if (err) { 18547c478bd9Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_putapage err=%d", err); 18557c478bd9Sstevel@tonic-gate } 18567c478bd9Sstevel@tonic-gate return (err); 18577c478bd9Sstevel@tonic-gate } 18587c478bd9Sstevel@tonic-gate 18597c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 18607c478bd9Sstevel@tonic-gate static int 18617c478bd9Sstevel@tonic-gate pcfs_map( 18627c478bd9Sstevel@tonic-gate struct vnode *vp, 18637c478bd9Sstevel@tonic-gate offset_t off, 18647c478bd9Sstevel@tonic-gate struct as *as, 18657c478bd9Sstevel@tonic-gate caddr_t *addrp, 18667c478bd9Sstevel@tonic-gate size_t len, 18677c478bd9Sstevel@tonic-gate uchar_t prot, 18687c478bd9Sstevel@tonic-gate uchar_t maxprot, 18697c478bd9Sstevel@tonic-gate uint_t flags, 1870da6c28aaSamw struct cred *cr, 1871da6c28aaSamw caller_context_t *ct) 18727c478bd9Sstevel@tonic-gate { 18737c478bd9Sstevel@tonic-gate struct segvn_crargs vn_a; 18747c478bd9Sstevel@tonic-gate int error; 18757c478bd9Sstevel@tonic-gate 18767c478bd9Sstevel@tonic-gate PC_DPRINTF0(6, "pcfs_map\n"); 18777c478bd9Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 18787c478bd9Sstevel@tonic-gate return (ENOSYS); 18797c478bd9Sstevel@tonic-gate 18807c478bd9Sstevel@tonic-gate if (off > UINT32_MAX || off + len > UINT32_MAX) 18817c478bd9Sstevel@tonic-gate return (ENXIO); 18827c478bd9Sstevel@tonic-gate 18837c478bd9Sstevel@tonic-gate as_rangelock(as); 188460946fe0Smec error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags); 188560946fe0Smec if (error != 0) { 18867c478bd9Sstevel@tonic-gate as_rangeunlock(as); 188760946fe0Smec return (error); 18887c478bd9Sstevel@tonic-gate } 18897c478bd9Sstevel@tonic-gate 18907c478bd9Sstevel@tonic-gate vn_a.vp = vp; 18917c478bd9Sstevel@tonic-gate vn_a.offset = off; 18927c478bd9Sstevel@tonic-gate vn_a.type = flags & MAP_TYPE; 18937c478bd9Sstevel@tonic-gate vn_a.prot = prot; 18947c478bd9Sstevel@tonic-gate vn_a.maxprot = maxprot; 18957c478bd9Sstevel@tonic-gate vn_a.flags = flags & ~MAP_TYPE; 18967c478bd9Sstevel@tonic-gate vn_a.cred = cr; 18977c478bd9Sstevel@tonic-gate vn_a.amp = NULL; 18987c478bd9Sstevel@tonic-gate vn_a.szc = 0; 18997c478bd9Sstevel@tonic-gate vn_a.lgrp_mem_policy_flags = 0; 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate error = as_map(as, *addrp, len, segvn_create, &vn_a); 19027c478bd9Sstevel@tonic-gate as_rangeunlock(as); 19037c478bd9Sstevel@tonic-gate return (error); 19047c478bd9Sstevel@tonic-gate } 19057c478bd9Sstevel@tonic-gate 19067c478bd9Sstevel@tonic-gate /* ARGSUSED */ 19077c478bd9Sstevel@tonic-gate static int 19087c478bd9Sstevel@tonic-gate pcfs_seek( 19097c478bd9Sstevel@tonic-gate struct vnode *vp, 19107c478bd9Sstevel@tonic-gate offset_t ooff, 1911da6c28aaSamw offset_t *noffp, 1912da6c28aaSamw caller_context_t *ct) 19137c478bd9Sstevel@tonic-gate { 19147c478bd9Sstevel@tonic-gate if (*noffp < 0) 19157c478bd9Sstevel@tonic-gate return (EINVAL); 19167c478bd9Sstevel@tonic-gate else if (*noffp > MAXOFFSET_T) 19177c478bd9Sstevel@tonic-gate return (EINVAL); 19187c478bd9Sstevel@tonic-gate else 19197c478bd9Sstevel@tonic-gate return (0); 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate /* ARGSUSED */ 19237c478bd9Sstevel@tonic-gate static int 19247c478bd9Sstevel@tonic-gate pcfs_addmap( 19257c478bd9Sstevel@tonic-gate struct vnode *vp, 19267c478bd9Sstevel@tonic-gate offset_t off, 19277c478bd9Sstevel@tonic-gate struct as *as, 19287c478bd9Sstevel@tonic-gate caddr_t addr, 19297c478bd9Sstevel@tonic-gate size_t len, 19307c478bd9Sstevel@tonic-gate uchar_t prot, 19317c478bd9Sstevel@tonic-gate uchar_t maxprot, 19327c478bd9Sstevel@tonic-gate uint_t flags, 1933da6c28aaSamw struct cred *cr, 1934da6c28aaSamw caller_context_t *ct) 19357c478bd9Sstevel@tonic-gate { 19367c478bd9Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 19377c478bd9Sstevel@tonic-gate return (ENOSYS); 19387c478bd9Sstevel@tonic-gate return (0); 19397c478bd9Sstevel@tonic-gate } 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19427c478bd9Sstevel@tonic-gate static int 19437c478bd9Sstevel@tonic-gate pcfs_delmap( 19447c478bd9Sstevel@tonic-gate struct vnode *vp, 19457c478bd9Sstevel@tonic-gate offset_t off, 19467c478bd9Sstevel@tonic-gate struct as *as, 19477c478bd9Sstevel@tonic-gate caddr_t addr, 19487c478bd9Sstevel@tonic-gate size_t len, 19497c478bd9Sstevel@tonic-gate uint_t prot, 19507c478bd9Sstevel@tonic-gate uint_t maxprot, 19517c478bd9Sstevel@tonic-gate uint_t flags, 1952da6c28aaSamw struct cred *cr, 1953da6c28aaSamw caller_context_t *ct) 19547c478bd9Sstevel@tonic-gate { 19557c478bd9Sstevel@tonic-gate if (vp->v_flag & VNOMAP) 19567c478bd9Sstevel@tonic-gate return (ENOSYS); 19577c478bd9Sstevel@tonic-gate return (0); 19587c478bd9Sstevel@tonic-gate } 19597c478bd9Sstevel@tonic-gate 19607c478bd9Sstevel@tonic-gate /* 19617c478bd9Sstevel@tonic-gate * POSIX pathconf() support. 19627c478bd9Sstevel@tonic-gate */ 19637c478bd9Sstevel@tonic-gate /* ARGSUSED */ 19647c478bd9Sstevel@tonic-gate static int 19657c478bd9Sstevel@tonic-gate pcfs_pathconf( 19667c478bd9Sstevel@tonic-gate struct vnode *vp, 19677c478bd9Sstevel@tonic-gate int cmd, 19687c478bd9Sstevel@tonic-gate ulong_t *valp, 1969da6c28aaSamw struct cred *cr, 1970da6c28aaSamw caller_context_t *ct) 19717c478bd9Sstevel@tonic-gate { 19727c478bd9Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 19737c478bd9Sstevel@tonic-gate 19747c478bd9Sstevel@tonic-gate switch (cmd) { 19757c478bd9Sstevel@tonic-gate case _PC_LINK_MAX: 1976e8f766d8Sbatschul *valp = 1; 1977e8f766d8Sbatschul return (0); 19787c478bd9Sstevel@tonic-gate 1979e8f766d8Sbatschul case _PC_CASE_BEHAVIOR: 1980e8f766d8Sbatschul return (EINVAL); 19817c478bd9Sstevel@tonic-gate 19827c478bd9Sstevel@tonic-gate case _PC_FILESIZEBITS: 19837c478bd9Sstevel@tonic-gate /* 19847c478bd9Sstevel@tonic-gate * Both FAT16 and FAT32 support 4GB - 1 byte for file size. 19857c478bd9Sstevel@tonic-gate * FAT12 can only go up to the maximum filesystem capacity 19867c478bd9Sstevel@tonic-gate * which is ~509MB. 19877c478bd9Sstevel@tonic-gate */ 1988e8f766d8Sbatschul *valp = IS_FAT12(fsp) ? 30 : 33; 1989e8f766d8Sbatschul return (0); 1990e8f766d8Sbatschul 19913b862e9aSRoger A. Faulkner case _PC_TIMESTAMP_RESOLUTION: 19923b862e9aSRoger A. Faulkner /* 19933b862e9aSRoger A. Faulkner * PCFS keeps track of modification times, it its own 19943b862e9aSRoger A. Faulkner * internal format, to a resolution of 2 seconds. 19953b862e9aSRoger A. Faulkner * Since 2000 million is representable in an int32_t 19963b862e9aSRoger A. Faulkner * without overflow (or becoming negative), we allow 19973b862e9aSRoger A. Faulkner * this value to be returned. 19983b862e9aSRoger A. Faulkner */ 19993b862e9aSRoger A. Faulkner *valp = 2000000000L; 20003b862e9aSRoger A. Faulkner return (0); 20013b862e9aSRoger A. Faulkner 20027c478bd9Sstevel@tonic-gate default: 2003e8f766d8Sbatschul return (fs_pathconf(vp, cmd, valp, cr, ct)); 20047c478bd9Sstevel@tonic-gate } 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate } 20077c478bd9Sstevel@tonic-gate 20087c478bd9Sstevel@tonic-gate /* ARGSUSED */ 20097c478bd9Sstevel@tonic-gate static int 20107c478bd9Sstevel@tonic-gate pcfs_space( 20117c478bd9Sstevel@tonic-gate struct vnode *vp, 20127c478bd9Sstevel@tonic-gate int cmd, 20137c478bd9Sstevel@tonic-gate struct flock64 *bfp, 20147c478bd9Sstevel@tonic-gate int flag, 20157c478bd9Sstevel@tonic-gate offset_t offset, 20167c478bd9Sstevel@tonic-gate cred_t *cr, 20177c478bd9Sstevel@tonic-gate caller_context_t *ct) 20187c478bd9Sstevel@tonic-gate { 20197c478bd9Sstevel@tonic-gate struct vattr vattr; 20207c478bd9Sstevel@tonic-gate int error; 20217c478bd9Sstevel@tonic-gate 20227c478bd9Sstevel@tonic-gate if (cmd != F_FREESP) 20237c478bd9Sstevel@tonic-gate return (EINVAL); 20247c478bd9Sstevel@tonic-gate 20257c478bd9Sstevel@tonic-gate if ((error = convoff(vp, bfp, 0, offset)) == 0) { 20267c478bd9Sstevel@tonic-gate if ((bfp->l_start > UINT32_MAX) || (bfp->l_len > UINT32_MAX)) 20277c478bd9Sstevel@tonic-gate return (EFBIG); 20287c478bd9Sstevel@tonic-gate /* 20297c478bd9Sstevel@tonic-gate * we only support the special case of l_len == 0, 20307c478bd9Sstevel@tonic-gate * meaning free to end of file at this moment. 20317c478bd9Sstevel@tonic-gate */ 20327c478bd9Sstevel@tonic-gate if (bfp->l_len != 0) 20337c478bd9Sstevel@tonic-gate return (EINVAL); 20347c478bd9Sstevel@tonic-gate vattr.va_mask = AT_SIZE; 20357c478bd9Sstevel@tonic-gate vattr.va_size = bfp->l_start; 2036da6c28aaSamw error = VOP_SETATTR(vp, (vattr_t *)&vattr, 0, cr, ct); 20377c478bd9Sstevel@tonic-gate } 20387c478bd9Sstevel@tonic-gate return (error); 20397c478bd9Sstevel@tonic-gate } 20407c478bd9Sstevel@tonic-gate 20417c478bd9Sstevel@tonic-gate /* 20427c478bd9Sstevel@tonic-gate * Break up 'len' chars from 'buf' into a long file name chunk. 20437c478bd9Sstevel@tonic-gate * Pad with '0xff' to make Norton Disk Doctor and Microsoft ScanDisk happy. 20447c478bd9Sstevel@tonic-gate */ 20457c478bd9Sstevel@tonic-gate void 20467c478bd9Sstevel@tonic-gate set_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int len) 20477c478bd9Sstevel@tonic-gate { 20487c478bd9Sstevel@tonic-gate int i; 20497c478bd9Sstevel@tonic-gate 20504a37d755Sksn ASSERT(buf != NULL); 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2) { 20537c478bd9Sstevel@tonic-gate if (len > 0) { 20544a37d755Sksn ep->pcdl_firstfilename[i] = *buf++; 20554a37d755Sksn ep->pcdl_firstfilename[i + 1] = *buf++; 20564a37d755Sksn len -= 2; 20577c478bd9Sstevel@tonic-gate } else { 20587c478bd9Sstevel@tonic-gate ep->pcdl_firstfilename[i] = (uchar_t)0xff; 20597c478bd9Sstevel@tonic-gate ep->pcdl_firstfilename[i + 1] = (uchar_t)0xff; 20607c478bd9Sstevel@tonic-gate } 20617c478bd9Sstevel@tonic-gate } 20627c478bd9Sstevel@tonic-gate 20637c478bd9Sstevel@tonic-gate for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2) { 20647c478bd9Sstevel@tonic-gate if (len > 0) { 20654a37d755Sksn ep->pcdl_secondfilename[i] = *buf++; 20664a37d755Sksn ep->pcdl_secondfilename[i + 1] = *buf++; 20674a37d755Sksn len -= 2; 20687c478bd9Sstevel@tonic-gate } else { 20697c478bd9Sstevel@tonic-gate ep->pcdl_secondfilename[i] = (uchar_t)0xff; 20707c478bd9Sstevel@tonic-gate ep->pcdl_secondfilename[i + 1] = (uchar_t)0xff; 20717c478bd9Sstevel@tonic-gate } 20727c478bd9Sstevel@tonic-gate } 20737c478bd9Sstevel@tonic-gate for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2) { 20747c478bd9Sstevel@tonic-gate if (len > 0) { 20754a37d755Sksn ep->pcdl_thirdfilename[i] = *buf++; 20764a37d755Sksn ep->pcdl_thirdfilename[i + 1] = *buf++; 20774a37d755Sksn len -= 2; 20787c478bd9Sstevel@tonic-gate } else { 20797c478bd9Sstevel@tonic-gate ep->pcdl_thirdfilename[i] = (uchar_t)0xff; 20807c478bd9Sstevel@tonic-gate ep->pcdl_thirdfilename[i + 1] = (uchar_t)0xff; 20817c478bd9Sstevel@tonic-gate } 20827c478bd9Sstevel@tonic-gate } 20837c478bd9Sstevel@tonic-gate } 20847c478bd9Sstevel@tonic-gate 20857c478bd9Sstevel@tonic-gate /* 20867c478bd9Sstevel@tonic-gate * Extract the characters from the long filename chunk into 'buf'. 20877c478bd9Sstevel@tonic-gate * Return the number of characters extracted. 20887c478bd9Sstevel@tonic-gate */ 20897c478bd9Sstevel@tonic-gate static int 20905f079001SOwen Roberts get_long_fn_chunk(struct pcdir_lfn *ep, char *buf) 20917c478bd9Sstevel@tonic-gate { 20927c478bd9Sstevel@tonic-gate char *tmp = buf; 20937c478bd9Sstevel@tonic-gate int i; 20947c478bd9Sstevel@tonic-gate 20954a37d755Sksn /* Copy all the names, no filtering now */ 20964a37d755Sksn 20974a37d755Sksn for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2, tmp += 2) { 20987c478bd9Sstevel@tonic-gate *tmp = ep->pcdl_firstfilename[i]; 20994a37d755Sksn *(tmp + 1) = ep->pcdl_firstfilename[i + 1]; 21004a37d755Sksn 21014a37d755Sksn if ((*tmp == '\0') && (*(tmp+1) == '\0')) 21027c478bd9Sstevel@tonic-gate return (tmp - buf); 21034a37d755Sksn } 21044a37d755Sksn for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2, tmp += 2) { 21057c478bd9Sstevel@tonic-gate *tmp = ep->pcdl_secondfilename[i]; 21064a37d755Sksn *(tmp + 1) = ep->pcdl_secondfilename[i + 1]; 21074a37d755Sksn 21084a37d755Sksn if ((*tmp == '\0') && (*(tmp+1) == '\0')) 21097c478bd9Sstevel@tonic-gate return (tmp - buf); 21104a37d755Sksn } 21114a37d755Sksn for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2, tmp += 2) { 21127c478bd9Sstevel@tonic-gate *tmp = ep->pcdl_thirdfilename[i]; 21134a37d755Sksn *(tmp + 1) = ep->pcdl_thirdfilename[i + 1]; 21144a37d755Sksn 21154a37d755Sksn if ((*tmp == '\0') && (*(tmp+1) == '\0')) 21167c478bd9Sstevel@tonic-gate return (tmp - buf); 21174a37d755Sksn } 21187c478bd9Sstevel@tonic-gate return (tmp - buf); 21197c478bd9Sstevel@tonic-gate } 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate 21227c478bd9Sstevel@tonic-gate /* 21237c478bd9Sstevel@tonic-gate * Checksum the passed in short filename. 21247c478bd9Sstevel@tonic-gate * This is used to validate each component of the long name to make 21257c478bd9Sstevel@tonic-gate * sure the long name is valid (it hasn't been "detached" from the 21267c478bd9Sstevel@tonic-gate * short filename). This algorithm was found in FreeBSD. 21277c478bd9Sstevel@tonic-gate * (sys/fs/msdosfs/msdosfs_conv.c:winChksum(), Wolfgang Solfrank) 21287c478bd9Sstevel@tonic-gate */ 21297c478bd9Sstevel@tonic-gate 21307c478bd9Sstevel@tonic-gate uchar_t 21317c478bd9Sstevel@tonic-gate pc_checksum_long_fn(char *name, char *ext) 21327c478bd9Sstevel@tonic-gate { 21337c478bd9Sstevel@tonic-gate uchar_t c; 21347c478bd9Sstevel@tonic-gate char b[11]; 21357c478bd9Sstevel@tonic-gate 21367c478bd9Sstevel@tonic-gate bcopy(name, b, 8); 21377c478bd9Sstevel@tonic-gate bcopy(ext, b+8, 3); 21387c478bd9Sstevel@tonic-gate 21397c478bd9Sstevel@tonic-gate c = b[0]; 21407c478bd9Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[1]; 21417c478bd9Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[2]; 21427c478bd9Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[3]; 21437c478bd9Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[4]; 21447c478bd9Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[5]; 21457c478bd9Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[6]; 21467c478bd9Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[7]; 21477c478bd9Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[8]; 21487c478bd9Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[9]; 21497c478bd9Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[10]; 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate return (c); 21527c478bd9Sstevel@tonic-gate } 21537c478bd9Sstevel@tonic-gate 21547c478bd9Sstevel@tonic-gate /* 21557c478bd9Sstevel@tonic-gate * Read a chunk of long filename entries into 'namep'. 21567c478bd9Sstevel@tonic-gate * Return with offset pointing to short entry (on success), or next 21577c478bd9Sstevel@tonic-gate * entry to read (if this wasn't a valid lfn really). 21587c478bd9Sstevel@tonic-gate * Uses the passed-in buffer if it can, otherwise kmem_allocs() room for 21597c478bd9Sstevel@tonic-gate * a long filename. 21607c478bd9Sstevel@tonic-gate * 21617c478bd9Sstevel@tonic-gate * Can also be called with a NULL namep, in which case it just returns 21627c478bd9Sstevel@tonic-gate * whether this was really a valid long filename and consumes it 21637c478bd9Sstevel@tonic-gate * (used by pc_dirempty()). 21647c478bd9Sstevel@tonic-gate */ 21657c478bd9Sstevel@tonic-gate int 21667c478bd9Sstevel@tonic-gate pc_extract_long_fn(struct pcnode *pcp, char *namep, 21677c478bd9Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp) 21687c478bd9Sstevel@tonic-gate { 21697c478bd9Sstevel@tonic-gate struct pcdir *ep = *epp; 21707c478bd9Sstevel@tonic-gate struct pcdir_lfn *lep = (struct pcdir_lfn *)ep; 21717c478bd9Sstevel@tonic-gate struct vnode *dvp = PCTOV(pcp); 21727c478bd9Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 21737c478bd9Sstevel@tonic-gate char *lfn; 21747c478bd9Sstevel@tonic-gate char *lfn_base; 21757c478bd9Sstevel@tonic-gate int boff; 21767c478bd9Sstevel@tonic-gate int i, cs; 21774a37d755Sksn char *buf; 21787c478bd9Sstevel@tonic-gate uchar_t cksum; 21797c478bd9Sstevel@tonic-gate int detached = 0; 21807c478bd9Sstevel@tonic-gate int error = 0; 21817c478bd9Sstevel@tonic-gate int foldcase; 21824a37d755Sksn int count = 0; 21834a37d755Sksn size_t u16l = 0, u8l = 0; 21845f079001SOwen Roberts char *outbuf; 21855f079001SOwen Roberts size_t ret, inlen, outlen; 21867c478bd9Sstevel@tonic-gate 21877c478bd9Sstevel@tonic-gate foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE); 21884a37d755Sksn lfn_base = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP); 21894a37d755Sksn lfn = lfn_base + PCMAXNAM_UTF16 - sizeof (uint16_t); 21907c478bd9Sstevel@tonic-gate *lfn = '\0'; 21914a37d755Sksn *(lfn + 1) = '\0'; 21927c478bd9Sstevel@tonic-gate cksum = lep->pcdl_checksum; 21937c478bd9Sstevel@tonic-gate 21944a37d755Sksn buf = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP); 21957c478bd9Sstevel@tonic-gate for (i = (lep->pcdl_ordinal & ~0xc0); i > 0; i--) { 21967c478bd9Sstevel@tonic-gate /* read next block if necessary */ 21977c478bd9Sstevel@tonic-gate boff = pc_blkoff(fsp, *offset); 21987c478bd9Sstevel@tonic-gate if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) { 21997c478bd9Sstevel@tonic-gate if (*bp != NULL) { 22007c478bd9Sstevel@tonic-gate brelse(*bp); 22017c478bd9Sstevel@tonic-gate *bp = NULL; 22027c478bd9Sstevel@tonic-gate } 22037c478bd9Sstevel@tonic-gate error = pc_blkatoff(pcp, *offset, bp, &ep); 22047c478bd9Sstevel@tonic-gate if (error) { 22054a37d755Sksn kmem_free(lfn_base, PCMAXNAM_UTF16); 22064a37d755Sksn kmem_free(buf, PCMAXNAM_UTF16); 22077c478bd9Sstevel@tonic-gate return (error); 22087c478bd9Sstevel@tonic-gate } 22097c478bd9Sstevel@tonic-gate lep = (struct pcdir_lfn *)ep; 22107c478bd9Sstevel@tonic-gate } 22117c478bd9Sstevel@tonic-gate /* can this happen? Bad fs? */ 22127c478bd9Sstevel@tonic-gate if (!PCDL_IS_LFN((struct pcdir *)lep)) { 22137c478bd9Sstevel@tonic-gate detached = 1; 22147c478bd9Sstevel@tonic-gate break; 22157c478bd9Sstevel@tonic-gate } 22167c478bd9Sstevel@tonic-gate if (cksum != lep->pcdl_checksum) 22177c478bd9Sstevel@tonic-gate detached = 1; 22187c478bd9Sstevel@tonic-gate /* process current entry */ 22195f079001SOwen Roberts cs = get_long_fn_chunk(lep, buf); 22204a37d755Sksn count += cs; 22217c478bd9Sstevel@tonic-gate for (; cs > 0; cs--) { 22227c478bd9Sstevel@tonic-gate /* see if we underflow */ 22237c478bd9Sstevel@tonic-gate if (lfn >= lfn_base) 22247c478bd9Sstevel@tonic-gate *--lfn = buf[cs - 1]; 22257c478bd9Sstevel@tonic-gate else 22267c478bd9Sstevel@tonic-gate detached = 1; 22277c478bd9Sstevel@tonic-gate } 22287c478bd9Sstevel@tonic-gate lep++; 22297c478bd9Sstevel@tonic-gate *offset += sizeof (struct pcdir); 22307c478bd9Sstevel@tonic-gate } 22314a37d755Sksn kmem_free(buf, PCMAXNAM_UTF16); 22327c478bd9Sstevel@tonic-gate /* read next block if necessary */ 22337c478bd9Sstevel@tonic-gate boff = pc_blkoff(fsp, *offset); 22347c478bd9Sstevel@tonic-gate ep = (struct pcdir *)lep; 22357c478bd9Sstevel@tonic-gate if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) { 22367c478bd9Sstevel@tonic-gate if (*bp != NULL) { 22377c478bd9Sstevel@tonic-gate brelse(*bp); 22387c478bd9Sstevel@tonic-gate *bp = NULL; 22397c478bd9Sstevel@tonic-gate } 22407c478bd9Sstevel@tonic-gate error = pc_blkatoff(pcp, *offset, bp, &ep); 22417c478bd9Sstevel@tonic-gate if (error) { 22424a37d755Sksn kmem_free(lfn_base, PCMAXNAM_UTF16); 22437c478bd9Sstevel@tonic-gate return (error); 22447c478bd9Sstevel@tonic-gate } 22457c478bd9Sstevel@tonic-gate } 22467c478bd9Sstevel@tonic-gate /* should be on the short one */ 22477c478bd9Sstevel@tonic-gate if (PCDL_IS_LFN(ep) || ((ep->pcd_filename[0] == PCD_UNUSED) || 22487c478bd9Sstevel@tonic-gate (ep->pcd_filename[0] == PCD_ERASED))) { 22497c478bd9Sstevel@tonic-gate detached = 1; 22507c478bd9Sstevel@tonic-gate } 22517c478bd9Sstevel@tonic-gate if (detached || 22527c478bd9Sstevel@tonic-gate (cksum != pc_checksum_long_fn(ep->pcd_filename, ep->pcd_ext)) || 22534a37d755Sksn !pc_valid_long_fn(lfn, 0)) { 22547c478bd9Sstevel@tonic-gate /* 22557c478bd9Sstevel@tonic-gate * process current entry again. This may end up another lfn 22567c478bd9Sstevel@tonic-gate * or a short name. 22577c478bd9Sstevel@tonic-gate */ 22587c478bd9Sstevel@tonic-gate *epp = ep; 22594a37d755Sksn kmem_free(lfn_base, PCMAXNAM_UTF16); 22607c478bd9Sstevel@tonic-gate return (EINVAL); 22617c478bd9Sstevel@tonic-gate } 22627c478bd9Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) { 22637c478bd9Sstevel@tonic-gate /* 22647c478bd9Sstevel@tonic-gate * Don't display label because it may contain 22657c478bd9Sstevel@tonic-gate * funny characters. 22667c478bd9Sstevel@tonic-gate */ 22677c478bd9Sstevel@tonic-gate *offset += sizeof (struct pcdir); 22687c478bd9Sstevel@tonic-gate ep++; 22697c478bd9Sstevel@tonic-gate *epp = ep; 22704a37d755Sksn kmem_free(lfn_base, PCMAXNAM_UTF16); 22717c478bd9Sstevel@tonic-gate return (EINVAL); 22727c478bd9Sstevel@tonic-gate } 22737c478bd9Sstevel@tonic-gate if (namep) { 22744a37d755Sksn u16l = count / 2; 22754a37d755Sksn u8l = PCMAXNAMLEN; 22764a37d755Sksn error = uconv_u16tou8((const uint16_t *)lfn, &u16l, 22774a37d755Sksn (uchar_t *)namep, &u8l, UCONV_IN_LITTLE_ENDIAN); 22784a37d755Sksn /* 22794a37d755Sksn * uconv_u16tou8() will catch conversion errors including 22804a37d755Sksn * the case where there is not enough room to write the 22814a37d755Sksn * converted result and the u8l will never go over the given 22824a37d755Sksn * PCMAXNAMLEN. 22834a37d755Sksn */ 22844a37d755Sksn if (error != 0) { 22854a37d755Sksn kmem_free(lfn_base, PCMAXNAM_UTF16); 22864a37d755Sksn return (EINVAL); 22877c478bd9Sstevel@tonic-gate } 22884a37d755Sksn namep[u8l] = '\0'; 22895f079001SOwen Roberts if (foldcase) { 22905f079001SOwen Roberts inlen = strlen(namep); 22915f079001SOwen Roberts outlen = PCMAXNAMLEN; 22925f079001SOwen Roberts outbuf = kmem_alloc(PCMAXNAMLEN + 1, KM_SLEEP); 22935f079001SOwen Roberts ret = u8_textprep_str(namep, &inlen, outbuf, 22945f079001SOwen Roberts &outlen, U8_TEXTPREP_TOLOWER, U8_UNICODE_LATEST, 22955f079001SOwen Roberts &error); 22965f079001SOwen Roberts if (ret == -1) { 22975f079001SOwen Roberts kmem_free(outbuf, PCMAXNAMLEN + 1); 22985f079001SOwen Roberts kmem_free(lfn_base, PCMAXNAM_UTF16); 22995f079001SOwen Roberts return (EINVAL); 23005f079001SOwen Roberts } 23015f079001SOwen Roberts outbuf[PCMAXNAMLEN - outlen] = '\0'; 23025f079001SOwen Roberts (void) strncpy(namep, outbuf, PCMAXNAMLEN + 1); 23035f079001SOwen Roberts kmem_free(outbuf, PCMAXNAMLEN + 1); 23045f079001SOwen Roberts } 23054a37d755Sksn } 23064a37d755Sksn kmem_free(lfn_base, PCMAXNAM_UTF16); 23077c478bd9Sstevel@tonic-gate *epp = ep; 23087c478bd9Sstevel@tonic-gate return (0); 23097c478bd9Sstevel@tonic-gate } 23107c478bd9Sstevel@tonic-gate /* 23117c478bd9Sstevel@tonic-gate * Read a long filename into the pc_dirent structure and copy it out. 23127c478bd9Sstevel@tonic-gate */ 23137c478bd9Sstevel@tonic-gate int 23147c478bd9Sstevel@tonic-gate pc_read_long_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld, 23157c478bd9Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp) 23167c478bd9Sstevel@tonic-gate { 23177c478bd9Sstevel@tonic-gate struct pcdir *ep; 23187c478bd9Sstevel@tonic-gate struct pcnode *pcp = VTOPC(dvp); 23197c478bd9Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 23207c478bd9Sstevel@tonic-gate offset_t uiooffset = uiop->uio_loffset; 23217c478bd9Sstevel@tonic-gate int error = 0; 23227c478bd9Sstevel@tonic-gate offset_t oldoffset; 23237c478bd9Sstevel@tonic-gate 23247c478bd9Sstevel@tonic-gate oldoffset = *offset; 23257c478bd9Sstevel@tonic-gate error = pc_extract_long_fn(pcp, ld->d_name, epp, offset, bp); 23267c478bd9Sstevel@tonic-gate if (error) { 23277c478bd9Sstevel@tonic-gate if (error == EINVAL) { 23287c478bd9Sstevel@tonic-gate uiop->uio_loffset += *offset - oldoffset; 23297c478bd9Sstevel@tonic-gate return (0); 23307c478bd9Sstevel@tonic-gate } else 23317c478bd9Sstevel@tonic-gate return (error); 23327c478bd9Sstevel@tonic-gate } 23337c478bd9Sstevel@tonic-gate 23347c478bd9Sstevel@tonic-gate ep = *epp; 23357c478bd9Sstevel@tonic-gate uiop->uio_loffset += *offset - oldoffset; 23367c478bd9Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name)); 23377c478bd9Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 23387c478bd9Sstevel@tonic-gate uiop->uio_loffset = uiooffset; 23397c478bd9Sstevel@tonic-gate return (ENOSPC); 23407c478bd9Sstevel@tonic-gate } 23417c478bd9Sstevel@tonic-gate ld->d_off = uiop->uio_loffset + sizeof (struct pcdir); 23427c478bd9Sstevel@tonic-gate ld->d_ino = pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno), 23437c478bd9Sstevel@tonic-gate pc_blkoff(fsp, *offset), ep->pcd_attr, 2344f127cb91Sfrankho pc_getstartcluster(fsp, ep), pc_direntpersec(fsp)); 23457c478bd9Sstevel@tonic-gate (void) uiomove((caddr_t)ld, ld->d_reclen, UIO_READ, uiop); 23467c478bd9Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 23477c478bd9Sstevel@tonic-gate *offset += sizeof (struct pcdir); 23487c478bd9Sstevel@tonic-gate ep++; 23497c478bd9Sstevel@tonic-gate *epp = ep; 23507c478bd9Sstevel@tonic-gate return (0); 23517c478bd9Sstevel@tonic-gate } 23527c478bd9Sstevel@tonic-gate 23537c478bd9Sstevel@tonic-gate /* 23547c478bd9Sstevel@tonic-gate * Read a short filename into the pc_dirent structure and copy it out. 23557c478bd9Sstevel@tonic-gate */ 23567c478bd9Sstevel@tonic-gate int 23577c478bd9Sstevel@tonic-gate pc_read_short_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld, 23587c478bd9Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp) 23597c478bd9Sstevel@tonic-gate { 23607c478bd9Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp); 23617c478bd9Sstevel@tonic-gate int boff = pc_blkoff(fsp, *offset); 23627c478bd9Sstevel@tonic-gate struct pcdir *ep = *epp; 23637c478bd9Sstevel@tonic-gate offset_t oldoffset = uiop->uio_loffset; 23647c478bd9Sstevel@tonic-gate int error; 23657c478bd9Sstevel@tonic-gate int foldcase; 23667c478bd9Sstevel@tonic-gate 23677c478bd9Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) { 23687c478bd9Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir); 23697c478bd9Sstevel@tonic-gate *offset += sizeof (struct pcdir); 23707c478bd9Sstevel@tonic-gate ep++; 23717c478bd9Sstevel@tonic-gate *epp = ep; 23727c478bd9Sstevel@tonic-gate return (0); 23737c478bd9Sstevel@tonic-gate } 23747c478bd9Sstevel@tonic-gate ld->d_ino = (ino64_t)pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno), 2375f127cb91Sfrankho boff, ep->pcd_attr, pc_getstartcluster(fsp, ep), 2376f127cb91Sfrankho pc_direntpersec(fsp)); 23777c478bd9Sstevel@tonic-gate foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE); 23787c478bd9Sstevel@tonic-gate error = pc_fname_ext_to_name(&ld->d_name[0], &ep->pcd_filename[0], 23797c478bd9Sstevel@tonic-gate &ep->pcd_ext[0], foldcase); 23807c478bd9Sstevel@tonic-gate if (error == 0) { 23817c478bd9Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name)); 23827c478bd9Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) { 23837c478bd9Sstevel@tonic-gate uiop->uio_loffset = oldoffset; 23847c478bd9Sstevel@tonic-gate return (ENOSPC); 23857c478bd9Sstevel@tonic-gate } 23867c478bd9Sstevel@tonic-gate ld->d_off = (off64_t)(uiop->uio_loffset + 23877c478bd9Sstevel@tonic-gate sizeof (struct pcdir)); 23887c478bd9Sstevel@tonic-gate (void) uiomove((caddr_t)ld, 23897c478bd9Sstevel@tonic-gate ld->d_reclen, UIO_READ, uiop); 23907c478bd9Sstevel@tonic-gate uiop->uio_loffset = ld->d_off; 23917c478bd9Sstevel@tonic-gate } else { 23927c478bd9Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir); 23937c478bd9Sstevel@tonic-gate } 23947c478bd9Sstevel@tonic-gate *offset += sizeof (struct pcdir); 23957c478bd9Sstevel@tonic-gate ep++; 23967c478bd9Sstevel@tonic-gate *epp = ep; 23977c478bd9Sstevel@tonic-gate return (0); 23987c478bd9Sstevel@tonic-gate } 23997c478bd9Sstevel@tonic-gate 2400da6c28aaSamw /* ARGSUSED */ 24017c478bd9Sstevel@tonic-gate static int 2402da6c28aaSamw pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct) 24037c478bd9Sstevel@tonic-gate { 24047c478bd9Sstevel@tonic-gate struct pc_fid *pcfid; 24057c478bd9Sstevel@tonic-gate struct pcnode *pcp; 24067c478bd9Sstevel@tonic-gate struct pcfs *fsp; 24077c478bd9Sstevel@tonic-gate int error; 24087c478bd9Sstevel@tonic-gate 24097c478bd9Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 24107c478bd9Sstevel@tonic-gate if (fsp == NULL) 24117c478bd9Sstevel@tonic-gate return (EIO); 24127c478bd9Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 24137c478bd9Sstevel@tonic-gate if (error) 24147c478bd9Sstevel@tonic-gate return (error); 24159bd42341Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) { 24167c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 24177c478bd9Sstevel@tonic-gate return (EIO); 24187c478bd9Sstevel@tonic-gate } 24197c478bd9Sstevel@tonic-gate if (fidp->fid_len < (sizeof (struct pc_fid) - sizeof (ushort_t))) { 24207c478bd9Sstevel@tonic-gate fidp->fid_len = sizeof (struct pc_fid) - sizeof (ushort_t); 24217c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 24227c478bd9Sstevel@tonic-gate return (ENOSPC); 24237c478bd9Sstevel@tonic-gate } 24247c478bd9Sstevel@tonic-gate 24257c478bd9Sstevel@tonic-gate pcfid = (struct pc_fid *)fidp; 24267c478bd9Sstevel@tonic-gate bzero(pcfid, sizeof (struct pc_fid)); 24277c478bd9Sstevel@tonic-gate pcfid->pcfid_len = sizeof (struct pc_fid) - sizeof (ushort_t); 24287c478bd9Sstevel@tonic-gate if (vp->v_flag & VROOT) { 24297c478bd9Sstevel@tonic-gate pcfid->pcfid_block = 0; 24307c478bd9Sstevel@tonic-gate pcfid->pcfid_offset = 0; 24317c478bd9Sstevel@tonic-gate pcfid->pcfid_ctime = 0; 24327c478bd9Sstevel@tonic-gate } else { 24337c478bd9Sstevel@tonic-gate pcfid->pcfid_block = pcp->pc_eblkno; 24347c478bd9Sstevel@tonic-gate pcfid->pcfid_offset = pcp->pc_eoffset; 24357c478bd9Sstevel@tonic-gate pcfid->pcfid_ctime = pcp->pc_entry.pcd_crtime.pct_time; 24367c478bd9Sstevel@tonic-gate } 24377c478bd9Sstevel@tonic-gate pc_unlockfs(fsp); 24387c478bd9Sstevel@tonic-gate return (0); 24397c478bd9Sstevel@tonic-gate } 2440