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