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