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