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