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