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