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