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