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