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