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