xref: /onnv-gate/usr/src/uts/common/fs/pcfs/pc_vnops.c (revision 10440:ba48e0ae8d55)
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  */
21*10440SRoger.Faulkner@Sun.COM 
220Sstevel@tonic-gate /*
23*10440SRoger.Faulkner@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <sys/param.h>
280Sstevel@tonic-gate #include <sys/t_lock.h>
290Sstevel@tonic-gate #include <sys/systm.h>
300Sstevel@tonic-gate #include <sys/sysmacros.h>
310Sstevel@tonic-gate #include <sys/user.h>
320Sstevel@tonic-gate #include <sys/buf.h>
330Sstevel@tonic-gate #include <sys/stat.h>
340Sstevel@tonic-gate #include <sys/vfs.h>
353898Srsb #include <sys/vfs_opreg.h>
360Sstevel@tonic-gate #include <sys/dirent.h>
370Sstevel@tonic-gate #include <sys/vnode.h>
380Sstevel@tonic-gate #include <sys/proc.h>
390Sstevel@tonic-gate #include <sys/file.h>
400Sstevel@tonic-gate #include <sys/fcntl.h>
410Sstevel@tonic-gate #include <sys/uio.h>
420Sstevel@tonic-gate #include <sys/fs/pc_label.h>
430Sstevel@tonic-gate #include <sys/fs/pc_fs.h>
440Sstevel@tonic-gate #include <sys/fs/pc_dir.h>
450Sstevel@tonic-gate #include <sys/fs/pc_node.h>
460Sstevel@tonic-gate #include <sys/mman.h>
470Sstevel@tonic-gate #include <sys/pathname.h>
480Sstevel@tonic-gate #include <sys/vmsystm.h>
490Sstevel@tonic-gate #include <sys/cmn_err.h>
500Sstevel@tonic-gate #include <sys/debug.h>
510Sstevel@tonic-gate #include <sys/statvfs.h>
520Sstevel@tonic-gate #include <sys/unistd.h>
530Sstevel@tonic-gate #include <sys/kmem.h>
540Sstevel@tonic-gate #include <sys/conf.h>
550Sstevel@tonic-gate #include <sys/flock.h>
560Sstevel@tonic-gate #include <sys/policy.h>
572720Sfrankho #include <sys/sdt.h>
584723Sksn #include <sys/sunddi.h>
597735SOwen.Roberts@Sun.Com #include <sys/types.h>
607735SOwen.Roberts@Sun.Com #include <sys/errno.h>
610Sstevel@tonic-gate 
620Sstevel@tonic-gate #include <vm/seg.h>
630Sstevel@tonic-gate #include <vm/page.h>
640Sstevel@tonic-gate #include <vm/pvn.h>
650Sstevel@tonic-gate #include <vm/seg_map.h>
660Sstevel@tonic-gate #include <vm/seg_vn.h>
670Sstevel@tonic-gate #include <vm/hat.h>
680Sstevel@tonic-gate #include <vm/as.h>
690Sstevel@tonic-gate #include <vm/seg_kmem.h>
700Sstevel@tonic-gate 
710Sstevel@tonic-gate #include <fs/fs_subr.h>
720Sstevel@tonic-gate 
735331Samw static int pcfs_open(struct vnode **, int, struct cred *, caller_context_t *ct);
745331Samw static int pcfs_close(struct vnode *, int, int, offset_t, struct cred *,
755331Samw 	caller_context_t *ct);
760Sstevel@tonic-gate static int pcfs_read(struct vnode *, struct uio *, int, struct cred *,
775331Samw 	caller_context_t *);
780Sstevel@tonic-gate static int pcfs_write(struct vnode *, struct uio *, int, struct cred *,
795331Samw 	caller_context_t *);
805331Samw static int pcfs_getattr(struct vnode *, struct vattr *, int, struct cred *,
815331Samw 	caller_context_t *ct);
820Sstevel@tonic-gate static int pcfs_setattr(struct vnode *, struct vattr *, int, struct cred *,
830Sstevel@tonic-gate 	caller_context_t *);
845331Samw static int pcfs_access(struct vnode *, int, int, struct cred *,
855331Samw 	caller_context_t *ct);
860Sstevel@tonic-gate static int pcfs_lookup(struct vnode *, char *, struct vnode **,
875331Samw 	struct pathname *, int, struct vnode *, struct cred *,
885331Samw 	caller_context_t *, int *, pathname_t *);
890Sstevel@tonic-gate static int pcfs_create(struct vnode *, char *, struct vattr *,
905331Samw 	enum vcexcl, int mode, struct vnode **, struct cred *, int,
915331Samw 	caller_context_t *, vsecattr_t *);
925331Samw static int pcfs_remove(struct vnode *, char *, struct cred *,
935331Samw 	caller_context_t *, int);
940Sstevel@tonic-gate static int pcfs_rename(struct vnode *, char *, struct vnode *, char *,
955331Samw 	struct cred *, caller_context_t *, int);
960Sstevel@tonic-gate static int pcfs_mkdir(struct vnode *, char *, struct vattr *, struct vnode **,
975331Samw 	struct cred *, caller_context_t *, int, vsecattr_t *);
985331Samw static int pcfs_rmdir(struct vnode *, char *, struct vnode *, struct cred *,
995331Samw 	caller_context_t *, int);
1005331Samw static int pcfs_readdir(struct vnode *, struct uio *, struct cred *, int *,
1015331Samw 	caller_context_t *, int);
1025331Samw static int pcfs_fsync(struct vnode *, int, struct cred *, caller_context_t *);
1035331Samw static void pcfs_inactive(struct vnode *, struct cred *, caller_context_t *);
1045331Samw static int pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *);
1050Sstevel@tonic-gate static int pcfs_space(struct vnode *, int, struct flock64 *, int,
1060Sstevel@tonic-gate 	offset_t, cred_t *, caller_context_t *);
1070Sstevel@tonic-gate static int pcfs_getpage(struct vnode *, offset_t, size_t, uint_t *, page_t *[],
1085331Samw 	size_t, struct seg *, caddr_t, enum seg_rw, struct cred *,
1095331Samw 	caller_context_t *);
1100Sstevel@tonic-gate static int pcfs_getapage(struct vnode *, u_offset_t, size_t, uint_t *,
1110Sstevel@tonic-gate 	page_t *[], size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
1125331Samw static int pcfs_putpage(struct vnode *, offset_t, size_t, int, struct cred *,
1135331Samw 	caller_context_t *);
1140Sstevel@tonic-gate static int pcfs_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t,
1155331Samw 	uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
1160Sstevel@tonic-gate static int pcfs_addmap(struct vnode *, offset_t, struct as *, caddr_t,
1175331Samw 	size_t, uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
1180Sstevel@tonic-gate static int pcfs_delmap(struct vnode *, offset_t, struct as *, caddr_t,
1195331Samw 	size_t, uint_t, uint_t, uint_t, struct cred *, caller_context_t *);
1205331Samw static int pcfs_seek(struct vnode *, offset_t, offset_t *,
1215331Samw 	caller_context_t *);
1225331Samw static int pcfs_pathconf(struct vnode *, int, ulong_t *, struct cred *,
1235331Samw 	caller_context_t *);
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate int pcfs_putapage(struct vnode *, page_t *, u_offset_t *, size_t *, int,
1260Sstevel@tonic-gate 	struct cred *);
1270Sstevel@tonic-gate static int rwpcp(struct pcnode *, struct uio *, enum uio_rw, int);
1287735SOwen.Roberts@Sun.Com static int get_long_fn_chunk(struct pcdir_lfn *ep, char *buf);
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate extern krwlock_t pcnodes_lock;
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate #define	lround(r)	(((r)+sizeof (long long)-1)&(~(sizeof (long long)-1)))
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate  * vnode op vectors for files and directories.
1360Sstevel@tonic-gate  */
1370Sstevel@tonic-gate struct vnodeops *pcfs_fvnodeops;
1380Sstevel@tonic-gate struct vnodeops *pcfs_dvnodeops;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate const fs_operation_def_t pcfs_fvnodeops_template[] = {
1413898Srsb 	VOPNAME_OPEN,		{ .vop_open = pcfs_open },
1423898Srsb 	VOPNAME_CLOSE,		{ .vop_close = pcfs_close },
1433898Srsb 	VOPNAME_READ,		{ .vop_read = pcfs_read },
1443898Srsb 	VOPNAME_WRITE,		{ .vop_write = pcfs_write },
1453898Srsb 	VOPNAME_GETATTR,	{ .vop_getattr = pcfs_getattr },
1463898Srsb 	VOPNAME_SETATTR,	{ .vop_setattr = pcfs_setattr },
1473898Srsb 	VOPNAME_ACCESS,		{ .vop_access = pcfs_access },
1483898Srsb 	VOPNAME_FSYNC,		{ .vop_fsync = pcfs_fsync },
1493898Srsb 	VOPNAME_INACTIVE,	{ .vop_inactive = pcfs_inactive },
1503898Srsb 	VOPNAME_FID,		{ .vop_fid = pcfs_fid },
1513898Srsb 	VOPNAME_SEEK,		{ .vop_seek = pcfs_seek },
1523898Srsb 	VOPNAME_SPACE,		{ .vop_space = pcfs_space },
1533898Srsb 	VOPNAME_GETPAGE,	{ .vop_getpage = pcfs_getpage },
1543898Srsb 	VOPNAME_PUTPAGE,	{ .vop_putpage = pcfs_putpage },
1553898Srsb 	VOPNAME_MAP,		{ .vop_map = pcfs_map },
1563898Srsb 	VOPNAME_ADDMAP,		{ .vop_addmap = pcfs_addmap },
1573898Srsb 	VOPNAME_DELMAP,		{ .vop_delmap = pcfs_delmap },
1583898Srsb 	VOPNAME_PATHCONF,	{ .vop_pathconf = pcfs_pathconf },
1593898Srsb 	VOPNAME_VNEVENT,	{ .vop_vnevent = fs_vnevent_support },
1603898Srsb 	NULL,			NULL
1610Sstevel@tonic-gate };
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate const fs_operation_def_t pcfs_dvnodeops_template[] = {
1643898Srsb 	VOPNAME_OPEN,		{ .vop_open = pcfs_open },
1653898Srsb 	VOPNAME_CLOSE,		{ .vop_close = pcfs_close },
1663898Srsb 	VOPNAME_GETATTR,	{ .vop_getattr = pcfs_getattr },
1673898Srsb 	VOPNAME_SETATTR,	{ .vop_setattr = pcfs_setattr },
1683898Srsb 	VOPNAME_ACCESS,		{ .vop_access = pcfs_access },
1693898Srsb 	VOPNAME_LOOKUP,		{ .vop_lookup = pcfs_lookup },
1703898Srsb 	VOPNAME_CREATE,		{ .vop_create = pcfs_create },
1713898Srsb 	VOPNAME_REMOVE,		{ .vop_remove = pcfs_remove },
1723898Srsb 	VOPNAME_RENAME,		{ .vop_rename = pcfs_rename },
1733898Srsb 	VOPNAME_MKDIR,		{ .vop_mkdir = pcfs_mkdir },
1743898Srsb 	VOPNAME_RMDIR,		{ .vop_rmdir = pcfs_rmdir },
1753898Srsb 	VOPNAME_READDIR,	{ .vop_readdir = pcfs_readdir },
1763898Srsb 	VOPNAME_FSYNC,		{ .vop_fsync = pcfs_fsync },
1773898Srsb 	VOPNAME_INACTIVE,	{ .vop_inactive = pcfs_inactive },
1783898Srsb 	VOPNAME_FID,		{ .vop_fid = pcfs_fid },
1793898Srsb 	VOPNAME_SEEK,		{ .vop_seek = pcfs_seek },
1803898Srsb 	VOPNAME_PATHCONF,	{ .vop_pathconf = pcfs_pathconf },
1813898Srsb 	VOPNAME_VNEVENT,	{ .vop_vnevent = fs_vnevent_support },
1823898Srsb 	NULL,			NULL
1830Sstevel@tonic-gate };
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate /*ARGSUSED*/
1870Sstevel@tonic-gate static int
pcfs_open(struct vnode ** vpp,int flag,struct cred * cr,caller_context_t * ct)1880Sstevel@tonic-gate pcfs_open(
1890Sstevel@tonic-gate 	struct vnode **vpp,
1900Sstevel@tonic-gate 	int flag,
1915331Samw 	struct cred *cr,
1925331Samw 	caller_context_t *ct)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate 	return (0);
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate /*
1980Sstevel@tonic-gate  * files are sync'ed on close to keep floppy up to date
1990Sstevel@tonic-gate  */
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate /*ARGSUSED*/
2020Sstevel@tonic-gate static int
pcfs_close(struct vnode * vp,int flag,int count,offset_t offset,struct cred * cr,caller_context_t * ct)2030Sstevel@tonic-gate pcfs_close(
2040Sstevel@tonic-gate 	struct vnode *vp,
2050Sstevel@tonic-gate 	int flag,
2060Sstevel@tonic-gate 	int count,
2070Sstevel@tonic-gate 	offset_t offset,
2085331Samw 	struct cred *cr,
2095331Samw 	caller_context_t *ct)
2100Sstevel@tonic-gate {
2110Sstevel@tonic-gate 	return (0);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate /*ARGSUSED*/
2150Sstevel@tonic-gate static int
pcfs_read(struct vnode * vp,struct uio * uiop,int ioflag,struct cred * cr,struct caller_context * ct)2160Sstevel@tonic-gate pcfs_read(
2170Sstevel@tonic-gate 	struct vnode *vp,
2180Sstevel@tonic-gate 	struct uio *uiop,
2190Sstevel@tonic-gate 	int ioflag,
2200Sstevel@tonic-gate 	struct cred *cr,
2210Sstevel@tonic-gate 	struct caller_context *ct)
2220Sstevel@tonic-gate {
2230Sstevel@tonic-gate 	struct pcfs *fsp;
2240Sstevel@tonic-gate 	struct pcnode *pcp;
2250Sstevel@tonic-gate 	int error;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
2280Sstevel@tonic-gate 	if (error = pc_verify(fsp))
2290Sstevel@tonic-gate 		return (error);
2300Sstevel@tonic-gate 	error = pc_lockfs(fsp, 0, 0);
2310Sstevel@tonic-gate 	if (error)
2320Sstevel@tonic-gate 		return (error);
2332972Sfrankho 	if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
2340Sstevel@tonic-gate 		pc_unlockfs(fsp);
2350Sstevel@tonic-gate 		return (EIO);
2360Sstevel@tonic-gate 	}
2370Sstevel@tonic-gate 	error = rwpcp(pcp, uiop, UIO_READ, ioflag);
2380Sstevel@tonic-gate 	if ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0) {
2395121Sfrankho 		pc_mark_acc(fsp, pcp);
2400Sstevel@tonic-gate 	}
2410Sstevel@tonic-gate 	pc_unlockfs(fsp);
2420Sstevel@tonic-gate 	if (error) {
2430Sstevel@tonic-gate 		PC_DPRINTF1(1, "pcfs_read: io error = %d\n", error);
2440Sstevel@tonic-gate 	}
2450Sstevel@tonic-gate 	return (error);
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate /*ARGSUSED*/
2490Sstevel@tonic-gate static int
pcfs_write(struct vnode * vp,struct uio * uiop,int ioflag,struct cred * cr,struct caller_context * ct)2500Sstevel@tonic-gate pcfs_write(
2510Sstevel@tonic-gate 	struct vnode *vp,
2520Sstevel@tonic-gate 	struct uio *uiop,
2530Sstevel@tonic-gate 	int ioflag,
2540Sstevel@tonic-gate 	struct cred *cr,
2550Sstevel@tonic-gate 	struct caller_context *ct)
2560Sstevel@tonic-gate {
2570Sstevel@tonic-gate 	struct pcfs *fsp;
2580Sstevel@tonic-gate 	struct pcnode *pcp;
2590Sstevel@tonic-gate 	int error;
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
2620Sstevel@tonic-gate 	if (error = pc_verify(fsp))
2630Sstevel@tonic-gate 		return (error);
2640Sstevel@tonic-gate 	error = pc_lockfs(fsp, 0, 0);
2650Sstevel@tonic-gate 	if (error)
2660Sstevel@tonic-gate 		return (error);
2672972Sfrankho 	if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
2680Sstevel@tonic-gate 		pc_unlockfs(fsp);
2690Sstevel@tonic-gate 		return (EIO);
2700Sstevel@tonic-gate 	}
2710Sstevel@tonic-gate 	if (ioflag & FAPPEND) {
2720Sstevel@tonic-gate 		/*
2730Sstevel@tonic-gate 		 * in append mode start at end of file.
2740Sstevel@tonic-gate 		 */
2750Sstevel@tonic-gate 		uiop->uio_loffset = pcp->pc_size;
2760Sstevel@tonic-gate 	}
2770Sstevel@tonic-gate 	error = rwpcp(pcp, uiop, UIO_WRITE, ioflag);
2780Sstevel@tonic-gate 	pcp->pc_flags |= PC_MOD;
2795121Sfrankho 	pc_mark_mod(fsp, pcp);
2800Sstevel@tonic-gate 	if (ioflag & (FSYNC|FDSYNC))
2810Sstevel@tonic-gate 		(void) pc_nodeupdate(pcp);
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	pc_unlockfs(fsp);
2840Sstevel@tonic-gate 	if (error) {
2850Sstevel@tonic-gate 		PC_DPRINTF1(1, "pcfs_write: io error = %d\n", error);
2860Sstevel@tonic-gate 	}
2870Sstevel@tonic-gate 	return (error);
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate /*
2910Sstevel@tonic-gate  * read or write a vnode
2920Sstevel@tonic-gate  */
2930Sstevel@tonic-gate static int
rwpcp(struct pcnode * pcp,struct uio * uio,enum uio_rw rw,int ioflag)2940Sstevel@tonic-gate rwpcp(
2950Sstevel@tonic-gate 	struct pcnode *pcp,
2960Sstevel@tonic-gate 	struct uio *uio,
2970Sstevel@tonic-gate 	enum uio_rw rw,
2980Sstevel@tonic-gate 	int ioflag)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate 	struct vnode *vp = PCTOV(pcp);
3010Sstevel@tonic-gate 	struct pcfs *fsp;
3020Sstevel@tonic-gate 	daddr_t bn;			/* phys block number */
3030Sstevel@tonic-gate 	int n;
3040Sstevel@tonic-gate 	offset_t off;
3050Sstevel@tonic-gate 	caddr_t base;
3060Sstevel@tonic-gate 	int mapon, pagecreate;
3070Sstevel@tonic-gate 	int newpage;
3080Sstevel@tonic-gate 	int error = 0;
3090Sstevel@tonic-gate 	rlim64_t limit = uio->uio_llimit;
3100Sstevel@tonic-gate 	int oresid = uio->uio_resid;
3110Sstevel@tonic-gate 
3122720Sfrankho 	/*
3132720Sfrankho 	 * If the filesystem was umounted by force, return immediately.
3142720Sfrankho 	 */
3152720Sfrankho 	if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
3162720Sfrankho 		return (EIO);
3172720Sfrankho 
3180Sstevel@tonic-gate 	PC_DPRINTF4(5, "rwpcp pcp=%p off=%lld resid=%ld size=%u\n", (void *)pcp,
3190Sstevel@tonic-gate 	    uio->uio_loffset, uio->uio_resid, pcp->pc_size);
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	ASSERT(rw == UIO_READ || rw == UIO_WRITE);
3220Sstevel@tonic-gate 	ASSERT(vp->v_type == VREG);
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	if (uio->uio_loffset >= UINT32_MAX && rw == UIO_READ) {
3250Sstevel@tonic-gate 		return (0);
3260Sstevel@tonic-gate 	}
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	if (uio->uio_loffset < 0)
3290Sstevel@tonic-gate 		return (EINVAL);
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
3320Sstevel@tonic-gate 		limit = MAXOFFSET_T;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	if (uio->uio_loffset >= limit && rw == UIO_WRITE) {
3350Sstevel@tonic-gate 		proc_t *p = ttoproc(curthread);
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
3380Sstevel@tonic-gate 		(void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], p->p_rctls,
3390Sstevel@tonic-gate 		    p, RCA_UNSAFE_SIGINFO);
3400Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
3410Sstevel@tonic-gate 		return (EFBIG);
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	/* the following condition will occur only for write */
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	if (uio->uio_loffset >= UINT32_MAX)
3470Sstevel@tonic-gate 		return (EFBIG);
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	if (uio->uio_resid == 0)
3500Sstevel@tonic-gate 		return (0);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	if (limit > UINT32_MAX)
3530Sstevel@tonic-gate 		limit = UINT32_MAX;
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
3560Sstevel@tonic-gate 	if (fsp->pcfs_flags & PCFS_IRRECOV)
3570Sstevel@tonic-gate 		return (EIO);
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	do {
3600Sstevel@tonic-gate 		/*
3610Sstevel@tonic-gate 		 * Assignments to "n" in this block may appear
3620Sstevel@tonic-gate 		 * to overflow in some cases.  However, after careful
3630Sstevel@tonic-gate 		 * analysis it was determined that all assignments to
3640Sstevel@tonic-gate 		 * "n" serve only to make "n" smaller.  Since "n"
3650Sstevel@tonic-gate 		 * starts out as no larger than MAXBSIZE, "int" is
3660Sstevel@tonic-gate 		 * safe.
3670Sstevel@tonic-gate 		 */
3680Sstevel@tonic-gate 		off = uio->uio_loffset & MAXBMASK;
3690Sstevel@tonic-gate 		mapon = (int)(uio->uio_loffset & MAXBOFFSET);
3700Sstevel@tonic-gate 		n = MIN(MAXBSIZE - mapon, uio->uio_resid);
3710Sstevel@tonic-gate 		if (rw == UIO_READ) {
3720Sstevel@tonic-gate 			offset_t diff;
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 			diff = pcp->pc_size - uio->uio_loffset;
3750Sstevel@tonic-gate 			if (diff <= 0)
3760Sstevel@tonic-gate 				return (0);
3770Sstevel@tonic-gate 			if (diff < n)
3780Sstevel@tonic-gate 				n = (int)diff;
3790Sstevel@tonic-gate 		}
3800Sstevel@tonic-gate 		/*
3810Sstevel@tonic-gate 		 * Compare limit with the actual offset + n, not the
3820Sstevel@tonic-gate 		 * rounded down offset "off" or we will overflow
3830Sstevel@tonic-gate 		 * the maximum file size after all.
3840Sstevel@tonic-gate 		 */
3850Sstevel@tonic-gate 		if (rw == UIO_WRITE && uio->uio_loffset + n >= limit) {
3860Sstevel@tonic-gate 			if (uio->uio_loffset >= limit) {
3870Sstevel@tonic-gate 				error = EFBIG;
3880Sstevel@tonic-gate 				break;
3890Sstevel@tonic-gate 			}
3900Sstevel@tonic-gate 			n = (int)(limit - uio->uio_loffset);
3910Sstevel@tonic-gate 		}
3928059SDonghai.Qiao@Sun.COM 
3938059SDonghai.Qiao@Sun.COM 		/*
3948059SDonghai.Qiao@Sun.COM 		 * Touch the page and fault it in if it is not in
3958059SDonghai.Qiao@Sun.COM 		 * core before segmap_getmapflt can lock it. This
3968059SDonghai.Qiao@Sun.COM 		 * is to avoid the deadlock if the buffer is mapped
3978059SDonghai.Qiao@Sun.COM 		 * to the same file through mmap which we want to
3988059SDonghai.Qiao@Sun.COM 		 * write to.
3998059SDonghai.Qiao@Sun.COM 		 */
4008059SDonghai.Qiao@Sun.COM 		uio_prefaultpages((long)n, uio);
4018059SDonghai.Qiao@Sun.COM 
4020Sstevel@tonic-gate 		base = segmap_getmap(segkmap, vp, (u_offset_t)off);
4030Sstevel@tonic-gate 		pagecreate = 0;
4040Sstevel@tonic-gate 		newpage = 0;
4050Sstevel@tonic-gate 		if (rw == UIO_WRITE) {
4060Sstevel@tonic-gate 			/*
4070Sstevel@tonic-gate 			 * If PAGESIZE < MAXBSIZE, perhaps we ought to deal
4080Sstevel@tonic-gate 			 * with one page at a time, instead of one MAXBSIZE
4090Sstevel@tonic-gate 			 * at a time, so we can fully explore pagecreate
4100Sstevel@tonic-gate 			 * optimization??
4110Sstevel@tonic-gate 			 */
4120Sstevel@tonic-gate 			if (uio->uio_loffset + n > pcp->pc_size) {
4130Sstevel@tonic-gate 				uint_t ncl, lcn;
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 				ncl = (uint_t)howmany((offset_t)pcp->pc_size,
4164723Sksn 				    fsp->pcfs_clsize);
4170Sstevel@tonic-gate 				if (uio->uio_loffset > pcp->pc_size &&
4180Sstevel@tonic-gate 				    ncl < (uint_t)howmany(uio->uio_loffset,
4194723Sksn 				    fsp->pcfs_clsize)) {
4200Sstevel@tonic-gate 					/*
4210Sstevel@tonic-gate 					 * Allocate and zerofill skipped
4220Sstevel@tonic-gate 					 * clusters. This may not be worth the
4230Sstevel@tonic-gate 					 * effort since a small lseek beyond
4240Sstevel@tonic-gate 					 * eof but still within the cluster
4250Sstevel@tonic-gate 					 * will not be zeroed out.
4260Sstevel@tonic-gate 					 */
4270Sstevel@tonic-gate 					lcn = pc_lblkno(fsp, uio->uio_loffset);
4280Sstevel@tonic-gate 					error = pc_balloc(pcp, (daddr_t)lcn,
4290Sstevel@tonic-gate 					    1, &bn);
4300Sstevel@tonic-gate 					ncl = lcn + 1;
4310Sstevel@tonic-gate 				}
4320Sstevel@tonic-gate 				if (!error &&
4330Sstevel@tonic-gate 				    ncl < (uint_t)howmany(uio->uio_loffset + n,
4344723Sksn 				    fsp->pcfs_clsize))
4350Sstevel@tonic-gate 					/*
4360Sstevel@tonic-gate 					 * allocate clusters w/o zerofill
4370Sstevel@tonic-gate 					 */
4380Sstevel@tonic-gate 					error = pc_balloc(pcp,
4390Sstevel@tonic-gate 					    (daddr_t)pc_lblkno(fsp,
4400Sstevel@tonic-gate 					    uio->uio_loffset + n - 1),
4410Sstevel@tonic-gate 					    0, &bn);
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 				pcp->pc_flags |= PC_CHG;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 				if (error) {
4462972Sfrankho 					pc_cluster32_t ncl;
4472972Sfrankho 					int nerror;
4482972Sfrankho 
4492972Sfrankho 					/*
4502972Sfrankho 					 * figure out new file size from
4512972Sfrankho 					 * cluster chain length. If this
4522972Sfrankho 					 * is detected to loop, the chain
4532972Sfrankho 					 * is corrupted and we'd better
4542972Sfrankho 					 * keep our fingers off that file.
4552972Sfrankho 					 */
4562972Sfrankho 					nerror = pc_fileclsize(fsp,
4572972Sfrankho 					    pcp->pc_scluster, &ncl);
4582972Sfrankho 					if (nerror) {
4592972Sfrankho 						PC_DPRINTF1(2,
4602972Sfrankho 						    "cluster chain "
4612972Sfrankho 						    "corruption, "
4622972Sfrankho 						    "scluster=%d\n",
4632972Sfrankho 						    pcp->pc_scluster);
4642972Sfrankho 						pcp->pc_size = 0;
4652972Sfrankho 						pcp->pc_flags |= PC_INVAL;
4662972Sfrankho 						error = nerror;
4672972Sfrankho 						(void) segmap_release(segkmap,
4682972Sfrankho 						    base, 0);
4692972Sfrankho 						break;
4702972Sfrankho 					}
4712972Sfrankho 					pcp->pc_size = fsp->pcfs_clsize * ncl;
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 					if (error == ENOSPC &&
4740Sstevel@tonic-gate 					    (pcp->pc_size - uio->uio_loffset)
4754723Sksn 					    > 0) {
4760Sstevel@tonic-gate 						PC_DPRINTF3(2, "rwpcp ENOSPC "
4770Sstevel@tonic-gate 						    "off=%lld n=%d size=%d\n",
4780Sstevel@tonic-gate 						    uio->uio_loffset,
4790Sstevel@tonic-gate 						    n, pcp->pc_size);
4800Sstevel@tonic-gate 						n = (int)(pcp->pc_size -
4814723Sksn 						    uio->uio_loffset);
4820Sstevel@tonic-gate 					} else {
4830Sstevel@tonic-gate 						PC_DPRINTF1(1,
4840Sstevel@tonic-gate 						    "rwpcp error1=%d\n", error);
4850Sstevel@tonic-gate 						(void) segmap_release(segkmap,
4860Sstevel@tonic-gate 						    base, 0);
4870Sstevel@tonic-gate 						break;
4880Sstevel@tonic-gate 					}
4890Sstevel@tonic-gate 				} else {
4900Sstevel@tonic-gate 					pcp->pc_size =
4910Sstevel@tonic-gate 					    (uint_t)(uio->uio_loffset + n);
4920Sstevel@tonic-gate 				}
4930Sstevel@tonic-gate 				if (mapon == 0) {
4940Sstevel@tonic-gate 					newpage = segmap_pagecreate(segkmap,
4954723Sksn 					    base, (size_t)n, 0);
4960Sstevel@tonic-gate 					pagecreate = 1;
4970Sstevel@tonic-gate 				}
4980Sstevel@tonic-gate 			} else if (n == MAXBSIZE) {
4990Sstevel@tonic-gate 				newpage = segmap_pagecreate(segkmap, base,
5004723Sksn 				    (size_t)n, 0);
5010Sstevel@tonic-gate 				pagecreate = 1;
5020Sstevel@tonic-gate 			}
5030Sstevel@tonic-gate 		}
5040Sstevel@tonic-gate 		error = uiomove(base + mapon, (size_t)n, rw, uio);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 		if (pagecreate && uio->uio_loffset <
5074723Sksn 		    roundup(off + mapon + n, PAGESIZE)) {
5080Sstevel@tonic-gate 			offset_t nzero, nmoved;
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 			nmoved = uio->uio_loffset - (off + mapon);
5110Sstevel@tonic-gate 			nzero = roundup(mapon + n, PAGESIZE) - nmoved;
5120Sstevel@tonic-gate 			(void) kzero(base + mapon + nmoved, (size_t)nzero);
5130Sstevel@tonic-gate 		}
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 		/*
5160Sstevel@tonic-gate 		 * Unlock the pages which have been allocated by
5170Sstevel@tonic-gate 		 * page_create_va() in segmap_pagecreate().
5180Sstevel@tonic-gate 		 */
5195121Sfrankho 		if (newpage) {
5200Sstevel@tonic-gate 			segmap_pageunlock(segkmap, base, (size_t)n,
5214723Sksn 			    rw == UIO_WRITE ? S_WRITE : S_READ);
5225121Sfrankho 		}
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 		if (error) {
5250Sstevel@tonic-gate 			PC_DPRINTF1(1, "rwpcp error2=%d\n", error);
5260Sstevel@tonic-gate 			/*
5270Sstevel@tonic-gate 			 * If we failed on a write, we may have already
5280Sstevel@tonic-gate 			 * allocated file blocks as well as pages.  It's hard
5290Sstevel@tonic-gate 			 * to undo the block allocation, but we must be sure
5300Sstevel@tonic-gate 			 * to invalidate any pages that may have been
5310Sstevel@tonic-gate 			 * allocated.
5320Sstevel@tonic-gate 			 */
5330Sstevel@tonic-gate 			if (rw == UIO_WRITE)
5340Sstevel@tonic-gate 				(void) segmap_release(segkmap, base, SM_INVAL);
5350Sstevel@tonic-gate 			else
5360Sstevel@tonic-gate 				(void) segmap_release(segkmap, base, 0);
5370Sstevel@tonic-gate 		} else {
5380Sstevel@tonic-gate 			uint_t flags = 0;
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 			if (rw == UIO_READ) {
5410Sstevel@tonic-gate 				if (n + mapon == MAXBSIZE ||
5420Sstevel@tonic-gate 				    uio->uio_loffset == pcp->pc_size)
5430Sstevel@tonic-gate 					flags = SM_DONTNEED;
5440Sstevel@tonic-gate 			} else if (ioflag & (FSYNC|FDSYNC)) {
5450Sstevel@tonic-gate 				flags = SM_WRITE;
5460Sstevel@tonic-gate 			} else if (n + mapon == MAXBSIZE) {
5470Sstevel@tonic-gate 				flags = SM_WRITE|SM_ASYNC|SM_DONTNEED;
5480Sstevel@tonic-gate 			}
5490Sstevel@tonic-gate 			error = segmap_release(segkmap, base, flags);
5500Sstevel@tonic-gate 		}
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	} while (error == 0 && uio->uio_resid > 0 && n != 0);
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	if (oresid != uio->uio_resid)
5550Sstevel@tonic-gate 		error = 0;
5560Sstevel@tonic-gate 	return (error);
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate /*ARGSUSED*/
5600Sstevel@tonic-gate static int
pcfs_getattr(struct vnode * vp,struct vattr * vap,int flags,struct cred * cr,caller_context_t * ct)5610Sstevel@tonic-gate pcfs_getattr(
5620Sstevel@tonic-gate 	struct vnode *vp,
5630Sstevel@tonic-gate 	struct vattr *vap,
5640Sstevel@tonic-gate 	int flags,
5655331Samw 	struct cred *cr,
5665331Samw 	caller_context_t *ct)
5670Sstevel@tonic-gate {
5680Sstevel@tonic-gate 	struct pcnode *pcp;
5690Sstevel@tonic-gate 	struct pcfs *fsp;
5700Sstevel@tonic-gate 	int error;
5710Sstevel@tonic-gate 	char attr;
5720Sstevel@tonic-gate 	struct pctime atime;
5732720Sfrankho 	int64_t unixtime;
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	PC_DPRINTF1(8, "pcfs_getattr: vp=%p\n", (void *)vp);
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
5780Sstevel@tonic-gate 	error = pc_lockfs(fsp, 0, 0);
5790Sstevel@tonic-gate 	if (error)
5800Sstevel@tonic-gate 		return (error);
5812972Sfrankho 
5822972Sfrankho 	/*
5832972Sfrankho 	 * Note that we don't check for "invalid node" (PC_INVAL) here
5842972Sfrankho 	 * only in order to make stat() succeed. We allow no I/O on such
5855331Samw 	 * a node, but do allow to check for its existence.
5862972Sfrankho 	 */
5870Sstevel@tonic-gate 	if ((pcp = VTOPC(vp)) == NULL) {
5880Sstevel@tonic-gate 		pc_unlockfs(fsp);
5890Sstevel@tonic-gate 		return (EIO);
5900Sstevel@tonic-gate 	}
5910Sstevel@tonic-gate 	/*
5920Sstevel@tonic-gate 	 * Copy from pcnode.
5930Sstevel@tonic-gate 	 */
5940Sstevel@tonic-gate 	vap->va_type = vp->v_type;
5950Sstevel@tonic-gate 	attr = pcp->pc_entry.pcd_attr;
5960Sstevel@tonic-gate 	if (PCA_IS_HIDDEN(fsp, attr))
5970Sstevel@tonic-gate 		vap->va_mode = 0;
5980Sstevel@tonic-gate 	else if (attr & PCA_LABEL)
5990Sstevel@tonic-gate 		vap->va_mode = 0444;
6000Sstevel@tonic-gate 	else if (attr & PCA_RDONLY)
6010Sstevel@tonic-gate 		vap->va_mode = 0555;
6020Sstevel@tonic-gate 	else if (fsp->pcfs_flags & PCFS_BOOTPART) {
6030Sstevel@tonic-gate 		vap->va_mode = 0755;
6040Sstevel@tonic-gate 	} else {
6050Sstevel@tonic-gate 		vap->va_mode = 0777;
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	if (attr & PCA_DIR)
6090Sstevel@tonic-gate 		vap->va_mode |= S_IFDIR;
6100Sstevel@tonic-gate 	else
6110Sstevel@tonic-gate 		vap->va_mode |= S_IFREG;
6120Sstevel@tonic-gate 	if (fsp->pcfs_flags & PCFS_BOOTPART) {
6130Sstevel@tonic-gate 		vap->va_uid = 0;
6140Sstevel@tonic-gate 		vap->va_gid = 0;
6150Sstevel@tonic-gate 	} else {
6160Sstevel@tonic-gate 		vap->va_uid = crgetuid(cr);
6170Sstevel@tonic-gate 		vap->va_gid = crgetgid(cr);
6180Sstevel@tonic-gate 	}
6190Sstevel@tonic-gate 	vap->va_fsid = vp->v_vfsp->vfs_dev;
6200Sstevel@tonic-gate 	vap->va_nodeid = (ino64_t)pc_makenodeid(pcp->pc_eblkno,
6210Sstevel@tonic-gate 	    pcp->pc_eoffset, pcp->pc_entry.pcd_attr,
6225121Sfrankho 	    pc_getstartcluster(fsp, &pcp->pc_entry), pc_direntpersec(fsp));
6230Sstevel@tonic-gate 	vap->va_nlink = 1;
6240Sstevel@tonic-gate 	vap->va_size = (u_offset_t)pcp->pc_size;
6255121Sfrankho 	vap->va_rdev = 0;
6265121Sfrankho 	vap->va_nblocks =
6275121Sfrankho 	    (fsblkcnt64_t)howmany((offset_t)pcp->pc_size, DEV_BSIZE);
6285121Sfrankho 	vap->va_blksize = fsp->pcfs_clsize;
6295121Sfrankho 
6305121Sfrankho 	/*
6315121Sfrankho 	 * FAT root directories have no timestamps. In order not to return
6325121Sfrankho 	 * "time zero" (1/1/1970), we record the time of the mount and give
6335121Sfrankho 	 * that. This breaks less expectations.
6345121Sfrankho 	 */
6355121Sfrankho 	if (vp->v_flag & VROOT) {
6365121Sfrankho 		vap->va_mtime = fsp->pcfs_mounttime;
6375121Sfrankho 		vap->va_atime = fsp->pcfs_mounttime;
6385121Sfrankho 		vap->va_ctime = fsp->pcfs_mounttime;
6395121Sfrankho 		pc_unlockfs(fsp);
6405121Sfrankho 		return (0);
6415121Sfrankho 	}
6422720Sfrankho 
6432720Sfrankho 	pc_pcttotv(&pcp->pc_entry.pcd_mtime, &unixtime);
6442720Sfrankho 	if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) {
6452720Sfrankho 		if (unixtime > INT32_MAX)
6462720Sfrankho 			DTRACE_PROBE1(pcfs__mtimeclamped, int64_t, unixtime);
6472720Sfrankho 		unixtime = MIN(unixtime, INT32_MAX);
6482720Sfrankho 	} else if (unixtime > INT32_MAX &&
6492720Sfrankho 	    get_udatamodel() == DATAMODEL_ILP32) {
6502720Sfrankho 		pc_unlockfs(fsp);
6512720Sfrankho 		DTRACE_PROBE1(pcfs__mtimeoverflowed, int64_t, unixtime);
6522720Sfrankho 		return (EOVERFLOW);
6532720Sfrankho 	}
6542720Sfrankho 
6552720Sfrankho 	vap->va_mtime.tv_sec = (time_t)unixtime;
6562720Sfrankho 	vap->va_mtime.tv_nsec = 0;
6572720Sfrankho 
6582720Sfrankho 	/*
6592720Sfrankho 	 * FAT doesn't know about POSIX ctime.
6602720Sfrankho 	 * Best approximation is to always set it to mtime.
6612720Sfrankho 	 */
6620Sstevel@tonic-gate 	vap->va_ctime = vap->va_mtime;
6632720Sfrankho 
6642720Sfrankho 	/*
6652720Sfrankho 	 * FAT only stores "last access date". If that's the
6662720Sfrankho 	 * same as the date of last modification then the time
6672720Sfrankho 	 * of last access is known. Otherwise, use midnight.
6682720Sfrankho 	 */
6690Sstevel@tonic-gate 	atime.pct_date = pcp->pc_entry.pcd_ladate;
6702720Sfrankho 	if (atime.pct_date == pcp->pc_entry.pcd_mtime.pct_date)
6712720Sfrankho 		atime.pct_time = pcp->pc_entry.pcd_mtime.pct_time;
6722720Sfrankho 	else
6732720Sfrankho 		atime.pct_time = 0;
6742720Sfrankho 	pc_pcttotv(&atime, &unixtime);
6752720Sfrankho 	if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) {
6762720Sfrankho 		if (unixtime > INT32_MAX)
6772720Sfrankho 			DTRACE_PROBE1(pcfs__atimeclamped, int64_t, unixtime);
6782720Sfrankho 		unixtime = MIN(unixtime, INT32_MAX);
6792720Sfrankho 	} else if (unixtime > INT32_MAX &&
6802720Sfrankho 	    get_udatamodel() == DATAMODEL_ILP32) {
6812720Sfrankho 		pc_unlockfs(fsp);
6822720Sfrankho 		DTRACE_PROBE1(pcfs__atimeoverflowed, int64_t, unixtime);
6832720Sfrankho 		return (EOVERFLOW);
6842720Sfrankho 	}
6852720Sfrankho 
6862720Sfrankho 	vap->va_atime.tv_sec = (time_t)unixtime;
6872720Sfrankho 	vap->va_atime.tv_nsec = 0;
6882720Sfrankho 
6890Sstevel@tonic-gate 	pc_unlockfs(fsp);
6900Sstevel@tonic-gate 	return (0);
6910Sstevel@tonic-gate }
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate /*ARGSUSED*/
6950Sstevel@tonic-gate static int
pcfs_setattr(struct vnode * vp,struct vattr * vap,int flags,struct cred * cr,caller_context_t * ct)6960Sstevel@tonic-gate pcfs_setattr(
6970Sstevel@tonic-gate 	struct vnode *vp,
6980Sstevel@tonic-gate 	struct vattr *vap,
6990Sstevel@tonic-gate 	int flags,
7000Sstevel@tonic-gate 	struct cred *cr,
7010Sstevel@tonic-gate 	caller_context_t *ct)
7020Sstevel@tonic-gate {
7030Sstevel@tonic-gate 	struct pcnode *pcp;
7040Sstevel@tonic-gate 	mode_t mask = vap->va_mask;
7050Sstevel@tonic-gate 	int error;
7060Sstevel@tonic-gate 	struct pcfs *fsp;
7072720Sfrankho 	timestruc_t now, *timep;
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	PC_DPRINTF2(6, "pcfs_setattr: vp=%p mask=%x\n", (void *)vp, (int)mask);
7100Sstevel@tonic-gate 	/*
7110Sstevel@tonic-gate 	 * cannot set these attributes
7120Sstevel@tonic-gate 	 */
7130Sstevel@tonic-gate 	if (mask & (AT_NOSET | AT_UID | AT_GID)) {
7140Sstevel@tonic-gate 		return (EINVAL);
7150Sstevel@tonic-gate 	}
7160Sstevel@tonic-gate 	/*
7172720Sfrankho 	 * pcfs_setattr is now allowed on directories to avoid silly warnings
7180Sstevel@tonic-gate 	 * from 'tar' when it tries to set times on a directory, and console
7190Sstevel@tonic-gate 	 * printf's on the NFS server when it gets EINVAL back on such a
7200Sstevel@tonic-gate 	 * request. One possible problem with that since a directory entry
7210Sstevel@tonic-gate 	 * identifies a file, '.' and all the '..' entries in subdirectories
7220Sstevel@tonic-gate 	 * may get out of sync when the directory is updated since they're
7230Sstevel@tonic-gate 	 * treated like separate files. We could fix that by looking for
7240Sstevel@tonic-gate 	 * '.' and giving it the same attributes, and then looking for
7250Sstevel@tonic-gate 	 * all the subdirectories and updating '..', but that's pretty
7260Sstevel@tonic-gate 	 * expensive for something that doesn't seem likely to matter.
7270Sstevel@tonic-gate 	 */
7280Sstevel@tonic-gate 	/* can't do some ops on directories anyway */
7290Sstevel@tonic-gate 	if ((vp->v_type == VDIR) &&
7300Sstevel@tonic-gate 	    (mask & AT_SIZE)) {
7310Sstevel@tonic-gate 		return (EINVAL);
7320Sstevel@tonic-gate 	}
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
7350Sstevel@tonic-gate 	error = pc_lockfs(fsp, 0, 0);
7360Sstevel@tonic-gate 	if (error)
7370Sstevel@tonic-gate 		return (error);
7382972Sfrankho 	if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
7390Sstevel@tonic-gate 		pc_unlockfs(fsp);
7400Sstevel@tonic-gate 		return (EIO);
7410Sstevel@tonic-gate 	}
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	if (fsp->pcfs_flags & PCFS_BOOTPART) {
7440Sstevel@tonic-gate 		if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
7450Sstevel@tonic-gate 			pc_unlockfs(fsp);
7460Sstevel@tonic-gate 			return (EACCES);
7470Sstevel@tonic-gate 		}
7480Sstevel@tonic-gate 	}
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	/*
7510Sstevel@tonic-gate 	 * Change file access modes.
7520Sstevel@tonic-gate 	 * If nobody has write permission, file is marked readonly.
7530Sstevel@tonic-gate 	 * Otherwise file is writable by anyone.
7540Sstevel@tonic-gate 	 */
7550Sstevel@tonic-gate 	if ((mask & AT_MODE) && (vap->va_mode != (mode_t)-1)) {
7560Sstevel@tonic-gate 		if ((vap->va_mode & 0222) == 0)
7570Sstevel@tonic-gate 			pcp->pc_entry.pcd_attr |= PCA_RDONLY;
7580Sstevel@tonic-gate 		else
7590Sstevel@tonic-gate 			pcp->pc_entry.pcd_attr &= ~PCA_RDONLY;
7600Sstevel@tonic-gate 		pcp->pc_flags |= PC_CHG;
7610Sstevel@tonic-gate 	}
7620Sstevel@tonic-gate 	/*
7630Sstevel@tonic-gate 	 * Truncate file. Must have write permission.
7640Sstevel@tonic-gate 	 */
7650Sstevel@tonic-gate 	if ((mask & AT_SIZE) && (vap->va_size != (u_offset_t)-1)) {
7660Sstevel@tonic-gate 		if (pcp->pc_entry.pcd_attr & PCA_RDONLY) {
7670Sstevel@tonic-gate 			error = EACCES;
7680Sstevel@tonic-gate 			goto out;
7690Sstevel@tonic-gate 		}
7700Sstevel@tonic-gate 		if (vap->va_size > UINT32_MAX) {
7710Sstevel@tonic-gate 			error = EFBIG;
7720Sstevel@tonic-gate 			goto out;
7730Sstevel@tonic-gate 		}
7740Sstevel@tonic-gate 		error = pc_truncate(pcp, (uint_t)vap->va_size);
7750Sstevel@tonic-gate 		if (error)
7760Sstevel@tonic-gate 			goto out;
7770Sstevel@tonic-gate 	}
7780Sstevel@tonic-gate 	/*
7790Sstevel@tonic-gate 	 * Change file modified times.
7800Sstevel@tonic-gate 	 */
7812720Sfrankho 	if (mask & (AT_MTIME | AT_CTIME)) {
7820Sstevel@tonic-gate 		/*
7830Sstevel@tonic-gate 		 * If SysV-compatible option to set access and
7840Sstevel@tonic-gate 		 * modified times if privileged, owner, or write access,
7850Sstevel@tonic-gate 		 * use current time rather than va_mtime.
7860Sstevel@tonic-gate 		 *
7870Sstevel@tonic-gate 		 * XXX - va_mtime.tv_sec == -1 flags this.
7880Sstevel@tonic-gate 		 */
7892720Sfrankho 		timep = &vap->va_mtime;
7900Sstevel@tonic-gate 		if (vap->va_mtime.tv_sec == -1) {
7910Sstevel@tonic-gate 			gethrestime(&now);
7922720Sfrankho 			timep = &now;
7930Sstevel@tonic-gate 		}
7942720Sfrankho 		if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 &&
7952720Sfrankho 		    timep->tv_sec > INT32_MAX) {
7962720Sfrankho 			error = EOVERFLOW;
7972720Sfrankho 			goto out;
7982720Sfrankho 		}
7992720Sfrankho 		error = pc_tvtopct(timep, &pcp->pc_entry.pcd_mtime);
8002720Sfrankho 		if (error)
8012720Sfrankho 			goto out;
8020Sstevel@tonic-gate 		pcp->pc_flags |= PC_CHG;
8030Sstevel@tonic-gate 	}
8040Sstevel@tonic-gate 	/*
8050Sstevel@tonic-gate 	 * Change file access times.
8060Sstevel@tonic-gate 	 */
8072720Sfrankho 	if (mask & AT_ATIME) {
8080Sstevel@tonic-gate 		/*
8090Sstevel@tonic-gate 		 * If SysV-compatible option to set access and
8100Sstevel@tonic-gate 		 * modified times if privileged, owner, or write access,
8110Sstevel@tonic-gate 		 * use current time rather than va_mtime.
8120Sstevel@tonic-gate 		 *
8130Sstevel@tonic-gate 		 * XXX - va_atime.tv_sec == -1 flags this.
8140Sstevel@tonic-gate 		 */
8150Sstevel@tonic-gate 		struct pctime	atime;
8160Sstevel@tonic-gate 
8172720Sfrankho 		timep = &vap->va_atime;
8180Sstevel@tonic-gate 		if (vap->va_atime.tv_sec == -1) {
8190Sstevel@tonic-gate 			gethrestime(&now);
8202720Sfrankho 			timep = &now;
8210Sstevel@tonic-gate 		}
8222720Sfrankho 		if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 &&
8232720Sfrankho 		    timep->tv_sec > INT32_MAX) {
8242720Sfrankho 			error = EOVERFLOW;
8252720Sfrankho 			goto out;
8262720Sfrankho 		}
8272720Sfrankho 		error = pc_tvtopct(timep, &atime);
8282720Sfrankho 		if (error)
8292720Sfrankho 			goto out;
8300Sstevel@tonic-gate 		pcp->pc_entry.pcd_ladate = atime.pct_date;
8310Sstevel@tonic-gate 		pcp->pc_flags |= PC_CHG;
8320Sstevel@tonic-gate 	}
8330Sstevel@tonic-gate out:
8340Sstevel@tonic-gate 	pc_unlockfs(fsp);
8350Sstevel@tonic-gate 	return (error);
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate /*ARGSUSED*/
8400Sstevel@tonic-gate static int
pcfs_access(struct vnode * vp,int mode,int flags,struct cred * cr,caller_context_t * ct)8410Sstevel@tonic-gate pcfs_access(
8420Sstevel@tonic-gate 	struct vnode *vp,
8430Sstevel@tonic-gate 	int mode,
8440Sstevel@tonic-gate 	int flags,
8455331Samw 	struct cred *cr,
8465331Samw 	caller_context_t *ct)
8470Sstevel@tonic-gate {
8480Sstevel@tonic-gate 	struct pcnode *pcp;
8490Sstevel@tonic-gate 	struct pcfs *fsp;
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
8530Sstevel@tonic-gate 
8542972Sfrankho 	if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL)
8550Sstevel@tonic-gate 		return (EIO);
8560Sstevel@tonic-gate 	if ((mode & VWRITE) && (pcp->pc_entry.pcd_attr & PCA_RDONLY))
8570Sstevel@tonic-gate 		return (EACCES);
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 	/*
8600Sstevel@tonic-gate 	 * If this is a boot partition, privileged users have full access while
8610Sstevel@tonic-gate 	 * others have read-only access.
8620Sstevel@tonic-gate 	 */
8630Sstevel@tonic-gate 	if (fsp->pcfs_flags & PCFS_BOOTPART) {
8640Sstevel@tonic-gate 		if ((mode & VWRITE) &&
8650Sstevel@tonic-gate 		    secpolicy_pcfs_modify_bootpartition(cr) != 0)
8660Sstevel@tonic-gate 			return (EACCES);
8670Sstevel@tonic-gate 	}
8680Sstevel@tonic-gate 	return (0);
8690Sstevel@tonic-gate }
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate /*ARGSUSED*/
8730Sstevel@tonic-gate static int
pcfs_fsync(struct vnode * vp,int syncflag,struct cred * cr,caller_context_t * ct)8740Sstevel@tonic-gate pcfs_fsync(
8750Sstevel@tonic-gate 	struct vnode *vp,
8760Sstevel@tonic-gate 	int syncflag,
8775331Samw 	struct cred *cr,
8785331Samw 	caller_context_t *ct)
8790Sstevel@tonic-gate {
8800Sstevel@tonic-gate 	struct pcfs *fsp;
8810Sstevel@tonic-gate 	struct pcnode *pcp;
8820Sstevel@tonic-gate 	int error;
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
8850Sstevel@tonic-gate 	if (error = pc_verify(fsp))
8860Sstevel@tonic-gate 		return (error);
8870Sstevel@tonic-gate 	error = pc_lockfs(fsp, 0, 0);
8880Sstevel@tonic-gate 	if (error)
8890Sstevel@tonic-gate 		return (error);
8902972Sfrankho 	if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
8910Sstevel@tonic-gate 		pc_unlockfs(fsp);
8920Sstevel@tonic-gate 		return (EIO);
8930Sstevel@tonic-gate 	}
8940Sstevel@tonic-gate 	rw_enter(&pcnodes_lock, RW_WRITER);
8950Sstevel@tonic-gate 	error = pc_nodesync(pcp);
8960Sstevel@tonic-gate 	rw_exit(&pcnodes_lock);
8970Sstevel@tonic-gate 	pc_unlockfs(fsp);
8980Sstevel@tonic-gate 	return (error);
8990Sstevel@tonic-gate }
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate /*ARGSUSED*/
9030Sstevel@tonic-gate static void
pcfs_inactive(struct vnode * vp,struct cred * cr,caller_context_t * ct)9040Sstevel@tonic-gate pcfs_inactive(
9050Sstevel@tonic-gate 	struct vnode *vp,
9065331Samw 	struct cred *cr,
9075331Samw 	caller_context_t *ct)
9080Sstevel@tonic-gate {
9090Sstevel@tonic-gate 	struct pcnode *pcp;
9100Sstevel@tonic-gate 	struct pcfs *fsp;
9110Sstevel@tonic-gate 	int error;
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
9140Sstevel@tonic-gate 	error = pc_lockfs(fsp, 0, 1);
9150Sstevel@tonic-gate 
9162720Sfrankho 	/*
9172720Sfrankho 	 * If the filesystem was umounted by force, all dirty
9182720Sfrankho 	 * pages associated with this vnode are invalidated
9192720Sfrankho 	 * and then the vnode will be freed.
9202720Sfrankho 	 */
9212720Sfrankho 	if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) {
9222720Sfrankho 		pcp = VTOPC(vp);
9232720Sfrankho 		if (vn_has_cached_data(vp)) {
9242720Sfrankho 			(void) pvn_vplist_dirty(vp, (u_offset_t)0,
9252720Sfrankho 			    pcfs_putapage, B_INVAL, (struct cred *)NULL);
9262720Sfrankho 		}
9272720Sfrankho 		remque(pcp);
9282720Sfrankho 		if (error == 0)
9292720Sfrankho 			pc_unlockfs(fsp);
9302720Sfrankho 		vn_free(vp);
9312720Sfrankho 		kmem_free(pcp, sizeof (struct pcnode));
9322720Sfrankho 		VFS_RELE(PCFSTOVFS(fsp));
9332720Sfrankho 		return;
9342720Sfrankho 	}
9352720Sfrankho 
9360Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
9370Sstevel@tonic-gate 	ASSERT(vp->v_count >= 1);
9380Sstevel@tonic-gate 	if (vp->v_count > 1) {
9390Sstevel@tonic-gate 		vp->v_count--;  /* release our hold from vn_rele */
9400Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
9410Sstevel@tonic-gate 		pc_unlockfs(fsp);
9420Sstevel@tonic-gate 		return;
9430Sstevel@tonic-gate 	}
9440Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	/*
9470Sstevel@tonic-gate 	 * Check again to confirm that no intervening I/O error
9480Sstevel@tonic-gate 	 * with a subsequent pc_diskchanged() call has released
9492972Sfrankho 	 * the pcnode. If it has then release the vnode as above.
9500Sstevel@tonic-gate 	 */
9512972Sfrankho 	pcp = VTOPC(vp);
9522972Sfrankho 	if (pcp == NULL || pcp->pc_flags & PC_INVAL) {
9532720Sfrankho 		if (vn_has_cached_data(vp))
9542720Sfrankho 			(void) pvn_vplist_dirty(vp, (u_offset_t)0,
9552720Sfrankho 			    pcfs_putapage, B_INVAL | B_TRUNC,
9562720Sfrankho 			    (struct cred *)NULL);
9572972Sfrankho 	}
9582972Sfrankho 
9592972Sfrankho 	if (pcp == NULL) {
9600Sstevel@tonic-gate 		vn_free(vp);
9612720Sfrankho 	} else {
9620Sstevel@tonic-gate 		pc_rele(pcp);
9632720Sfrankho 	}
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	if (!error)
9660Sstevel@tonic-gate 		pc_unlockfs(fsp);
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate /*ARGSUSED*/
9700Sstevel@tonic-gate static int
pcfs_lookup(struct vnode * dvp,char * nm,struct vnode ** vpp,struct pathname * pnp,int flags,struct vnode * rdir,struct cred * cr,caller_context_t * ct,int * direntflags,pathname_t * realpnp)9710Sstevel@tonic-gate pcfs_lookup(
9720Sstevel@tonic-gate 	struct vnode *dvp,
9730Sstevel@tonic-gate 	char *nm,
9740Sstevel@tonic-gate 	struct vnode **vpp,
9750Sstevel@tonic-gate 	struct pathname *pnp,
9760Sstevel@tonic-gate 	int flags,
9770Sstevel@tonic-gate 	struct vnode *rdir,
9785331Samw 	struct cred *cr,
9795331Samw 	caller_context_t *ct,
9805331Samw 	int *direntflags,
9815331Samw 	pathname_t *realpnp)
9820Sstevel@tonic-gate {
9830Sstevel@tonic-gate 	struct pcfs *fsp;
9840Sstevel@tonic-gate 	struct pcnode *pcp;
9850Sstevel@tonic-gate 	int error;
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	/*
9882720Sfrankho 	 * If the filesystem was umounted by force, return immediately.
9892720Sfrankho 	 */
9902720Sfrankho 	if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
9912720Sfrankho 		return (EIO);
9922720Sfrankho 
9932720Sfrankho 	/*
9940Sstevel@tonic-gate 	 * verify that the dvp is still valid on the disk
9950Sstevel@tonic-gate 	 */
9960Sstevel@tonic-gate 	fsp = VFSTOPCFS(dvp->v_vfsp);
9970Sstevel@tonic-gate 	if (error = pc_verify(fsp))
9980Sstevel@tonic-gate 		return (error);
9990Sstevel@tonic-gate 	error = pc_lockfs(fsp, 0, 0);
10000Sstevel@tonic-gate 	if (error)
10010Sstevel@tonic-gate 		return (error);
10022972Sfrankho 	if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
10030Sstevel@tonic-gate 		pc_unlockfs(fsp);
10040Sstevel@tonic-gate 		return (EIO);
10050Sstevel@tonic-gate 	}
10060Sstevel@tonic-gate 	/*
10070Sstevel@tonic-gate 	 * Null component name is a synonym for directory being searched.
10080Sstevel@tonic-gate 	 */
10090Sstevel@tonic-gate 	if (*nm == '\0') {
10100Sstevel@tonic-gate 		VN_HOLD(dvp);
10110Sstevel@tonic-gate 		*vpp = dvp;
10120Sstevel@tonic-gate 		pc_unlockfs(fsp);
10130Sstevel@tonic-gate 		return (0);
10140Sstevel@tonic-gate 	}
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 	error = pc_dirlook(VTOPC(dvp), nm, &pcp);
10170Sstevel@tonic-gate 	if (!error) {
10180Sstevel@tonic-gate 		*vpp = PCTOV(pcp);
10190Sstevel@tonic-gate 		pcp->pc_flags |= PC_EXTERNAL;
10200Sstevel@tonic-gate 	}
10210Sstevel@tonic-gate 	pc_unlockfs(fsp);
10220Sstevel@tonic-gate 	return (error);
10230Sstevel@tonic-gate }
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate /*ARGSUSED*/
10270Sstevel@tonic-gate static int
pcfs_create(struct vnode * dvp,char * nm,struct vattr * vap,enum vcexcl exclusive,int mode,struct vnode ** vpp,struct cred * cr,int flag,caller_context_t * ct,vsecattr_t * vsecp)10280Sstevel@tonic-gate pcfs_create(
10290Sstevel@tonic-gate 	struct vnode *dvp,
10300Sstevel@tonic-gate 	char *nm,
10310Sstevel@tonic-gate 	struct vattr *vap,
10320Sstevel@tonic-gate 	enum vcexcl exclusive,
10330Sstevel@tonic-gate 	int mode,
10340Sstevel@tonic-gate 	struct vnode **vpp,
10350Sstevel@tonic-gate 	struct cred *cr,
10365331Samw 	int flag,
10375331Samw 	caller_context_t *ct,
10385331Samw 	vsecattr_t *vsecp)
10390Sstevel@tonic-gate {
10400Sstevel@tonic-gate 	int error;
10410Sstevel@tonic-gate 	struct pcnode *pcp;
10420Sstevel@tonic-gate 	struct vnode *vp;
10430Sstevel@tonic-gate 	struct pcfs *fsp;
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	/*
10460Sstevel@tonic-gate 	 * can't create directories. use pcfs_mkdir.
10470Sstevel@tonic-gate 	 * can't create anything other than files.
10480Sstevel@tonic-gate 	 */
10490Sstevel@tonic-gate 	if (vap->va_type == VDIR)
10500Sstevel@tonic-gate 		return (EISDIR);
10510Sstevel@tonic-gate 	else if (vap->va_type != VREG)
10520Sstevel@tonic-gate 		return (EINVAL);
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 	pcp = NULL;
10550Sstevel@tonic-gate 	fsp = VFSTOPCFS(dvp->v_vfsp);
10560Sstevel@tonic-gate 	error = pc_lockfs(fsp, 0, 0);
10570Sstevel@tonic-gate 	if (error)
10580Sstevel@tonic-gate 		return (error);
10592972Sfrankho 	if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
10600Sstevel@tonic-gate 		pc_unlockfs(fsp);
10610Sstevel@tonic-gate 		return (EIO);
10620Sstevel@tonic-gate 	}
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	if (fsp->pcfs_flags & PCFS_BOOTPART) {
10650Sstevel@tonic-gate 		if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
10660Sstevel@tonic-gate 			pc_unlockfs(fsp);
10670Sstevel@tonic-gate 			return (EACCES);
10680Sstevel@tonic-gate 		}
10690Sstevel@tonic-gate 	}
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	if (*nm == '\0') {
10720Sstevel@tonic-gate 		/*
10730Sstevel@tonic-gate 		 * Null component name refers to the directory itself.
10740Sstevel@tonic-gate 		 */
10750Sstevel@tonic-gate 		VN_HOLD(dvp);
10760Sstevel@tonic-gate 		pcp = VTOPC(dvp);
10770Sstevel@tonic-gate 		error = EEXIST;
10780Sstevel@tonic-gate 	} else {
10790Sstevel@tonic-gate 		error = pc_direnter(VTOPC(dvp), nm, vap, &pcp);
10800Sstevel@tonic-gate 	}
10810Sstevel@tonic-gate 	/*
10820Sstevel@tonic-gate 	 * if file exists and this is a nonexclusive create,
10830Sstevel@tonic-gate 	 * check for access permissions
10840Sstevel@tonic-gate 	 */
10850Sstevel@tonic-gate 	if (error == EEXIST) {
10860Sstevel@tonic-gate 		vp = PCTOV(pcp);
10870Sstevel@tonic-gate 		if (exclusive == NONEXCL) {
10880Sstevel@tonic-gate 			if (vp->v_type == VDIR) {
10890Sstevel@tonic-gate 				error = EISDIR;
10900Sstevel@tonic-gate 			} else if (mode) {
10910Sstevel@tonic-gate 				error = pcfs_access(PCTOV(pcp), mode, 0,
10925331Samw 				    cr, ct);
10930Sstevel@tonic-gate 			} else {
10940Sstevel@tonic-gate 				error = 0;
10950Sstevel@tonic-gate 			}
10960Sstevel@tonic-gate 		}
10970Sstevel@tonic-gate 		if (error) {
10980Sstevel@tonic-gate 			VN_RELE(PCTOV(pcp));
10990Sstevel@tonic-gate 		} else if ((vp->v_type == VREG) && (vap->va_mask & AT_SIZE) &&
11004723Sksn 		    (vap->va_size == 0)) {
11010Sstevel@tonic-gate 			error = pc_truncate(pcp, 0L);
11024863Spraks 			if (error) {
11030Sstevel@tonic-gate 				VN_RELE(PCTOV(pcp));
11044863Spraks 			} else {
11055331Samw 				vnevent_create(PCTOV(pcp), ct);
11064863Spraks 			}
11070Sstevel@tonic-gate 		}
11080Sstevel@tonic-gate 	}
11090Sstevel@tonic-gate 	if (error) {
11100Sstevel@tonic-gate 		pc_unlockfs(fsp);
11110Sstevel@tonic-gate 		return (error);
11120Sstevel@tonic-gate 	}
11130Sstevel@tonic-gate 	*vpp = PCTOV(pcp);
11140Sstevel@tonic-gate 	pcp->pc_flags |= PC_EXTERNAL;
11150Sstevel@tonic-gate 	pc_unlockfs(fsp);
11160Sstevel@tonic-gate 	return (error);
11170Sstevel@tonic-gate }
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate /*ARGSUSED*/
11200Sstevel@tonic-gate static int
pcfs_remove(struct vnode * vp,char * nm,struct cred * cr,caller_context_t * ct,int flags)11210Sstevel@tonic-gate pcfs_remove(
11220Sstevel@tonic-gate 	struct vnode *vp,
11230Sstevel@tonic-gate 	char *nm,
11245331Samw 	struct cred *cr,
11255331Samw 	caller_context_t *ct,
11265331Samw 	int flags)
11270Sstevel@tonic-gate {
11280Sstevel@tonic-gate 	struct pcfs *fsp;
11290Sstevel@tonic-gate 	struct pcnode *pcp;
11300Sstevel@tonic-gate 	int error;
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
11330Sstevel@tonic-gate 	if (error = pc_verify(fsp))
11340Sstevel@tonic-gate 		return (error);
11350Sstevel@tonic-gate 	error = pc_lockfs(fsp, 0, 0);
11360Sstevel@tonic-gate 	if (error)
11370Sstevel@tonic-gate 		return (error);
11382972Sfrankho 	if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
11390Sstevel@tonic-gate 		pc_unlockfs(fsp);
11400Sstevel@tonic-gate 		return (EIO);
11410Sstevel@tonic-gate 	}
11420Sstevel@tonic-gate 	if (fsp->pcfs_flags & PCFS_BOOTPART) {
11430Sstevel@tonic-gate 		if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
11440Sstevel@tonic-gate 			pc_unlockfs(fsp);
11450Sstevel@tonic-gate 			return (EACCES);
11460Sstevel@tonic-gate 		}
11470Sstevel@tonic-gate 	}
11485331Samw 	error = pc_dirremove(pcp, nm, (struct vnode *)0, VREG, ct);
11490Sstevel@tonic-gate 	pc_unlockfs(fsp);
11500Sstevel@tonic-gate 	return (error);
11510Sstevel@tonic-gate }
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate /*
11540Sstevel@tonic-gate  * Rename a file or directory
11550Sstevel@tonic-gate  * This rename is restricted to only rename files within a directory.
11560Sstevel@tonic-gate  * XX should make rename more general
11570Sstevel@tonic-gate  */
11580Sstevel@tonic-gate /*ARGSUSED*/
11590Sstevel@tonic-gate static int
pcfs_rename(struct vnode * sdvp,char * snm,struct vnode * tdvp,char * tnm,struct cred * cr,caller_context_t * ct,int flags)11600Sstevel@tonic-gate pcfs_rename(
11610Sstevel@tonic-gate 	struct vnode *sdvp,		/* old (source) parent vnode */
11620Sstevel@tonic-gate 	char *snm,			/* old (source) entry name */
11630Sstevel@tonic-gate 	struct vnode *tdvp,		/* new (target) parent vnode */
11640Sstevel@tonic-gate 	char *tnm,			/* new (target) entry name */
11655331Samw 	struct cred *cr,
11665331Samw 	caller_context_t *ct,
11675331Samw 	int flags)
11680Sstevel@tonic-gate {
11690Sstevel@tonic-gate 	struct pcfs *fsp;
11700Sstevel@tonic-gate 	struct pcnode *dp;	/* parent pcnode */
11710Sstevel@tonic-gate 	struct pcnode *tdp;
11720Sstevel@tonic-gate 	int error;
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	fsp = VFSTOPCFS(sdvp->v_vfsp);
11750Sstevel@tonic-gate 	if (error = pc_verify(fsp))
11760Sstevel@tonic-gate 		return (error);
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	/*
11790Sstevel@tonic-gate 	 * make sure we can muck with this directory.
11800Sstevel@tonic-gate 	 */
11815331Samw 	error = pcfs_access(sdvp, VWRITE, 0, cr, ct);
11820Sstevel@tonic-gate 	if (error) {
11830Sstevel@tonic-gate 		return (error);
11840Sstevel@tonic-gate 	}
11850Sstevel@tonic-gate 	error = pc_lockfs(fsp, 0, 0);
11860Sstevel@tonic-gate 	if (error)
11870Sstevel@tonic-gate 		return (error);
11882972Sfrankho 	if (((dp = VTOPC(sdvp)) == NULL) || ((tdp = VTOPC(tdvp)) == NULL) ||
11892972Sfrankho 	    (dp->pc_flags & PC_INVAL) || (tdp->pc_flags & PC_INVAL)) {
11900Sstevel@tonic-gate 		pc_unlockfs(fsp);
11910Sstevel@tonic-gate 		return (EIO);
11920Sstevel@tonic-gate 	}
11935331Samw 	error = pc_rename(dp, tdp, snm, tnm, ct);
11940Sstevel@tonic-gate 	pc_unlockfs(fsp);
11950Sstevel@tonic-gate 	return (error);
11960Sstevel@tonic-gate }
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate /*ARGSUSED*/
11990Sstevel@tonic-gate static int
pcfs_mkdir(struct vnode * dvp,char * nm,struct vattr * vap,struct vnode ** vpp,struct cred * cr,caller_context_t * ct,int flags,vsecattr_t * vsecp)12000Sstevel@tonic-gate pcfs_mkdir(
12010Sstevel@tonic-gate 	struct vnode *dvp,
12020Sstevel@tonic-gate 	char *nm,
12030Sstevel@tonic-gate 	struct vattr *vap,
12040Sstevel@tonic-gate 	struct vnode **vpp,
12055331Samw 	struct cred *cr,
12065331Samw 	caller_context_t *ct,
12075331Samw 	int flags,
12085331Samw 	vsecattr_t *vsecp)
12090Sstevel@tonic-gate {
12100Sstevel@tonic-gate 	struct pcfs *fsp;
12110Sstevel@tonic-gate 	struct pcnode *pcp;
12120Sstevel@tonic-gate 	int error;
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 	fsp = VFSTOPCFS(dvp->v_vfsp);
12150Sstevel@tonic-gate 	if (error = pc_verify(fsp))
12160Sstevel@tonic-gate 		return (error);
12170Sstevel@tonic-gate 	error = pc_lockfs(fsp, 0, 0);
12180Sstevel@tonic-gate 	if (error)
12190Sstevel@tonic-gate 		return (error);
12202972Sfrankho 	if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
12210Sstevel@tonic-gate 		pc_unlockfs(fsp);
12220Sstevel@tonic-gate 		return (EIO);
12230Sstevel@tonic-gate 	}
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 	if (fsp->pcfs_flags & PCFS_BOOTPART) {
12260Sstevel@tonic-gate 		if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
12270Sstevel@tonic-gate 			pc_unlockfs(fsp);
12280Sstevel@tonic-gate 			return (EACCES);
12290Sstevel@tonic-gate 		}
12300Sstevel@tonic-gate 	}
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	error = pc_direnter(VTOPC(dvp), nm, vap, &pcp);
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 	if (!error) {
12350Sstevel@tonic-gate 		pcp -> pc_flags |= PC_EXTERNAL;
12360Sstevel@tonic-gate 		*vpp = PCTOV(pcp);
12370Sstevel@tonic-gate 	} else if (error == EEXIST) {
12380Sstevel@tonic-gate 		VN_RELE(PCTOV(pcp));
12390Sstevel@tonic-gate 	}
12400Sstevel@tonic-gate 	pc_unlockfs(fsp);
12410Sstevel@tonic-gate 	return (error);
12420Sstevel@tonic-gate }
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate /*ARGSUSED*/
12450Sstevel@tonic-gate static int
pcfs_rmdir(struct vnode * dvp,char * nm,struct vnode * cdir,struct cred * cr,caller_context_t * ct,int flags)12460Sstevel@tonic-gate pcfs_rmdir(
12470Sstevel@tonic-gate 	struct vnode *dvp,
12480Sstevel@tonic-gate 	char *nm,
12490Sstevel@tonic-gate 	struct vnode *cdir,
12505331Samw 	struct cred *cr,
12515331Samw 	caller_context_t *ct,
12525331Samw 	int flags)
12530Sstevel@tonic-gate {
12540Sstevel@tonic-gate 	struct pcfs *fsp;
12550Sstevel@tonic-gate 	struct pcnode *pcp;
12560Sstevel@tonic-gate 	int error;
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate 	fsp = VFSTOPCFS(dvp -> v_vfsp);
12590Sstevel@tonic-gate 	if (error = pc_verify(fsp))
12600Sstevel@tonic-gate 		return (error);
12610Sstevel@tonic-gate 	if (error = pc_lockfs(fsp, 0, 0))
12620Sstevel@tonic-gate 		return (error);
12630Sstevel@tonic-gate 
12642972Sfrankho 	if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) {
12650Sstevel@tonic-gate 		pc_unlockfs(fsp);
12660Sstevel@tonic-gate 		return (EIO);
12670Sstevel@tonic-gate 	}
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate 	if (fsp->pcfs_flags & PCFS_BOOTPART) {
12700Sstevel@tonic-gate 		if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
12710Sstevel@tonic-gate 			pc_unlockfs(fsp);
12720Sstevel@tonic-gate 			return (EACCES);
12730Sstevel@tonic-gate 		}
12740Sstevel@tonic-gate 	}
12750Sstevel@tonic-gate 
12765331Samw 	error = pc_dirremove(pcp, nm, cdir, VDIR, ct);
12770Sstevel@tonic-gate 	pc_unlockfs(fsp);
12780Sstevel@tonic-gate 	return (error);
12790Sstevel@tonic-gate }
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate /*
12820Sstevel@tonic-gate  * read entries in a directory.
12830Sstevel@tonic-gate  * we must convert pc format to unix format
12840Sstevel@tonic-gate  */
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate /*ARGSUSED*/
12870Sstevel@tonic-gate static int
pcfs_readdir(struct vnode * dvp,struct uio * uiop,struct cred * cr,int * eofp,caller_context_t * ct,int flags)12880Sstevel@tonic-gate pcfs_readdir(
12890Sstevel@tonic-gate 	struct vnode *dvp,
12900Sstevel@tonic-gate 	struct uio *uiop,
12910Sstevel@tonic-gate 	struct cred *cr,
12925331Samw 	int *eofp,
12935331Samw 	caller_context_t *ct,
12945331Samw 	int flags)
12950Sstevel@tonic-gate {
12960Sstevel@tonic-gate 	struct pcnode *pcp;
12970Sstevel@tonic-gate 	struct pcfs *fsp;
12980Sstevel@tonic-gate 	struct pcdir *ep;
12990Sstevel@tonic-gate 	struct buf *bp = NULL;
13000Sstevel@tonic-gate 	offset_t offset;
13010Sstevel@tonic-gate 	int boff;
13020Sstevel@tonic-gate 	struct pc_dirent lbp;
13030Sstevel@tonic-gate 	struct pc_dirent *ld = &lbp;
13040Sstevel@tonic-gate 	int error;
13050Sstevel@tonic-gate 
13062720Sfrankho 	/*
13072720Sfrankho 	 * If the filesystem was umounted by force, return immediately.
13082720Sfrankho 	 */
13092720Sfrankho 	if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
13102720Sfrankho 		return (EIO);
13112720Sfrankho 
13120Sstevel@tonic-gate 	if ((uiop->uio_iovcnt != 1) ||
13130Sstevel@tonic-gate 	    (uiop->uio_loffset % sizeof (struct pcdir)) != 0) {
13140Sstevel@tonic-gate 		return (EINVAL);
13150Sstevel@tonic-gate 	}
13160Sstevel@tonic-gate 	fsp = VFSTOPCFS(dvp->v_vfsp);
13170Sstevel@tonic-gate 	/*
13180Sstevel@tonic-gate 	 * verify that the dp is still valid on the disk
13190Sstevel@tonic-gate 	 */
13200Sstevel@tonic-gate 	if (error = pc_verify(fsp)) {
13210Sstevel@tonic-gate 		return (error);
13220Sstevel@tonic-gate 	}
13230Sstevel@tonic-gate 	error = pc_lockfs(fsp, 0, 0);
13240Sstevel@tonic-gate 	if (error)
13250Sstevel@tonic-gate 		return (error);
13262972Sfrankho 	if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) {
13270Sstevel@tonic-gate 		pc_unlockfs(fsp);
13280Sstevel@tonic-gate 		return (EIO);
13290Sstevel@tonic-gate 	}
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 	bzero(ld, sizeof (*ld));
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 	if (eofp != NULL)
13340Sstevel@tonic-gate 		*eofp = 0;
13350Sstevel@tonic-gate 	offset = uiop->uio_loffset;
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 	if (dvp->v_flag & VROOT) {
13380Sstevel@tonic-gate 		/*
13390Sstevel@tonic-gate 		 * kludge up entries for "." and ".." in the root.
13400Sstevel@tonic-gate 		 */
13410Sstevel@tonic-gate 		if (offset == 0) {
13420Sstevel@tonic-gate 			(void) strcpy(ld->d_name, ".");
13430Sstevel@tonic-gate 			ld->d_reclen = DIRENT64_RECLEN(1);
13440Sstevel@tonic-gate 			ld->d_off = (off64_t)sizeof (struct pcdir);
13450Sstevel@tonic-gate 			ld->d_ino = (ino64_t)UINT_MAX;
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 			(void) uiomove(ld, ld->d_reclen, UIO_READ, uiop);
13510Sstevel@tonic-gate 			uiop->uio_loffset = ld->d_off;
13520Sstevel@tonic-gate 			offset = uiop->uio_loffset;
13530Sstevel@tonic-gate 		}
13540Sstevel@tonic-gate 		if (offset == sizeof (struct pcdir)) {
13550Sstevel@tonic-gate 			(void) strcpy(ld->d_name, "..");
13560Sstevel@tonic-gate 			ld->d_reclen = DIRENT64_RECLEN(2);
13570Sstevel@tonic-gate 			if (ld->d_reclen > uiop->uio_resid) {
13580Sstevel@tonic-gate 				pc_unlockfs(fsp);
13590Sstevel@tonic-gate 				return (ENOSPC);
13600Sstevel@tonic-gate 			}
13610Sstevel@tonic-gate 			ld->d_off = (off64_t)(uiop->uio_loffset +
13620Sstevel@tonic-gate 			    sizeof (struct pcdir));
13630Sstevel@tonic-gate 			ld->d_ino = (ino64_t)UINT_MAX;
13640Sstevel@tonic-gate 			(void) uiomove(ld, ld->d_reclen, UIO_READ, uiop);
13650Sstevel@tonic-gate 			uiop->uio_loffset = ld->d_off;
13660Sstevel@tonic-gate 			offset = uiop->uio_loffset;
13670Sstevel@tonic-gate 		}
13680Sstevel@tonic-gate 		offset -= 2 * sizeof (struct pcdir);
13690Sstevel@tonic-gate 		/* offset now has the real offset value into directory file */
13700Sstevel@tonic-gate 	}
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate 	for (;;) {
13730Sstevel@tonic-gate 		boff = pc_blkoff(fsp, offset);
13740Sstevel@tonic-gate 		if (boff == 0 || bp == NULL || boff >= bp->b_bcount) {
13750Sstevel@tonic-gate 			if (bp != NULL) {
13760Sstevel@tonic-gate 				brelse(bp);
13770Sstevel@tonic-gate 				bp = NULL;
13780Sstevel@tonic-gate 			}
13790Sstevel@tonic-gate 			error = pc_blkatoff(pcp, offset, &bp, &ep);
13800Sstevel@tonic-gate 			if (error) {
13810Sstevel@tonic-gate 				if (error == ENOENT) {
13820Sstevel@tonic-gate 					error = 0;
13830Sstevel@tonic-gate 					if (eofp)
13840Sstevel@tonic-gate 						*eofp = 1;
13850Sstevel@tonic-gate 				}
13860Sstevel@tonic-gate 				break;
13870Sstevel@tonic-gate 			}
13880Sstevel@tonic-gate 		}
13890Sstevel@tonic-gate 		if (ep->pcd_filename[0] == PCD_UNUSED) {
13900Sstevel@tonic-gate 			if (eofp)
13910Sstevel@tonic-gate 				*eofp = 1;
13920Sstevel@tonic-gate 			break;
13930Sstevel@tonic-gate 		}
13940Sstevel@tonic-gate 		/*
13950Sstevel@tonic-gate 		 * Don't display label because it may contain funny characters.
13960Sstevel@tonic-gate 		 */
13970Sstevel@tonic-gate 		if (ep->pcd_filename[0] == PCD_ERASED) {
13980Sstevel@tonic-gate 			uiop->uio_loffset += sizeof (struct pcdir);
13990Sstevel@tonic-gate 			offset += sizeof (struct pcdir);
14000Sstevel@tonic-gate 			ep++;
14010Sstevel@tonic-gate 			continue;
14020Sstevel@tonic-gate 		}
14030Sstevel@tonic-gate 		if (PCDL_IS_LFN(ep)) {
14040Sstevel@tonic-gate 			if (pc_read_long_fn(dvp, uiop, ld, &ep, &offset, &bp) !=
14050Sstevel@tonic-gate 			    0)
14060Sstevel@tonic-gate 				break;
14070Sstevel@tonic-gate 			continue;
14080Sstevel@tonic-gate 		}
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate 		if (pc_read_short_fn(dvp, uiop, ld, &ep, &offset, &bp) != 0)
14110Sstevel@tonic-gate 			break;
14120Sstevel@tonic-gate 	}
14130Sstevel@tonic-gate 	if (bp)
14140Sstevel@tonic-gate 		brelse(bp);
14150Sstevel@tonic-gate 	pc_unlockfs(fsp);
14160Sstevel@tonic-gate 	return (error);
14170Sstevel@tonic-gate }
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate /*
14210Sstevel@tonic-gate  * Called from pvn_getpages or pcfs_getpage to get a particular page.
14220Sstevel@tonic-gate  * When we are called the pcfs is already locked.
14230Sstevel@tonic-gate  */
14240Sstevel@tonic-gate /*ARGSUSED*/
14250Sstevel@tonic-gate static int
pcfs_getapage(struct vnode * vp,u_offset_t off,size_t len,uint_t * protp,page_t * pl[],size_t plsz,struct seg * seg,caddr_t addr,enum seg_rw rw,struct cred * cr)14260Sstevel@tonic-gate pcfs_getapage(
14270Sstevel@tonic-gate 	struct vnode *vp,
14280Sstevel@tonic-gate 	u_offset_t off,
14290Sstevel@tonic-gate 	size_t len,
14300Sstevel@tonic-gate 	uint_t *protp,
14310Sstevel@tonic-gate 	page_t *pl[],		/* NULL if async IO is requested */
14320Sstevel@tonic-gate 	size_t plsz,
14330Sstevel@tonic-gate 	struct seg *seg,
14340Sstevel@tonic-gate 	caddr_t addr,
14350Sstevel@tonic-gate 	enum seg_rw rw,
14360Sstevel@tonic-gate 	struct cred *cr)
14370Sstevel@tonic-gate {
14380Sstevel@tonic-gate 	struct pcnode *pcp;
14390Sstevel@tonic-gate 	struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
14400Sstevel@tonic-gate 	struct vnode *devvp;
14410Sstevel@tonic-gate 	page_t *pp;
14420Sstevel@tonic-gate 	page_t *pagefound;
14430Sstevel@tonic-gate 	int err;
14440Sstevel@tonic-gate 
14452720Sfrankho 	/*
14462720Sfrankho 	 * If the filesystem was umounted by force, return immediately.
14472720Sfrankho 	 */
14482720Sfrankho 	if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
14492720Sfrankho 		return (EIO);
14502720Sfrankho 
14510Sstevel@tonic-gate 	PC_DPRINTF3(5, "pcfs_getapage: vp=%p off=%lld len=%lu\n",
14520Sstevel@tonic-gate 	    (void *)vp, off, len);
14530Sstevel@tonic-gate 
14542972Sfrankho 	if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL)
14550Sstevel@tonic-gate 		return (EIO);
14560Sstevel@tonic-gate 	devvp = fsp->pcfs_devvp;
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate 	/* pcfs doesn't do readaheads */
14590Sstevel@tonic-gate 	if (pl == NULL)
14600Sstevel@tonic-gate 		return (0);
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 	pl[0] = NULL;
14630Sstevel@tonic-gate 	err = 0;
14640Sstevel@tonic-gate 	/*
14650Sstevel@tonic-gate 	 * If the accessed time on the pcnode has not already been
14660Sstevel@tonic-gate 	 * set elsewhere (e.g. for read/setattr) we set the time now.
14670Sstevel@tonic-gate 	 * This gives us approximate modified times for mmap'ed files
14680Sstevel@tonic-gate 	 * which are accessed via loads in the user address space.
14690Sstevel@tonic-gate 	 */
14700Sstevel@tonic-gate 	if ((pcp->pc_flags & PC_ACC) == 0 &&
14710Sstevel@tonic-gate 	    ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0)) {
14725121Sfrankho 		pc_mark_acc(fsp, pcp);
14730Sstevel@tonic-gate 	}
14740Sstevel@tonic-gate reread:
14750Sstevel@tonic-gate 	if ((pagefound = page_exists(vp, off)) == NULL) {
14760Sstevel@tonic-gate 		/*
14770Sstevel@tonic-gate 		 * Need to really do disk IO to get the page(s).
14780Sstevel@tonic-gate 		 */
14790Sstevel@tonic-gate 		struct buf *bp;
14800Sstevel@tonic-gate 		daddr_t lbn, bn;
14810Sstevel@tonic-gate 		u_offset_t io_off;
14820Sstevel@tonic-gate 		size_t io_len;
14830Sstevel@tonic-gate 		u_offset_t lbnoff, xferoffset;
14840Sstevel@tonic-gate 		u_offset_t pgoff;
14850Sstevel@tonic-gate 		uint_t	xfersize;
14860Sstevel@tonic-gate 		int err1;
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 		lbn = pc_lblkno(fsp, off);
14890Sstevel@tonic-gate 		lbnoff = off & ~(fsp->pcfs_clsize - 1);
14900Sstevel@tonic-gate 		xferoffset = off & ~(fsp->pcfs_secsize - 1);
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 		pp = pvn_read_kluster(vp, off, seg, addr, &io_off, &io_len,
14930Sstevel@tonic-gate 		    off, (size_t)MIN(pc_blksize(fsp, pcp, off), PAGESIZE), 0);
14940Sstevel@tonic-gate 		if (pp == NULL)
14950Sstevel@tonic-gate 			/*
14960Sstevel@tonic-gate 			 * XXX - If pcfs is made MT-hot, this should go
14970Sstevel@tonic-gate 			 * back to reread.
14980Sstevel@tonic-gate 			 */
14990Sstevel@tonic-gate 			panic("pcfs_getapage pvn_read_kluster");
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 		for (pgoff = 0; pgoff < PAGESIZE && xferoffset < pcp->pc_size;
15020Sstevel@tonic-gate 		    pgoff += xfersize,
15030Sstevel@tonic-gate 		    lbn +=  howmany(xfersize, fsp->pcfs_clsize),
15040Sstevel@tonic-gate 		    lbnoff += xfersize, xferoffset += xfersize) {
15050Sstevel@tonic-gate 			/*
15060Sstevel@tonic-gate 			 * read as many contiguous blocks as possible to
15070Sstevel@tonic-gate 			 * fill this page
15080Sstevel@tonic-gate 			 */
15090Sstevel@tonic-gate 			xfersize = PAGESIZE - pgoff;
15100Sstevel@tonic-gate 			err1 = pc_bmap(pcp, lbn, &bn, &xfersize);
15110Sstevel@tonic-gate 			if (err1) {
15120Sstevel@tonic-gate 				PC_DPRINTF1(1, "pc_getapage err=%d", err1);
15130Sstevel@tonic-gate 				err = err1;
15140Sstevel@tonic-gate 				goto out;
15150Sstevel@tonic-gate 			}
15160Sstevel@tonic-gate 			bp = pageio_setup(pp, xfersize, devvp, B_READ);
15170Sstevel@tonic-gate 			bp->b_edev = devvp->v_rdev;
15180Sstevel@tonic-gate 			bp->b_dev = cmpdev(devvp->v_rdev);
15195121Sfrankho 			bp->b_blkno = bn + btodt(xferoffset - lbnoff);
1520973Selowe 			bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff;
15210Sstevel@tonic-gate 			bp->b_file = vp;
15220Sstevel@tonic-gate 			bp->b_offset = (offset_t)(off + pgoff);
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 			(void) bdev_strategy(bp);
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 			lwp_stat_update(LWP_STAT_INBLK, 1);
15270Sstevel@tonic-gate 
15280Sstevel@tonic-gate 			if (err == 0)
15290Sstevel@tonic-gate 				err = biowait(bp);
15300Sstevel@tonic-gate 			else
15310Sstevel@tonic-gate 				(void) biowait(bp);
15320Sstevel@tonic-gate 			pageio_done(bp);
15330Sstevel@tonic-gate 			if (err)
15340Sstevel@tonic-gate 				goto out;
15350Sstevel@tonic-gate 		}
15360Sstevel@tonic-gate 		if (pgoff < PAGESIZE) {
15370Sstevel@tonic-gate 			pagezero(pp->p_prev, pgoff, PAGESIZE - pgoff);
15380Sstevel@tonic-gate 		}
15390Sstevel@tonic-gate 		pvn_plist_init(pp, pl, plsz, off, io_len, rw);
15400Sstevel@tonic-gate 	}
15410Sstevel@tonic-gate out:
15420Sstevel@tonic-gate 	if (err) {
15430Sstevel@tonic-gate 		if (pp != NULL)
15440Sstevel@tonic-gate 			pvn_read_done(pp, B_ERROR);
15450Sstevel@tonic-gate 		return (err);
15460Sstevel@tonic-gate 	}
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 	if (pagefound) {
15490Sstevel@tonic-gate 		/*
15500Sstevel@tonic-gate 		 * Page exists in the cache, acquire the "shared"
15510Sstevel@tonic-gate 		 * lock.  If this fails, go back to reread.
15520Sstevel@tonic-gate 		 */
15530Sstevel@tonic-gate 		if ((pp = page_lookup(vp, off, SE_SHARED)) == NULL) {
15540Sstevel@tonic-gate 			goto reread;
15550Sstevel@tonic-gate 		}
15560Sstevel@tonic-gate 		pl[0] = pp;
15570Sstevel@tonic-gate 		pl[1] = NULL;
15580Sstevel@tonic-gate 	}
15590Sstevel@tonic-gate 	return (err);
15600Sstevel@tonic-gate }
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate /*
15630Sstevel@tonic-gate  * Return all the pages from [off..off+len] in given file
15640Sstevel@tonic-gate  */
15655331Samw /* ARGSUSED */
15660Sstevel@tonic-gate static int
pcfs_getpage(struct vnode * vp,offset_t off,size_t len,uint_t * protp,page_t * pl[],size_t plsz,struct seg * seg,caddr_t addr,enum seg_rw rw,struct cred * cr,caller_context_t * ct)15670Sstevel@tonic-gate pcfs_getpage(
15680Sstevel@tonic-gate 	struct vnode *vp,
15690Sstevel@tonic-gate 	offset_t off,
15700Sstevel@tonic-gate 	size_t len,
15710Sstevel@tonic-gate 	uint_t *protp,
15720Sstevel@tonic-gate 	page_t *pl[],
15730Sstevel@tonic-gate 	size_t plsz,
15740Sstevel@tonic-gate 	struct seg *seg,
15750Sstevel@tonic-gate 	caddr_t addr,
15760Sstevel@tonic-gate 	enum seg_rw rw,
15775331Samw 	struct cred *cr,
15785331Samw 	caller_context_t *ct)
15790Sstevel@tonic-gate {
15800Sstevel@tonic-gate 	struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
15810Sstevel@tonic-gate 	int err;
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate 	PC_DPRINTF0(6, "pcfs_getpage\n");
15840Sstevel@tonic-gate 	if (err = pc_verify(fsp))
15850Sstevel@tonic-gate 		return (err);
15860Sstevel@tonic-gate 	if (vp->v_flag & VNOMAP)
15870Sstevel@tonic-gate 		return (ENOSYS);
15880Sstevel@tonic-gate 	ASSERT(off <= UINT32_MAX);
15890Sstevel@tonic-gate 	err = pc_lockfs(fsp, 0, 0);
15900Sstevel@tonic-gate 	if (err)
15910Sstevel@tonic-gate 		return (err);
15920Sstevel@tonic-gate 	if (protp != NULL)
15930Sstevel@tonic-gate 		*protp = PROT_ALL;
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 	ASSERT((off & PAGEOFFSET) == 0);
15960Sstevel@tonic-gate 	if (len <= PAGESIZE) {
15970Sstevel@tonic-gate 		err = pcfs_getapage(vp, off, len, protp, pl,
15980Sstevel@tonic-gate 		    plsz, seg, addr, rw, cr);
15990Sstevel@tonic-gate 	} else {
16000Sstevel@tonic-gate 		err = pvn_getpages(pcfs_getapage, vp, off,
16010Sstevel@tonic-gate 		    len, protp, pl, plsz, seg, addr, rw, cr);
16020Sstevel@tonic-gate 	}
16030Sstevel@tonic-gate 	pc_unlockfs(fsp);
16040Sstevel@tonic-gate 	return (err);
16050Sstevel@tonic-gate }
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate /*
16090Sstevel@tonic-gate  * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE}
16100Sstevel@tonic-gate  * If len == 0, do from off to EOF.
16110Sstevel@tonic-gate  *
16120Sstevel@tonic-gate  * The normal cases should be len == 0 & off == 0 (entire vp list),
16130Sstevel@tonic-gate  * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
16140Sstevel@tonic-gate  * (from pageout).
16150Sstevel@tonic-gate  *
16160Sstevel@tonic-gate  */
16170Sstevel@tonic-gate /*ARGSUSED*/
16180Sstevel@tonic-gate static int
pcfs_putpage(struct vnode * vp,offset_t off,size_t len,int flags,struct cred * cr,caller_context_t * ct)16190Sstevel@tonic-gate pcfs_putpage(
16200Sstevel@tonic-gate 	struct vnode *vp,
16210Sstevel@tonic-gate 	offset_t off,
16220Sstevel@tonic-gate 	size_t len,
16230Sstevel@tonic-gate 	int flags,
16245331Samw 	struct cred *cr,
16255331Samw 	caller_context_t *ct)
16260Sstevel@tonic-gate {
16270Sstevel@tonic-gate 	struct pcnode *pcp;
16280Sstevel@tonic-gate 	page_t *pp;
16290Sstevel@tonic-gate 	struct pcfs *fsp;
16300Sstevel@tonic-gate 	u_offset_t io_off;
16310Sstevel@tonic-gate 	size_t io_len;
16320Sstevel@tonic-gate 	offset_t eoff;
16330Sstevel@tonic-gate 	int err;
16340Sstevel@tonic-gate 
16352720Sfrankho 	/*
16362720Sfrankho 	 * If the filesystem was umounted by force, return immediately.
16372720Sfrankho 	 */
16382720Sfrankho 	if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
16392720Sfrankho 		return (EIO);
16402720Sfrankho 
16410Sstevel@tonic-gate 	PC_DPRINTF1(6, "pcfs_putpage vp=0x%p\n", (void *)vp);
16420Sstevel@tonic-gate 	if (vp->v_flag & VNOMAP)
16430Sstevel@tonic-gate 		return (ENOSYS);
16440Sstevel@tonic-gate 
16450Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	if (err = pc_verify(fsp))
16480Sstevel@tonic-gate 		return (err);
16490Sstevel@tonic-gate 	if ((pcp = VTOPC(vp)) == NULL) {
16500Sstevel@tonic-gate 		PC_DPRINTF1(3, "pcfs_putpage NULL vp=0x%p\n", (void *)vp);
16510Sstevel@tonic-gate 		return (EIO);
16520Sstevel@tonic-gate 	}
16532972Sfrankho 	if (pcp->pc_flags & PC_INVAL)
16542972Sfrankho 		return (EIO);
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 	if (curproc == proc_pageout) {
16570Sstevel@tonic-gate 		/*
16580Sstevel@tonic-gate 		 * XXX - This is a quick hack to avoid blocking
16590Sstevel@tonic-gate 		 * pageout. Also to avoid pcfs_getapage deadlocking
16600Sstevel@tonic-gate 		 * with putpage when memory is running out,
16610Sstevel@tonic-gate 		 * since we only have one global lock and we don't
16620Sstevel@tonic-gate 		 * support async putpage.
16630Sstevel@tonic-gate 		 * It should be fixed someday.
16640Sstevel@tonic-gate 		 *
16650Sstevel@tonic-gate 		 * Interestingly, this used to be a test of NOMEMWAIT().
16660Sstevel@tonic-gate 		 * We only ever got here once pcfs started supporting
16670Sstevel@tonic-gate 		 * NFS sharing, and then only because the NFS server
16680Sstevel@tonic-gate 		 * threads seem to do writes in sched's process context.
16690Sstevel@tonic-gate 		 * Since everyone else seems to just care about pageout,
16700Sstevel@tonic-gate 		 * the test was changed to look for pageout directly.
16710Sstevel@tonic-gate 		 */
16720Sstevel@tonic-gate 		return (ENOMEM);
16730Sstevel@tonic-gate 	}
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 	ASSERT(off <= UINT32_MAX);
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate 	flags &= ~B_ASYNC;	/* XXX should fix this later */
16780Sstevel@tonic-gate 
16790Sstevel@tonic-gate 	err = pc_lockfs(fsp, 0, 0);
16800Sstevel@tonic-gate 	if (err)
16810Sstevel@tonic-gate 		return (err);
16820Sstevel@tonic-gate 	if (!vn_has_cached_data(vp) || off >= pcp->pc_size) {
16830Sstevel@tonic-gate 		pc_unlockfs(fsp);
16840Sstevel@tonic-gate 		return (0);
16850Sstevel@tonic-gate 	}
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate 	if (len == 0) {
16880Sstevel@tonic-gate 		/*
16890Sstevel@tonic-gate 		 * Search the entire vp list for pages >= off
16900Sstevel@tonic-gate 		 */
16910Sstevel@tonic-gate 		err = pvn_vplist_dirty(vp, off,
16920Sstevel@tonic-gate 		    pcfs_putapage, flags, cr);
16930Sstevel@tonic-gate 	} else {
16940Sstevel@tonic-gate 		eoff = off + len;
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 		for (io_off = off; io_off < eoff &&
16970Sstevel@tonic-gate 		    io_off < pcp->pc_size; io_off += io_len) {
16980Sstevel@tonic-gate 			/*
16990Sstevel@tonic-gate 			 * If we are not invalidating, synchronously
17000Sstevel@tonic-gate 			 * freeing or writing pages use the routine
17010Sstevel@tonic-gate 			 * page_lookup_nowait() to prevent reclaiming
17020Sstevel@tonic-gate 			 * them from the free list.
17030Sstevel@tonic-gate 			 */
17040Sstevel@tonic-gate 			if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) {
17050Sstevel@tonic-gate 				pp = page_lookup(vp, io_off,
17064723Sksn 				    (flags & (B_INVAL | B_FREE)) ?
17074723Sksn 				    SE_EXCL : SE_SHARED);
17080Sstevel@tonic-gate 			} else {
17090Sstevel@tonic-gate 				pp = page_lookup_nowait(vp, io_off,
17104723Sksn 				    (flags & B_FREE) ? SE_EXCL : SE_SHARED);
17110Sstevel@tonic-gate 			}
17120Sstevel@tonic-gate 
17130Sstevel@tonic-gate 			if (pp == NULL || pvn_getdirty(pp, flags) == 0)
17140Sstevel@tonic-gate 				io_len = PAGESIZE;
17150Sstevel@tonic-gate 			else {
17160Sstevel@tonic-gate 				err = pcfs_putapage(vp, pp, &io_off, &io_len,
17174723Sksn 				    flags, cr);
17180Sstevel@tonic-gate 				if (err != 0)
17190Sstevel@tonic-gate 					break;
17200Sstevel@tonic-gate 				/*
17210Sstevel@tonic-gate 				 * "io_off" and "io_len" are returned as
17220Sstevel@tonic-gate 				 * the range of pages we actually wrote.
17230Sstevel@tonic-gate 				 * This allows us to skip ahead more quickly
17240Sstevel@tonic-gate 				 * since several pages may've been dealt
17250Sstevel@tonic-gate 				 * with by this iteration of the loop.
17260Sstevel@tonic-gate 				 */
17270Sstevel@tonic-gate 			}
17280Sstevel@tonic-gate 		}
17290Sstevel@tonic-gate 	}
17300Sstevel@tonic-gate 	if (err == 0 && (flags & B_INVAL) &&
17310Sstevel@tonic-gate 	    off == 0 && len == 0 && vn_has_cached_data(vp)) {
17320Sstevel@tonic-gate 		/*
17330Sstevel@tonic-gate 		 * If doing "invalidation", make sure that
17340Sstevel@tonic-gate 		 * all pages on the vnode list are actually
17350Sstevel@tonic-gate 		 * gone.
17360Sstevel@tonic-gate 		 */
17370Sstevel@tonic-gate 		cmn_err(CE_PANIC,
17384723Sksn 		    "pcfs_putpage: B_INVAL, pages not gone");
17390Sstevel@tonic-gate 	} else if (err) {
17400Sstevel@tonic-gate 		PC_DPRINTF1(1, "pcfs_putpage err=%d\n", err);
17410Sstevel@tonic-gate 	}
17420Sstevel@tonic-gate 	pc_unlockfs(fsp);
17430Sstevel@tonic-gate 	return (err);
17440Sstevel@tonic-gate }
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate /*
17470Sstevel@tonic-gate  * Write out a single page, possibly klustering adjacent dirty pages.
17480Sstevel@tonic-gate  */
17490Sstevel@tonic-gate /*ARGSUSED*/
17500Sstevel@tonic-gate int
pcfs_putapage(struct vnode * vp,page_t * pp,u_offset_t * offp,size_t * lenp,int flags,struct cred * cr)17510Sstevel@tonic-gate pcfs_putapage(
17520Sstevel@tonic-gate 	struct vnode *vp,
17530Sstevel@tonic-gate 	page_t *pp,
17540Sstevel@tonic-gate 	u_offset_t *offp,
17550Sstevel@tonic-gate 	size_t *lenp,
17560Sstevel@tonic-gate 	int flags,
17570Sstevel@tonic-gate 	struct cred *cr)
17580Sstevel@tonic-gate {
17590Sstevel@tonic-gate 	struct pcnode *pcp;
17600Sstevel@tonic-gate 	struct pcfs *fsp;
17610Sstevel@tonic-gate 	struct vnode *devvp;
17620Sstevel@tonic-gate 	size_t io_len;
17630Sstevel@tonic-gate 	daddr_t bn;
17640Sstevel@tonic-gate 	u_offset_t lbn, lbnoff, xferoffset;
17650Sstevel@tonic-gate 	uint_t pgoff, xfersize;
17660Sstevel@tonic-gate 	int err = 0;
17670Sstevel@tonic-gate 	u_offset_t io_off;
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 	pcp = VTOPC(vp);
17700Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
17710Sstevel@tonic-gate 	devvp = fsp->pcfs_devvp;
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate 	/*
17740Sstevel@tonic-gate 	 * If the modified time on the inode has not already been
17750Sstevel@tonic-gate 	 * set elsewhere (e.g. for write/setattr) and this is not
17760Sstevel@tonic-gate 	 * a call from msync (B_FORCE) we set the time now.
17770Sstevel@tonic-gate 	 * This gives us approximate modified times for mmap'ed files
17780Sstevel@tonic-gate 	 * which are modified via stores in the user address space.
17790Sstevel@tonic-gate 	 */
17800Sstevel@tonic-gate 	if ((pcp->pc_flags & PC_MOD) == 0 || (flags & B_FORCE)) {
17810Sstevel@tonic-gate 		pcp->pc_flags |= PC_MOD;
17825121Sfrankho 		pc_mark_mod(fsp, pcp);
17830Sstevel@tonic-gate 	}
17840Sstevel@tonic-gate 	pp = pvn_write_kluster(vp, pp, &io_off, &io_len, pp->p_offset,
17850Sstevel@tonic-gate 	    PAGESIZE, flags);
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate 	if (fsp->pcfs_flags & PCFS_IRRECOV) {
17880Sstevel@tonic-gate 		goto out;
17890Sstevel@tonic-gate 	}
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 	PC_DPRINTF1(7, "pc_putpage writing dirty page off=%llu\n", io_off);
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 	lbn = pc_lblkno(fsp, io_off);
17940Sstevel@tonic-gate 	lbnoff = io_off & ~(fsp->pcfs_clsize - 1);
17950Sstevel@tonic-gate 	xferoffset = io_off & ~(fsp->pcfs_secsize - 1);
17960Sstevel@tonic-gate 
17970Sstevel@tonic-gate 	for (pgoff = 0; pgoff < io_len && xferoffset < pcp->pc_size;
17980Sstevel@tonic-gate 	    pgoff += xfersize,
17990Sstevel@tonic-gate 	    lbn += howmany(xfersize, fsp->pcfs_clsize),
18000Sstevel@tonic-gate 	    lbnoff += xfersize, xferoffset += xfersize) {
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate 		struct buf *bp;
18030Sstevel@tonic-gate 		int err1;
18040Sstevel@tonic-gate 
18050Sstevel@tonic-gate 		/*
18060Sstevel@tonic-gate 		 * write as many contiguous blocks as possible from this page
18070Sstevel@tonic-gate 		 */
18080Sstevel@tonic-gate 		xfersize = io_len - pgoff;
18090Sstevel@tonic-gate 		err1 = pc_bmap(pcp, (daddr_t)lbn, &bn, &xfersize);
18100Sstevel@tonic-gate 		if (err1) {
18110Sstevel@tonic-gate 			err = err1;
18120Sstevel@tonic-gate 			goto out;
18130Sstevel@tonic-gate 		}
18140Sstevel@tonic-gate 		bp = pageio_setup(pp, xfersize, devvp, B_WRITE | flags);
18150Sstevel@tonic-gate 		bp->b_edev = devvp->v_rdev;
18160Sstevel@tonic-gate 		bp->b_dev = cmpdev(devvp->v_rdev);
18175121Sfrankho 		bp->b_blkno = bn + btodt(xferoffset - lbnoff);
18180Sstevel@tonic-gate 		bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff;
18190Sstevel@tonic-gate 		bp->b_file = vp;
18200Sstevel@tonic-gate 		bp->b_offset = (offset_t)(io_off + pgoff);
18210Sstevel@tonic-gate 
18220Sstevel@tonic-gate 		(void) bdev_strategy(bp);
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 		lwp_stat_update(LWP_STAT_OUBLK, 1);
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate 		if (err == 0)
18270Sstevel@tonic-gate 			err = biowait(bp);
18280Sstevel@tonic-gate 		else
18290Sstevel@tonic-gate 			(void) biowait(bp);
18300Sstevel@tonic-gate 		pageio_done(bp);
18310Sstevel@tonic-gate 	}
18320Sstevel@tonic-gate 	pvn_write_done(pp, ((err) ? B_ERROR : 0) | B_WRITE | flags);
18330Sstevel@tonic-gate 	pp = NULL;
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate out:
18360Sstevel@tonic-gate 	if ((fsp->pcfs_flags & PCFS_IRRECOV) && pp != NULL) {
18370Sstevel@tonic-gate 		pvn_write_done(pp, B_WRITE | flags);
18380Sstevel@tonic-gate 	} else if (err != 0 && pp != NULL) {
18390Sstevel@tonic-gate 		pvn_write_done(pp, B_ERROR | B_WRITE | flags);
18400Sstevel@tonic-gate 	}
18410Sstevel@tonic-gate 
18420Sstevel@tonic-gate 	if (offp)
18430Sstevel@tonic-gate 		*offp = io_off;
18440Sstevel@tonic-gate 	if (lenp)
18450Sstevel@tonic-gate 		*lenp = io_len;
18460Sstevel@tonic-gate 		PC_DPRINTF4(4, "pcfs_putapage: vp=%p pp=%p off=%lld len=%lu\n",
18470Sstevel@tonic-gate 		    (void *)vp, (void *)pp, io_off, io_len);
18480Sstevel@tonic-gate 	if (err) {
18490Sstevel@tonic-gate 		PC_DPRINTF1(1, "pcfs_putapage err=%d", err);
18500Sstevel@tonic-gate 	}
18510Sstevel@tonic-gate 	return (err);
18520Sstevel@tonic-gate }
18530Sstevel@tonic-gate 
18540Sstevel@tonic-gate /*ARGSUSED*/
18550Sstevel@tonic-gate static int
pcfs_map(struct vnode * vp,offset_t off,struct as * as,caddr_t * addrp,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)18560Sstevel@tonic-gate pcfs_map(
18570Sstevel@tonic-gate 	struct vnode *vp,
18580Sstevel@tonic-gate 	offset_t off,
18590Sstevel@tonic-gate 	struct as *as,
18600Sstevel@tonic-gate 	caddr_t *addrp,
18610Sstevel@tonic-gate 	size_t len,
18620Sstevel@tonic-gate 	uchar_t prot,
18630Sstevel@tonic-gate 	uchar_t maxprot,
18640Sstevel@tonic-gate 	uint_t flags,
18655331Samw 	struct cred *cr,
18665331Samw 	caller_context_t *ct)
18670Sstevel@tonic-gate {
18680Sstevel@tonic-gate 	struct segvn_crargs vn_a;
18690Sstevel@tonic-gate 	int error;
18700Sstevel@tonic-gate 
18710Sstevel@tonic-gate 	PC_DPRINTF0(6, "pcfs_map\n");
18720Sstevel@tonic-gate 	if (vp->v_flag & VNOMAP)
18730Sstevel@tonic-gate 		return (ENOSYS);
18740Sstevel@tonic-gate 
18750Sstevel@tonic-gate 	if (off > UINT32_MAX || off + len > UINT32_MAX)
18760Sstevel@tonic-gate 		return (ENXIO);
18770Sstevel@tonic-gate 
18780Sstevel@tonic-gate 	as_rangelock(as);
18796036Smec 	error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
18806036Smec 	if (error != 0) {
18816036Smec 		as_rangeunlock(as);
18826036Smec 		return (error);
18830Sstevel@tonic-gate 	}
18840Sstevel@tonic-gate 
18850Sstevel@tonic-gate 	vn_a.vp = vp;
18860Sstevel@tonic-gate 	vn_a.offset = off;
18870Sstevel@tonic-gate 	vn_a.type = flags & MAP_TYPE;
18880Sstevel@tonic-gate 	vn_a.prot = prot;
18890Sstevel@tonic-gate 	vn_a.maxprot = maxprot;
18900Sstevel@tonic-gate 	vn_a.flags = flags & ~MAP_TYPE;
18910Sstevel@tonic-gate 	vn_a.cred = cr;
18920Sstevel@tonic-gate 	vn_a.amp = NULL;
18930Sstevel@tonic-gate 	vn_a.szc = 0;
18940Sstevel@tonic-gate 	vn_a.lgrp_mem_policy_flags = 0;
18950Sstevel@tonic-gate 
18960Sstevel@tonic-gate 	error = as_map(as, *addrp, len, segvn_create, &vn_a);
18970Sstevel@tonic-gate 	as_rangeunlock(as);
18980Sstevel@tonic-gate 	return (error);
18990Sstevel@tonic-gate }
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate /* ARGSUSED */
19020Sstevel@tonic-gate static int
pcfs_seek(struct vnode * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)19030Sstevel@tonic-gate pcfs_seek(
19040Sstevel@tonic-gate 	struct vnode *vp,
19050Sstevel@tonic-gate 	offset_t ooff,
19065331Samw 	offset_t *noffp,
19075331Samw 	caller_context_t *ct)
19080Sstevel@tonic-gate {
19090Sstevel@tonic-gate 	if (*noffp < 0)
19100Sstevel@tonic-gate 		return (EINVAL);
19110Sstevel@tonic-gate 	else if (*noffp > MAXOFFSET_T)
19120Sstevel@tonic-gate 		return (EINVAL);
19130Sstevel@tonic-gate 	else
19140Sstevel@tonic-gate 		return (0);
19150Sstevel@tonic-gate }
19160Sstevel@tonic-gate 
19170Sstevel@tonic-gate /* ARGSUSED */
19180Sstevel@tonic-gate static int
pcfs_addmap(struct vnode * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)19190Sstevel@tonic-gate pcfs_addmap(
19200Sstevel@tonic-gate 	struct vnode *vp,
19210Sstevel@tonic-gate 	offset_t off,
19220Sstevel@tonic-gate 	struct as *as,
19230Sstevel@tonic-gate 	caddr_t addr,
19240Sstevel@tonic-gate 	size_t len,
19250Sstevel@tonic-gate 	uchar_t prot,
19260Sstevel@tonic-gate 	uchar_t maxprot,
19270Sstevel@tonic-gate 	uint_t flags,
19285331Samw 	struct cred *cr,
19295331Samw 	caller_context_t *ct)
19300Sstevel@tonic-gate {
19310Sstevel@tonic-gate 	if (vp->v_flag & VNOMAP)
19320Sstevel@tonic-gate 		return (ENOSYS);
19330Sstevel@tonic-gate 	return (0);
19340Sstevel@tonic-gate }
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate /*ARGSUSED*/
19370Sstevel@tonic-gate static int
pcfs_delmap(struct vnode * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uint_t prot,uint_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)19380Sstevel@tonic-gate pcfs_delmap(
19390Sstevel@tonic-gate 	struct vnode *vp,
19400Sstevel@tonic-gate 	offset_t off,
19410Sstevel@tonic-gate 	struct as *as,
19420Sstevel@tonic-gate 	caddr_t addr,
19430Sstevel@tonic-gate 	size_t len,
19440Sstevel@tonic-gate 	uint_t prot,
19450Sstevel@tonic-gate 	uint_t maxprot,
19460Sstevel@tonic-gate 	uint_t flags,
19475331Samw 	struct cred *cr,
19485331Samw 	caller_context_t *ct)
19490Sstevel@tonic-gate {
19500Sstevel@tonic-gate 	if (vp->v_flag & VNOMAP)
19510Sstevel@tonic-gate 		return (ENOSYS);
19520Sstevel@tonic-gate 	return (0);
19530Sstevel@tonic-gate }
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate /*
19560Sstevel@tonic-gate  * POSIX pathconf() support.
19570Sstevel@tonic-gate  */
19580Sstevel@tonic-gate /* ARGSUSED */
19590Sstevel@tonic-gate static int
pcfs_pathconf(struct vnode * vp,int cmd,ulong_t * valp,struct cred * cr,caller_context_t * ct)19600Sstevel@tonic-gate pcfs_pathconf(
19610Sstevel@tonic-gate 	struct vnode *vp,
19620Sstevel@tonic-gate 	int cmd,
19630Sstevel@tonic-gate 	ulong_t *valp,
19645331Samw 	struct cred *cr,
19655331Samw 	caller_context_t *ct)
19660Sstevel@tonic-gate {
19670Sstevel@tonic-gate 	struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
19680Sstevel@tonic-gate 
19690Sstevel@tonic-gate 	switch (cmd) {
19700Sstevel@tonic-gate 	case _PC_LINK_MAX:
19716971Sbatschul 		*valp = 1;
19726971Sbatschul 		return (0);
19730Sstevel@tonic-gate 
19746971Sbatschul 	case _PC_CASE_BEHAVIOR:
19756971Sbatschul 		return (EINVAL);
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate 	case _PC_FILESIZEBITS:
19780Sstevel@tonic-gate 		/*
19790Sstevel@tonic-gate 		 * Both FAT16 and FAT32 support 4GB - 1 byte for file size.
19800Sstevel@tonic-gate 		 * FAT12 can only go up to the maximum filesystem capacity
19810Sstevel@tonic-gate 		 * which is ~509MB.
19820Sstevel@tonic-gate 		 */
19836971Sbatschul 		*valp = IS_FAT12(fsp) ? 30 : 33;
19846971Sbatschul 		return (0);
19856971Sbatschul 
1986*10440SRoger.Faulkner@Sun.COM 	case _PC_TIMESTAMP_RESOLUTION:
1987*10440SRoger.Faulkner@Sun.COM 		/*
1988*10440SRoger.Faulkner@Sun.COM 		 * PCFS keeps track of modification times, it its own
1989*10440SRoger.Faulkner@Sun.COM 		 * internal format, to a resolution of 2 seconds.
1990*10440SRoger.Faulkner@Sun.COM 		 * Since 2000 million is representable in an int32_t
1991*10440SRoger.Faulkner@Sun.COM 		 * without overflow (or becoming negative), we allow
1992*10440SRoger.Faulkner@Sun.COM 		 * this value to be returned.
1993*10440SRoger.Faulkner@Sun.COM 		 */
1994*10440SRoger.Faulkner@Sun.COM 		*valp = 2000000000L;
1995*10440SRoger.Faulkner@Sun.COM 		return (0);
1996*10440SRoger.Faulkner@Sun.COM 
19970Sstevel@tonic-gate 	default:
19986971Sbatschul 		return (fs_pathconf(vp, cmd, valp, cr, ct));
19990Sstevel@tonic-gate 	}
20000Sstevel@tonic-gate 
20010Sstevel@tonic-gate }
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate /* ARGSUSED */
20040Sstevel@tonic-gate static int
pcfs_space(struct vnode * vp,int cmd,struct flock64 * bfp,int flag,offset_t offset,cred_t * cr,caller_context_t * ct)20050Sstevel@tonic-gate pcfs_space(
20060Sstevel@tonic-gate 	struct vnode *vp,
20070Sstevel@tonic-gate 	int cmd,
20080Sstevel@tonic-gate 	struct flock64 *bfp,
20090Sstevel@tonic-gate 	int flag,
20100Sstevel@tonic-gate 	offset_t offset,
20110Sstevel@tonic-gate 	cred_t *cr,
20120Sstevel@tonic-gate 	caller_context_t *ct)
20130Sstevel@tonic-gate {
20140Sstevel@tonic-gate 	struct vattr vattr;
20150Sstevel@tonic-gate 	int error;
20160Sstevel@tonic-gate 
20170Sstevel@tonic-gate 	if (cmd != F_FREESP)
20180Sstevel@tonic-gate 		return (EINVAL);
20190Sstevel@tonic-gate 
20200Sstevel@tonic-gate 	if ((error = convoff(vp, bfp, 0, offset)) == 0) {
20210Sstevel@tonic-gate 		if ((bfp->l_start > UINT32_MAX) || (bfp->l_len > UINT32_MAX))
20220Sstevel@tonic-gate 			return (EFBIG);
20230Sstevel@tonic-gate 		/*
20240Sstevel@tonic-gate 		 * we only support the special case of l_len == 0,
20250Sstevel@tonic-gate 		 * meaning free to end of file at this moment.
20260Sstevel@tonic-gate 		 */
20270Sstevel@tonic-gate 		if (bfp->l_len != 0)
20280Sstevel@tonic-gate 			return (EINVAL);
20290Sstevel@tonic-gate 		vattr.va_mask = AT_SIZE;
20300Sstevel@tonic-gate 		vattr.va_size = bfp->l_start;
20315331Samw 		error = VOP_SETATTR(vp, (vattr_t *)&vattr, 0, cr, ct);
20320Sstevel@tonic-gate 	}
20330Sstevel@tonic-gate 	return (error);
20340Sstevel@tonic-gate }
20350Sstevel@tonic-gate 
20360Sstevel@tonic-gate /*
20370Sstevel@tonic-gate  * Break up 'len' chars from 'buf' into a long file name chunk.
20380Sstevel@tonic-gate  * Pad with '0xff' to make Norton Disk Doctor and Microsoft ScanDisk happy.
20390Sstevel@tonic-gate  */
20400Sstevel@tonic-gate void
set_long_fn_chunk(struct pcdir_lfn * ep,char * buf,int len)20410Sstevel@tonic-gate set_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int len)
20420Sstevel@tonic-gate {
20430Sstevel@tonic-gate 	int	i;
20440Sstevel@tonic-gate 
20454723Sksn 	ASSERT(buf != NULL);
20460Sstevel@tonic-gate 
20470Sstevel@tonic-gate 	for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2) {
20480Sstevel@tonic-gate 		if (len > 0) {
20494723Sksn 			ep->pcdl_firstfilename[i] = *buf++;
20504723Sksn 			ep->pcdl_firstfilename[i + 1] = *buf++;
20514723Sksn 			len -= 2;
20520Sstevel@tonic-gate 		} else {
20530Sstevel@tonic-gate 			ep->pcdl_firstfilename[i] = (uchar_t)0xff;
20544723Sksn 			ep->pcdl_firstfilename[i + 1] = (uchar_t)0xff;
20550Sstevel@tonic-gate 		}
20560Sstevel@tonic-gate 	}
20570Sstevel@tonic-gate 
20580Sstevel@tonic-gate 	for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2) {
20590Sstevel@tonic-gate 		if (len > 0) {
20604723Sksn 			ep->pcdl_secondfilename[i] = *buf++;
20614723Sksn 			ep->pcdl_secondfilename[i + 1] = *buf++;
20624723Sksn 			len -= 2;
20630Sstevel@tonic-gate 		} else {
20640Sstevel@tonic-gate 			ep->pcdl_secondfilename[i] = (uchar_t)0xff;
20654723Sksn 			ep->pcdl_secondfilename[i + 1] = (uchar_t)0xff;
20660Sstevel@tonic-gate 		}
20670Sstevel@tonic-gate 	}
20680Sstevel@tonic-gate 	for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2) {
20690Sstevel@tonic-gate 		if (len > 0) {
20704723Sksn 			ep->pcdl_thirdfilename[i] = *buf++;
20714723Sksn 			ep->pcdl_thirdfilename[i + 1] = *buf++;
20724723Sksn 			len -= 2;
20730Sstevel@tonic-gate 		} else {
20740Sstevel@tonic-gate 			ep->pcdl_thirdfilename[i] = (uchar_t)0xff;
20754723Sksn 			ep->pcdl_thirdfilename[i + 1] = (uchar_t)0xff;
20760Sstevel@tonic-gate 		}
20770Sstevel@tonic-gate 	}
20780Sstevel@tonic-gate }
20790Sstevel@tonic-gate 
20800Sstevel@tonic-gate /*
20810Sstevel@tonic-gate  * Extract the characters from the long filename chunk into 'buf'.
20820Sstevel@tonic-gate  * Return the number of characters extracted.
20830Sstevel@tonic-gate  */
20840Sstevel@tonic-gate static int
get_long_fn_chunk(struct pcdir_lfn * ep,char * buf)20857735SOwen.Roberts@Sun.Com get_long_fn_chunk(struct pcdir_lfn *ep, char *buf)
20860Sstevel@tonic-gate {
20870Sstevel@tonic-gate 	char 	*tmp = buf;
20880Sstevel@tonic-gate 	int	i;
20890Sstevel@tonic-gate 
20904723Sksn 	/* Copy all the names, no filtering now */
20914723Sksn 
20924723Sksn 	for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2, tmp += 2) {
20934723Sksn 		*tmp = ep->pcdl_firstfilename[i];
20944723Sksn 		*(tmp + 1) = ep->pcdl_firstfilename[i + 1];
20954723Sksn 
20964723Sksn 		if ((*tmp == '\0') && (*(tmp+1) == '\0'))
20970Sstevel@tonic-gate 			return (tmp - buf);
20980Sstevel@tonic-gate 	}
20994723Sksn 	for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2, tmp += 2) {
21004723Sksn 		*tmp = ep->pcdl_secondfilename[i];
21014723Sksn 		*(tmp + 1) = ep->pcdl_secondfilename[i + 1];
21024723Sksn 
21034723Sksn 		if ((*tmp == '\0') && (*(tmp+1) == '\0'))
21040Sstevel@tonic-gate 			return (tmp - buf);
21050Sstevel@tonic-gate 	}
21064723Sksn 	for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2, tmp += 2) {
21074723Sksn 		*tmp = ep->pcdl_thirdfilename[i];
21084723Sksn 		*(tmp + 1) = ep->pcdl_thirdfilename[i + 1];
21094723Sksn 
21104723Sksn 		if ((*tmp == '\0') && (*(tmp+1) == '\0'))
21110Sstevel@tonic-gate 			return (tmp - buf);
21120Sstevel@tonic-gate 	}
21130Sstevel@tonic-gate 	return (tmp - buf);
21140Sstevel@tonic-gate }
21150Sstevel@tonic-gate 
21160Sstevel@tonic-gate 
21170Sstevel@tonic-gate /*
21180Sstevel@tonic-gate  * Checksum the passed in short filename.
21190Sstevel@tonic-gate  * This is used to validate each component of the long name to make
21200Sstevel@tonic-gate  * sure the long name is valid (it hasn't been "detached" from the
21210Sstevel@tonic-gate  * short filename). This algorithm was found in FreeBSD.
21220Sstevel@tonic-gate  * (sys/fs/msdosfs/msdosfs_conv.c:winChksum(), Wolfgang Solfrank)
21230Sstevel@tonic-gate  */
21240Sstevel@tonic-gate 
21250Sstevel@tonic-gate uchar_t
pc_checksum_long_fn(char * name,char * ext)21260Sstevel@tonic-gate pc_checksum_long_fn(char *name, char *ext)
21270Sstevel@tonic-gate {
21280Sstevel@tonic-gate 	uchar_t c;
21290Sstevel@tonic-gate 	char	b[11];
21300Sstevel@tonic-gate 
21310Sstevel@tonic-gate 	bcopy(name, b, 8);
21320Sstevel@tonic-gate 	bcopy(ext, b+8, 3);
21330Sstevel@tonic-gate 
21340Sstevel@tonic-gate 	c = b[0];
21350Sstevel@tonic-gate 	c = ((c << 7) | (c >> 1)) + b[1];
21360Sstevel@tonic-gate 	c = ((c << 7) | (c >> 1)) + b[2];
21370Sstevel@tonic-gate 	c = ((c << 7) | (c >> 1)) + b[3];
21380Sstevel@tonic-gate 	c = ((c << 7) | (c >> 1)) + b[4];
21390Sstevel@tonic-gate 	c = ((c << 7) | (c >> 1)) + b[5];
21400Sstevel@tonic-gate 	c = ((c << 7) | (c >> 1)) + b[6];
21410Sstevel@tonic-gate 	c = ((c << 7) | (c >> 1)) + b[7];
21420Sstevel@tonic-gate 	c = ((c << 7) | (c >> 1)) + b[8];
21430Sstevel@tonic-gate 	c = ((c << 7) | (c >> 1)) + b[9];
21440Sstevel@tonic-gate 	c = ((c << 7) | (c >> 1)) + b[10];
21450Sstevel@tonic-gate 
21460Sstevel@tonic-gate 	return (c);
21470Sstevel@tonic-gate }
21480Sstevel@tonic-gate 
21490Sstevel@tonic-gate /*
21500Sstevel@tonic-gate  * Read a chunk of long filename entries into 'namep'.
21510Sstevel@tonic-gate  * Return with offset pointing to short entry (on success), or next
21520Sstevel@tonic-gate  * entry to read (if this wasn't a valid lfn really).
21530Sstevel@tonic-gate  * Uses the passed-in buffer if it can, otherwise kmem_allocs() room for
21540Sstevel@tonic-gate  * a long filename.
21550Sstevel@tonic-gate  *
21560Sstevel@tonic-gate  * Can also be called with a NULL namep, in which case it just returns
21570Sstevel@tonic-gate  * whether this was really a valid long filename and consumes it
21580Sstevel@tonic-gate  * (used by pc_dirempty()).
21590Sstevel@tonic-gate  */
21600Sstevel@tonic-gate int
pc_extract_long_fn(struct pcnode * pcp,char * namep,struct pcdir ** epp,offset_t * offset,struct buf ** bp)21610Sstevel@tonic-gate pc_extract_long_fn(struct pcnode *pcp, char *namep,
21620Sstevel@tonic-gate     struct pcdir **epp, offset_t *offset, struct buf **bp)
21630Sstevel@tonic-gate {
21640Sstevel@tonic-gate 	struct pcdir *ep = *epp;
21650Sstevel@tonic-gate 	struct pcdir_lfn *lep = (struct pcdir_lfn *)ep;
21660Sstevel@tonic-gate 	struct vnode *dvp = PCTOV(pcp);
21670Sstevel@tonic-gate 	struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
21680Sstevel@tonic-gate 	char	*lfn;
21690Sstevel@tonic-gate 	char	*lfn_base;
21700Sstevel@tonic-gate 	int	boff;
21710Sstevel@tonic-gate 	int	i, cs;
21725121Sfrankho 	char	*buf;
21730Sstevel@tonic-gate 	uchar_t	cksum;
21745121Sfrankho 	int	detached = 0;
21750Sstevel@tonic-gate 	int	error = 0;
21760Sstevel@tonic-gate 	int	foldcase;
21774723Sksn 	int	count = 0;
21785121Sfrankho 	size_t	u16l = 0, u8l = 0;
21797735SOwen.Roberts@Sun.Com 	char	*outbuf;
21807735SOwen.Roberts@Sun.Com 	size_t	ret, inlen, outlen;
21810Sstevel@tonic-gate 
21820Sstevel@tonic-gate 	foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE);
21834723Sksn 	lfn_base = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP);
21844723Sksn 	lfn = lfn_base + PCMAXNAM_UTF16 - sizeof (uint16_t);
21850Sstevel@tonic-gate 	*lfn = '\0';
21864723Sksn 	*(lfn + 1) = '\0';
21870Sstevel@tonic-gate 	cksum = lep->pcdl_checksum;
21880Sstevel@tonic-gate 
21894723Sksn 	buf = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP);
21900Sstevel@tonic-gate 	for (i = (lep->pcdl_ordinal & ~0xc0); i > 0; i--) {
21910Sstevel@tonic-gate 		/* read next block if necessary */
21920Sstevel@tonic-gate 		boff = pc_blkoff(fsp, *offset);
21930Sstevel@tonic-gate 		if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) {
21940Sstevel@tonic-gate 			if (*bp != NULL) {
21950Sstevel@tonic-gate 				brelse(*bp);
21960Sstevel@tonic-gate 				*bp = NULL;
21970Sstevel@tonic-gate 			}
21980Sstevel@tonic-gate 			error = pc_blkatoff(pcp, *offset, bp, &ep);
21990Sstevel@tonic-gate 			if (error) {
22004723Sksn 				kmem_free(lfn_base, PCMAXNAM_UTF16);
22014723Sksn 				kmem_free(buf, PCMAXNAM_UTF16);
22020Sstevel@tonic-gate 				return (error);
22030Sstevel@tonic-gate 			}
22040Sstevel@tonic-gate 			lep = (struct pcdir_lfn *)ep;
22050Sstevel@tonic-gate 		}
22060Sstevel@tonic-gate 		/* can this happen? Bad fs? */
22070Sstevel@tonic-gate 		if (!PCDL_IS_LFN((struct pcdir *)lep)) {
22080Sstevel@tonic-gate 			detached = 1;
22090Sstevel@tonic-gate 			break;
22100Sstevel@tonic-gate 		}
22110Sstevel@tonic-gate 		if (cksum != lep->pcdl_checksum)
22120Sstevel@tonic-gate 			detached = 1;
22130Sstevel@tonic-gate 		/* process current entry */
22147735SOwen.Roberts@Sun.Com 		cs = get_long_fn_chunk(lep, buf);
22154723Sksn 		count += cs;
22164723Sksn 		for (; cs > 0; cs--) {
22174723Sksn 			/* see if we underflow */
22184723Sksn 			if (lfn >= lfn_base)
22194723Sksn 				*--lfn = buf[cs - 1];
22204723Sksn 			else
22214723Sksn 				detached = 1;
22220Sstevel@tonic-gate 		}
22230Sstevel@tonic-gate 		lep++;
22240Sstevel@tonic-gate 		*offset += sizeof (struct pcdir);
22250Sstevel@tonic-gate 	}
22264723Sksn 	kmem_free(buf, PCMAXNAM_UTF16);
22270Sstevel@tonic-gate 	/* read next block if necessary */
22280Sstevel@tonic-gate 	boff = pc_blkoff(fsp, *offset);
22290Sstevel@tonic-gate 	ep = (struct pcdir *)lep;
22300Sstevel@tonic-gate 	if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) {
22310Sstevel@tonic-gate 		if (*bp != NULL) {
22320Sstevel@tonic-gate 			brelse(*bp);
22330Sstevel@tonic-gate 			*bp = NULL;
22340Sstevel@tonic-gate 		}
22350Sstevel@tonic-gate 		error = pc_blkatoff(pcp, *offset, bp, &ep);
22360Sstevel@tonic-gate 		if (error) {
22374723Sksn 			kmem_free(lfn_base, PCMAXNAM_UTF16);
22380Sstevel@tonic-gate 			return (error);
22390Sstevel@tonic-gate 		}
22400Sstevel@tonic-gate 	}
22410Sstevel@tonic-gate 	/* should be on the short one */
22420Sstevel@tonic-gate 	if (PCDL_IS_LFN(ep) || ((ep->pcd_filename[0] == PCD_UNUSED) ||
22430Sstevel@tonic-gate 	    (ep->pcd_filename[0] == PCD_ERASED))) {
22440Sstevel@tonic-gate 		detached = 1;
22450Sstevel@tonic-gate 	}
22460Sstevel@tonic-gate 	if (detached ||
22470Sstevel@tonic-gate 	    (cksum != pc_checksum_long_fn(ep->pcd_filename, ep->pcd_ext)) ||
22484723Sksn 	    !pc_valid_long_fn(lfn, 0)) {
22490Sstevel@tonic-gate 		/*
22500Sstevel@tonic-gate 		 * process current entry again. This may end up another lfn
22510Sstevel@tonic-gate 		 * or a short name.
22520Sstevel@tonic-gate 		 */
22530Sstevel@tonic-gate 		*epp = ep;
22544723Sksn 		kmem_free(lfn_base, PCMAXNAM_UTF16);
22550Sstevel@tonic-gate 		return (EINVAL);
22560Sstevel@tonic-gate 	}
22570Sstevel@tonic-gate 	if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) {
22580Sstevel@tonic-gate 		/*
22590Sstevel@tonic-gate 		 * Don't display label because it may contain
22600Sstevel@tonic-gate 		 * funny characters.
22610Sstevel@tonic-gate 		 */
22620Sstevel@tonic-gate 		*offset += sizeof (struct pcdir);
22630Sstevel@tonic-gate 		ep++;
22640Sstevel@tonic-gate 		*epp = ep;
22654723Sksn 		kmem_free(lfn_base, PCMAXNAM_UTF16);
22660Sstevel@tonic-gate 		return (EINVAL);
22670Sstevel@tonic-gate 	}
22680Sstevel@tonic-gate 	if (namep) {
22694723Sksn 		u16l = count / 2;
22704723Sksn 		u8l = PCMAXNAMLEN;
22714723Sksn 		error = uconv_u16tou8((const uint16_t *)lfn, &u16l,
22724723Sksn 		    (uchar_t *)namep, &u8l, UCONV_IN_LITTLE_ENDIAN);
22734723Sksn 		/*
22744723Sksn 		 * uconv_u16tou8() will catch conversion errors including
22754723Sksn 		 * the case where there is not enough room to write the
22764723Sksn 		 * converted result and the u8l will never go over the given
22774723Sksn 		 * PCMAXNAMLEN.
22784723Sksn 		 */
22794723Sksn 		if (error != 0) {
22804723Sksn 			kmem_free(lfn_base, PCMAXNAM_UTF16);
22814723Sksn 			return (EINVAL);
22824723Sksn 		}
22834723Sksn 		namep[u8l] = '\0';
22847735SOwen.Roberts@Sun.Com 		if (foldcase) {
22857735SOwen.Roberts@Sun.Com 			inlen = strlen(namep);
22867735SOwen.Roberts@Sun.Com 			outlen = PCMAXNAMLEN;
22877735SOwen.Roberts@Sun.Com 			outbuf = kmem_alloc(PCMAXNAMLEN + 1, KM_SLEEP);
22887735SOwen.Roberts@Sun.Com 			ret = u8_textprep_str(namep, &inlen, outbuf,
22897735SOwen.Roberts@Sun.Com 			    &outlen, U8_TEXTPREP_TOLOWER, U8_UNICODE_LATEST,
22907735SOwen.Roberts@Sun.Com 			    &error);
22917735SOwen.Roberts@Sun.Com 			if (ret == -1) {
22927735SOwen.Roberts@Sun.Com 				kmem_free(outbuf, PCMAXNAMLEN + 1);
22937735SOwen.Roberts@Sun.Com 				kmem_free(lfn_base, PCMAXNAM_UTF16);
22947735SOwen.Roberts@Sun.Com 				return (EINVAL);
22957735SOwen.Roberts@Sun.Com 			}
22967735SOwen.Roberts@Sun.Com 			outbuf[PCMAXNAMLEN - outlen] = '\0';
22977735SOwen.Roberts@Sun.Com 			(void) strncpy(namep, outbuf, PCMAXNAMLEN + 1);
22987735SOwen.Roberts@Sun.Com 			kmem_free(outbuf, PCMAXNAMLEN + 1);
22997735SOwen.Roberts@Sun.Com 		}
23000Sstevel@tonic-gate 	}
23014723Sksn 	kmem_free(lfn_base, PCMAXNAM_UTF16);
23020Sstevel@tonic-gate 	*epp = ep;
23030Sstevel@tonic-gate 	return (0);
23040Sstevel@tonic-gate }
23050Sstevel@tonic-gate /*
23060Sstevel@tonic-gate  * Read a long filename into the pc_dirent structure and copy it out.
23070Sstevel@tonic-gate  */
23080Sstevel@tonic-gate int
pc_read_long_fn(struct vnode * dvp,struct uio * uiop,struct pc_dirent * ld,struct pcdir ** epp,offset_t * offset,struct buf ** bp)23090Sstevel@tonic-gate pc_read_long_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld,
23100Sstevel@tonic-gate     struct pcdir **epp, offset_t *offset, struct buf **bp)
23110Sstevel@tonic-gate {
23120Sstevel@tonic-gate 	struct pcdir *ep;
23130Sstevel@tonic-gate 	struct pcnode *pcp = VTOPC(dvp);
23140Sstevel@tonic-gate 	struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
23150Sstevel@tonic-gate 	offset_t uiooffset = uiop->uio_loffset;
23160Sstevel@tonic-gate 	int	error = 0;
23170Sstevel@tonic-gate 	offset_t oldoffset;
23180Sstevel@tonic-gate 
23190Sstevel@tonic-gate 	oldoffset = *offset;
23200Sstevel@tonic-gate 	error = pc_extract_long_fn(pcp, ld->d_name, epp, offset, bp);
23210Sstevel@tonic-gate 	if (error) {
23220Sstevel@tonic-gate 		if (error == EINVAL) {
23230Sstevel@tonic-gate 			uiop->uio_loffset += *offset - oldoffset;
23240Sstevel@tonic-gate 			return (0);
23250Sstevel@tonic-gate 		} else
23260Sstevel@tonic-gate 			return (error);
23270Sstevel@tonic-gate 	}
23280Sstevel@tonic-gate 
23290Sstevel@tonic-gate 	ep = *epp;
23300Sstevel@tonic-gate 	uiop->uio_loffset += *offset - oldoffset;
23310Sstevel@tonic-gate 	ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name));
23320Sstevel@tonic-gate 	if (ld->d_reclen > uiop->uio_resid) {
23330Sstevel@tonic-gate 		uiop->uio_loffset = uiooffset;
23340Sstevel@tonic-gate 		return (ENOSPC);
23350Sstevel@tonic-gate 	}
23360Sstevel@tonic-gate 	ld->d_off = uiop->uio_loffset + sizeof (struct pcdir);
23370Sstevel@tonic-gate 	ld->d_ino = pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno),
23380Sstevel@tonic-gate 	    pc_blkoff(fsp, *offset), ep->pcd_attr,
23395121Sfrankho 	    pc_getstartcluster(fsp, ep), pc_direntpersec(fsp));
23400Sstevel@tonic-gate 	(void) uiomove((caddr_t)ld, ld->d_reclen, UIO_READ, uiop);
23410Sstevel@tonic-gate 	uiop->uio_loffset = ld->d_off;
23420Sstevel@tonic-gate 	*offset += sizeof (struct pcdir);
23430Sstevel@tonic-gate 	ep++;
23440Sstevel@tonic-gate 	*epp = ep;
23450Sstevel@tonic-gate 	return (0);
23460Sstevel@tonic-gate }
23470Sstevel@tonic-gate 
23480Sstevel@tonic-gate /*
23490Sstevel@tonic-gate  * Read a short filename into the pc_dirent structure and copy it out.
23500Sstevel@tonic-gate  */
23510Sstevel@tonic-gate int
pc_read_short_fn(struct vnode * dvp,struct uio * uiop,struct pc_dirent * ld,struct pcdir ** epp,offset_t * offset,struct buf ** bp)23520Sstevel@tonic-gate pc_read_short_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld,
23530Sstevel@tonic-gate     struct pcdir **epp, offset_t *offset, struct buf **bp)
23540Sstevel@tonic-gate {
23550Sstevel@tonic-gate 	struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
23560Sstevel@tonic-gate 	int	boff = pc_blkoff(fsp, *offset);
23570Sstevel@tonic-gate 	struct pcdir *ep = *epp;
23580Sstevel@tonic-gate 	offset_t	oldoffset = uiop->uio_loffset;
23590Sstevel@tonic-gate 	int	error;
23600Sstevel@tonic-gate 	int	foldcase;
23610Sstevel@tonic-gate 
23620Sstevel@tonic-gate 	if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) {
23630Sstevel@tonic-gate 		uiop->uio_loffset += sizeof (struct pcdir);
23640Sstevel@tonic-gate 		*offset += sizeof (struct pcdir);
23650Sstevel@tonic-gate 		ep++;
23660Sstevel@tonic-gate 		*epp = ep;
23670Sstevel@tonic-gate 		return (0);
23680Sstevel@tonic-gate 	}
23690Sstevel@tonic-gate 	ld->d_ino = (ino64_t)pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno),
23705121Sfrankho 	    boff, ep->pcd_attr, pc_getstartcluster(fsp, ep),
23715121Sfrankho 	    pc_direntpersec(fsp));
23720Sstevel@tonic-gate 	foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE);
23730Sstevel@tonic-gate 	error = pc_fname_ext_to_name(&ld->d_name[0], &ep->pcd_filename[0],
23740Sstevel@tonic-gate 	    &ep->pcd_ext[0], foldcase);
23750Sstevel@tonic-gate 	if (error == 0) {
23760Sstevel@tonic-gate 		ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name));
23770Sstevel@tonic-gate 		if (ld->d_reclen > uiop->uio_resid) {
23780Sstevel@tonic-gate 			uiop->uio_loffset = oldoffset;
23790Sstevel@tonic-gate 			return (ENOSPC);
23800Sstevel@tonic-gate 		}
23810Sstevel@tonic-gate 		ld->d_off = (off64_t)(uiop->uio_loffset +
23820Sstevel@tonic-gate 		    sizeof (struct pcdir));
23830Sstevel@tonic-gate 		(void) uiomove((caddr_t)ld,
23840Sstevel@tonic-gate 		    ld->d_reclen, UIO_READ, uiop);
23850Sstevel@tonic-gate 		uiop->uio_loffset = ld->d_off;
23860Sstevel@tonic-gate 	} else {
23870Sstevel@tonic-gate 		uiop->uio_loffset += sizeof (struct pcdir);
23880Sstevel@tonic-gate 	}
23890Sstevel@tonic-gate 	*offset += sizeof (struct pcdir);
23900Sstevel@tonic-gate 	ep++;
23910Sstevel@tonic-gate 	*epp = ep;
23920Sstevel@tonic-gate 	return (0);
23930Sstevel@tonic-gate }
23940Sstevel@tonic-gate 
23955331Samw /* ARGSUSED */
23960Sstevel@tonic-gate static int
pcfs_fid(struct vnode * vp,struct fid * fidp,caller_context_t * ct)23975331Samw pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
23980Sstevel@tonic-gate {
23990Sstevel@tonic-gate 	struct pc_fid *pcfid;
24000Sstevel@tonic-gate 	struct pcnode *pcp;
24010Sstevel@tonic-gate 	struct pcfs	*fsp;
24020Sstevel@tonic-gate 	int	error;
24030Sstevel@tonic-gate 
24040Sstevel@tonic-gate 	fsp = VFSTOPCFS(vp->v_vfsp);
24050Sstevel@tonic-gate 	if (fsp == NULL)
24060Sstevel@tonic-gate 		return (EIO);
24070Sstevel@tonic-gate 	error = pc_lockfs(fsp, 0, 0);
24080Sstevel@tonic-gate 	if (error)
24090Sstevel@tonic-gate 		return (error);
24102972Sfrankho 	if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
24110Sstevel@tonic-gate 		pc_unlockfs(fsp);
24120Sstevel@tonic-gate 		return (EIO);
24130Sstevel@tonic-gate 	}
24140Sstevel@tonic-gate 	if (fidp->fid_len < (sizeof (struct pc_fid) - sizeof (ushort_t))) {
24150Sstevel@tonic-gate 		fidp->fid_len = sizeof (struct pc_fid) - sizeof (ushort_t);
24160Sstevel@tonic-gate 		pc_unlockfs(fsp);
24170Sstevel@tonic-gate 		return (ENOSPC);
24180Sstevel@tonic-gate 	}
24190Sstevel@tonic-gate 
24200Sstevel@tonic-gate 	pcfid = (struct pc_fid *)fidp;
24210Sstevel@tonic-gate 	bzero(pcfid, sizeof (struct pc_fid));
24220Sstevel@tonic-gate 	pcfid->pcfid_len = sizeof (struct pc_fid) - sizeof (ushort_t);
24230Sstevel@tonic-gate 	if (vp->v_flag & VROOT) {
24240Sstevel@tonic-gate 		pcfid->pcfid_block = 0;
24250Sstevel@tonic-gate 		pcfid->pcfid_offset = 0;
24260Sstevel@tonic-gate 		pcfid->pcfid_ctime = 0;
24270Sstevel@tonic-gate 	} else {
24280Sstevel@tonic-gate 		pcfid->pcfid_block = pcp->pc_eblkno;
24290Sstevel@tonic-gate 		pcfid->pcfid_offset = pcp->pc_eoffset;
24300Sstevel@tonic-gate 		pcfid->pcfid_ctime = pcp->pc_entry.pcd_crtime.pct_time;
24310Sstevel@tonic-gate 	}
24320Sstevel@tonic-gate 	pc_unlockfs(fsp);
24330Sstevel@tonic-gate 	return (0);
24340Sstevel@tonic-gate }
2435