drop net-snmp dep
[unleashed.git] / kernel / fs / pcfs / pc_vnops.c
blobc3f30c89dccd9c6c67c51ffc4254df4675ca6ad8
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
29 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
30 * Copyright (c) 2017 by Delphix. All rights reserved.
33 #include <sys/param.h>
34 #include <sys/t_lock.h>
35 #include <sys/systm.h>
36 #include <sys/sysmacros.h>
37 #include <sys/user.h>
38 #include <sys/buf.h>
39 #include <sys/stat.h>
40 #include <sys/vfs.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>
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>
76 #include <sys/fs_subr.h>
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 *, uoff_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 *);
130 int pcfs_putapage(struct vnode *, page_t *, uoff_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);
135 extern krwlock_t pcnodes_lock;
137 #define lround(r) (((r)+sizeof (long long)-1)&(~(sizeof (long long)-1)))
140 * vnode op vectors for files and directories.
142 const struct vnodeops pcfs_fvnodeops = {
143 .vnop_name = "pcfs",
144 .vop_open = pcfs_open,
145 .vop_close = pcfs_close,
146 .vop_read = pcfs_read,
147 .vop_write = pcfs_write,
148 .vop_getattr = pcfs_getattr,
149 .vop_setattr = pcfs_setattr,
150 .vop_access = pcfs_access,
151 .vop_fsync = pcfs_fsync,
152 .vop_inactive = pcfs_inactive,
153 .vop_fid = pcfs_fid,
154 .vop_seek = pcfs_seek,
155 .vop_space = pcfs_space,
156 .vop_getpage = pcfs_getpage,
157 .vop_putpage = pcfs_putpage,
158 .vop_map = pcfs_map,
159 .vop_addmap = pcfs_addmap,
160 .vop_delmap = pcfs_delmap,
161 .vop_pathconf = pcfs_pathconf,
162 .vop_vnevent = fs_vnevent_support,
165 const struct vnodeops pcfs_dvnodeops = {
166 .vnop_name = "pcfs",
167 .vop_open = pcfs_open,
168 .vop_close = pcfs_close,
169 .vop_getattr = pcfs_getattr,
170 .vop_setattr = pcfs_setattr,
171 .vop_access = pcfs_access,
172 .vop_lookup = pcfs_lookup,
173 .vop_create = pcfs_create,
174 .vop_remove = pcfs_remove,
175 .vop_rename = pcfs_rename,
176 .vop_mkdir = pcfs_mkdir,
177 .vop_rmdir = pcfs_rmdir,
178 .vop_readdir = pcfs_readdir,
179 .vop_fsync = pcfs_fsync,
180 .vop_inactive = pcfs_inactive,
181 .vop_fid = pcfs_fid,
182 .vop_seek = pcfs_seek,
183 .vop_pathconf = pcfs_pathconf,
184 .vop_vnevent = fs_vnevent_support,
188 /*ARGSUSED*/
189 static int
190 pcfs_open(
191 struct vnode **vpp,
192 int flag,
193 struct cred *cr,
194 caller_context_t *ct)
196 return (0);
200 * files are sync'ed on close to keep floppy up to date
203 /*ARGSUSED*/
204 static int
205 pcfs_close(
206 struct vnode *vp,
207 int flag,
208 int count,
209 offset_t offset,
210 struct cred *cr,
211 caller_context_t *ct)
213 return (0);
216 /*ARGSUSED*/
217 static int
218 pcfs_read(
219 struct vnode *vp,
220 struct uio *uiop,
221 int ioflag,
222 struct cred *cr,
223 struct caller_context *ct)
225 struct pcfs *fsp;
226 struct pcnode *pcp;
227 int error;
229 fsp = VFSTOPCFS(vp->v_vfsp);
230 if (error = pc_verify(fsp))
231 return (error);
232 error = pc_lockfs(fsp, 0, 0);
233 if (error)
234 return (error);
235 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
236 pc_unlockfs(fsp);
237 return (EIO);
239 error = rwpcp(pcp, uiop, UIO_READ, ioflag);
240 if ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0) {
241 pc_mark_acc(fsp, pcp);
243 pc_unlockfs(fsp);
244 if (error) {
245 PC_DPRINTF1(1, "pcfs_read: io error = %d\n", error);
247 return (error);
250 /*ARGSUSED*/
251 static int
252 pcfs_write(
253 struct vnode *vp,
254 struct uio *uiop,
255 int ioflag,
256 struct cred *cr,
257 struct caller_context *ct)
259 struct pcfs *fsp;
260 struct pcnode *pcp;
261 int error;
263 fsp = VFSTOPCFS(vp->v_vfsp);
264 if (error = pc_verify(fsp))
265 return (error);
266 error = pc_lockfs(fsp, 0, 0);
267 if (error)
268 return (error);
269 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
270 pc_unlockfs(fsp);
271 return (EIO);
273 if (ioflag & FAPPEND) {
275 * in append mode start at end of file.
277 uiop->uio_loffset = pcp->pc_size;
279 error = rwpcp(pcp, uiop, UIO_WRITE, ioflag);
280 pcp->pc_flags |= PC_MOD;
281 pc_mark_mod(fsp, pcp);
282 if (ioflag & (FSYNC|FDSYNC))
283 (void) pc_nodeupdate(pcp);
285 pc_unlockfs(fsp);
286 if (error) {
287 PC_DPRINTF1(1, "pcfs_write: io error = %d\n", error);
289 return (error);
293 * read or write a vnode
295 static int
296 rwpcp(
297 struct pcnode *pcp,
298 struct uio *uio,
299 enum uio_rw rw,
300 int ioflag)
302 struct vnode *vp = PCTOV(pcp);
303 struct pcfs *fsp;
304 daddr_t bn; /* phys block number */
305 int n;
306 offset_t off;
307 caddr_t base;
308 int mapon, pagecreate;
309 int newpage;
310 int error = 0;
311 rlim64_t limit = uio->uio_llimit;
312 int oresid = uio->uio_resid;
315 * If the filesystem was umounted by force, return immediately.
317 if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
318 return (EIO);
320 PC_DPRINTF4(5, "rwpcp pcp=%p off=%lld resid=%ld size=%u\n", (void *)pcp,
321 uio->uio_loffset, uio->uio_resid, pcp->pc_size);
323 ASSERT(rw == UIO_READ || rw == UIO_WRITE);
324 ASSERT(vp->v_type == VREG);
326 if (uio->uio_loffset >= UINT32_MAX && rw == UIO_READ) {
327 return (0);
330 if (uio->uio_loffset < 0)
331 return (EINVAL);
333 if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
334 limit = MAXOFFSET_T;
336 if (uio->uio_loffset >= limit && rw == UIO_WRITE) {
337 proc_t *p = ttoproc(curthread);
339 mutex_enter(&p->p_lock);
340 (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], p->p_rctls,
341 p, RCA_UNSAFE_SIGINFO);
342 mutex_exit(&p->p_lock);
343 return (EFBIG);
346 /* the following condition will occur only for write */
348 if (uio->uio_loffset >= UINT32_MAX)
349 return (EFBIG);
351 if (uio->uio_resid == 0)
352 return (0);
354 if (limit > UINT32_MAX)
355 limit = UINT32_MAX;
357 fsp = VFSTOPCFS(vp->v_vfsp);
358 if (fsp->pcfs_flags & PCFS_IRRECOV)
359 return (EIO);
361 do {
363 * Assignments to "n" in this block may appear
364 * to overflow in some cases. However, after careful
365 * analysis it was determined that all assignments to
366 * "n" serve only to make "n" smaller. Since "n"
367 * starts out as no larger than MAXBSIZE, "int" is
368 * safe.
370 off = uio->uio_loffset & MAXBMASK;
371 mapon = (int)(uio->uio_loffset & MAXBOFFSET);
372 n = MIN(MAXBSIZE - mapon, uio->uio_resid);
373 if (rw == UIO_READ) {
374 offset_t diff;
376 diff = pcp->pc_size - uio->uio_loffset;
377 if (diff <= 0)
378 return (0);
379 if (diff < n)
380 n = (int)diff;
383 * Compare limit with the actual offset + n, not the
384 * rounded down offset "off" or we will overflow
385 * the maximum file size after all.
387 if (rw == UIO_WRITE && uio->uio_loffset + n >= limit) {
388 if (uio->uio_loffset >= limit) {
389 error = EFBIG;
390 break;
392 n = (int)(limit - uio->uio_loffset);
396 * Touch the page and fault it in if it is not in
397 * core before segmap_getmapflt can lock it. This
398 * is to avoid the deadlock if the buffer is mapped
399 * to the same file through mmap which we want to
400 * write to.
402 uio_prefaultpages((long)n, uio);
404 base = segmap_getmap(segkmap, vp, (uoff_t)off);
405 pagecreate = 0;
406 newpage = 0;
407 if (rw == UIO_WRITE) {
409 * If PAGESIZE < MAXBSIZE, perhaps we ought to deal
410 * with one page at a time, instead of one MAXBSIZE
411 * at a time, so we can fully explore pagecreate
412 * optimization??
414 if (uio->uio_loffset + n > pcp->pc_size) {
415 uint_t ncl, lcn;
417 ncl = (uint_t)howmany((offset_t)pcp->pc_size,
418 fsp->pcfs_clsize);
419 if (uio->uio_loffset > pcp->pc_size &&
420 ncl < (uint_t)howmany(uio->uio_loffset,
421 fsp->pcfs_clsize)) {
423 * Allocate and zerofill skipped
424 * clusters. This may not be worth the
425 * effort since a small lseek beyond
426 * eof but still within the cluster
427 * will not be zeroed out.
429 lcn = pc_lblkno(fsp, uio->uio_loffset);
430 error = pc_balloc(pcp, (daddr_t)lcn,
431 1, &bn);
432 ncl = lcn + 1;
434 if (!error &&
435 ncl < (uint_t)howmany(uio->uio_loffset + n,
436 fsp->pcfs_clsize))
438 * allocate clusters w/o zerofill
440 error = pc_balloc(pcp,
441 (daddr_t)pc_lblkno(fsp,
442 uio->uio_loffset + n - 1),
443 0, &bn);
445 pcp->pc_flags |= PC_CHG;
447 if (error) {
448 pc_cluster32_t ncl;
449 int nerror;
452 * figure out new file size from
453 * cluster chain length. If this
454 * is detected to loop, the chain
455 * is corrupted and we'd better
456 * keep our fingers off that file.
458 nerror = pc_fileclsize(fsp,
459 pcp->pc_scluster, &ncl);
460 if (nerror) {
461 PC_DPRINTF1(2,
462 "cluster chain "
463 "corruption, "
464 "scluster=%d\n",
465 pcp->pc_scluster);
466 pcp->pc_size = 0;
467 pcp->pc_flags |= PC_INVAL;
468 error = nerror;
469 (void) segmap_release(segkmap,
470 base, 0);
471 break;
473 pcp->pc_size = fsp->pcfs_clsize * ncl;
475 if (error == ENOSPC &&
476 (pcp->pc_size - uio->uio_loffset)
477 > 0) {
478 PC_DPRINTF3(2, "rwpcp ENOSPC "
479 "off=%lld n=%d size=%d\n",
480 uio->uio_loffset,
481 n, pcp->pc_size);
482 n = (int)(pcp->pc_size -
483 uio->uio_loffset);
484 } else {
485 PC_DPRINTF1(1,
486 "rwpcp error1=%d\n", error);
487 (void) segmap_release(segkmap,
488 base, 0);
489 break;
491 } else {
492 pcp->pc_size =
493 (uint_t)(uio->uio_loffset + n);
495 if (mapon == 0) {
496 newpage = segmap_pagecreate(segkmap,
497 base, (size_t)n, 0);
498 pagecreate = 1;
500 } else if (n == MAXBSIZE) {
501 newpage = segmap_pagecreate(segkmap, base,
502 (size_t)n, 0);
503 pagecreate = 1;
506 error = uiomove(base + mapon, (size_t)n, rw, uio);
508 if (pagecreate && uio->uio_loffset <
509 roundup(off + mapon + n, PAGESIZE)) {
510 offset_t nzero, nmoved;
512 nmoved = uio->uio_loffset - (off + mapon);
513 nzero = roundup(mapon + n, PAGESIZE) - nmoved;
514 (void) kzero(base + mapon + nmoved, (size_t)nzero);
518 * Unlock the pages which have been allocated by
519 * page_create_va() in segmap_pagecreate().
521 if (newpage) {
522 segmap_pageunlock(segkmap, base, (size_t)n,
523 rw == UIO_WRITE ? S_WRITE : S_READ);
526 if (error) {
527 PC_DPRINTF1(1, "rwpcp error2=%d\n", error);
529 * If we failed on a write, we may have already
530 * allocated file blocks as well as pages. It's hard
531 * to undo the block allocation, but we must be sure
532 * to invalidate any pages that may have been
533 * allocated.
535 if (rw == UIO_WRITE)
536 (void) segmap_release(segkmap, base, SM_INVAL);
537 else
538 (void) segmap_release(segkmap, base, 0);
539 } else {
540 uint_t flags = 0;
542 if (rw == UIO_READ) {
543 if (n + mapon == MAXBSIZE ||
544 uio->uio_loffset == pcp->pc_size)
545 flags = SM_DONTNEED;
546 } else if (ioflag & (FSYNC|FDSYNC)) {
547 flags = SM_WRITE;
548 } else if (n + mapon == MAXBSIZE) {
549 flags = SM_WRITE|SM_ASYNC|SM_DONTNEED;
551 error = segmap_release(segkmap, base, flags);
554 } while (error == 0 && uio->uio_resid > 0 && n != 0);
556 if (oresid != uio->uio_resid)
557 error = 0;
558 return (error);
561 /*ARGSUSED*/
562 static int
563 pcfs_getattr(
564 struct vnode *vp,
565 struct vattr *vap,
566 int flags,
567 struct cred *cr,
568 caller_context_t *ct)
570 struct pcnode *pcp;
571 struct pcfs *fsp;
572 int error;
573 char attr;
574 struct pctime atime;
575 int64_t unixtime;
577 PC_DPRINTF1(8, "pcfs_getattr: vp=%p\n", (void *)vp);
579 fsp = VFSTOPCFS(vp->v_vfsp);
580 error = pc_lockfs(fsp, 0, 0);
581 if (error)
582 return (error);
585 * Note that we don't check for "invalid node" (PC_INVAL) here
586 * only in order to make stat() succeed. We allow no I/O on such
587 * a node, but do allow to check for its existence.
589 if ((pcp = VTOPC(vp)) == NULL) {
590 pc_unlockfs(fsp);
591 return (EIO);
594 * Copy from pcnode.
596 vap->va_type = vp->v_type;
597 attr = pcp->pc_entry.pcd_attr;
598 if (PCA_IS_HIDDEN(fsp, attr))
599 vap->va_mode = 0;
600 else if (attr & PCA_LABEL)
601 vap->va_mode = 0444;
602 else if (attr & PCA_RDONLY)
603 vap->va_mode = 0555;
604 else if (fsp->pcfs_flags & PCFS_BOOTPART) {
605 vap->va_mode = 0755;
606 } else {
607 vap->va_mode = 0777;
610 if (attr & PCA_DIR)
611 vap->va_mode |= S_IFDIR;
612 else
613 vap->va_mode |= S_IFREG;
614 if (fsp->pcfs_flags & PCFS_BOOTPART) {
615 vap->va_uid = 0;
616 vap->va_gid = 0;
617 } else {
618 vap->va_uid = crgetuid(cr);
619 vap->va_gid = crgetgid(cr);
621 vap->va_fsid = vp->v_vfsp->vfs_dev;
622 vap->va_nodeid = (ino64_t)pc_makenodeid(pcp->pc_eblkno,
623 pcp->pc_eoffset, pcp->pc_entry.pcd_attr,
624 pc_getstartcluster(fsp, &pcp->pc_entry), pc_direntpersec(fsp));
625 vap->va_nlink = 1;
626 vap->va_size = (uoff_t)pcp->pc_size;
627 vap->va_rdev = 0;
628 vap->va_nblocks =
629 (fsblkcnt64_t)howmany((offset_t)pcp->pc_size, DEV_BSIZE);
630 vap->va_blksize = fsp->pcfs_clsize;
633 * FAT root directories have no timestamps. In order not to return
634 * "time zero" (1/1/1970), we record the time of the mount and give
635 * that. This breaks less expectations.
637 if (vp->v_flag & VROOT) {
638 vap->va_mtime = fsp->pcfs_mounttime;
639 vap->va_atime = fsp->pcfs_mounttime;
640 vap->va_ctime = fsp->pcfs_mounttime;
641 pc_unlockfs(fsp);
642 return (0);
645 pc_pcttotv(&pcp->pc_entry.pcd_mtime, &unixtime);
646 if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) {
647 if (unixtime > INT32_MAX)
648 DTRACE_PROBE1(pcfs__mtimeclamped, int64_t, unixtime);
649 unixtime = MIN(unixtime, INT32_MAX);
650 } else if (unixtime > INT32_MAX &&
651 get_udatamodel() == DATAMODEL_ILP32) {
652 pc_unlockfs(fsp);
653 DTRACE_PROBE1(pcfs__mtimeoverflowed, int64_t, unixtime);
654 return (EOVERFLOW);
657 vap->va_mtime.tv_sec = (time_t)unixtime;
658 vap->va_mtime.tv_nsec = 0;
661 * FAT doesn't know about POSIX ctime.
662 * Best approximation is to always set it to mtime.
664 vap->va_ctime = vap->va_mtime;
667 * FAT only stores "last access date". If that's the
668 * same as the date of last modification then the time
669 * of last access is known. Otherwise, use midnight.
671 atime.pct_date = pcp->pc_entry.pcd_ladate;
672 if (atime.pct_date == pcp->pc_entry.pcd_mtime.pct_date)
673 atime.pct_time = pcp->pc_entry.pcd_mtime.pct_time;
674 else
675 atime.pct_time = 0;
676 pc_pcttotv(&atime, &unixtime);
677 if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) {
678 if (unixtime > INT32_MAX)
679 DTRACE_PROBE1(pcfs__atimeclamped, int64_t, unixtime);
680 unixtime = MIN(unixtime, INT32_MAX);
681 } else if (unixtime > INT32_MAX &&
682 get_udatamodel() == DATAMODEL_ILP32) {
683 pc_unlockfs(fsp);
684 DTRACE_PROBE1(pcfs__atimeoverflowed, int64_t, unixtime);
685 return (EOVERFLOW);
688 vap->va_atime.tv_sec = (time_t)unixtime;
689 vap->va_atime.tv_nsec = 0;
691 pc_unlockfs(fsp);
692 return (0);
696 /*ARGSUSED*/
697 static int
698 pcfs_setattr(
699 struct vnode *vp,
700 struct vattr *vap,
701 int flags,
702 struct cred *cr,
703 caller_context_t *ct)
705 struct pcnode *pcp;
706 mode_t mask = vap->va_mask;
707 int error;
708 struct pcfs *fsp;
709 timestruc_t now, *timep;
711 PC_DPRINTF2(6, "pcfs_setattr: vp=%p mask=%x\n", (void *)vp, (int)mask);
713 * cannot set these attributes
715 if (mask & (VATTR_NOSET | VATTR_UID | VATTR_GID)) {
716 return (EINVAL);
719 * pcfs_setattr is now allowed on directories to avoid silly warnings
720 * from 'tar' when it tries to set times on a directory, and console
721 * printf's on the NFS server when it gets EINVAL back on such a
722 * request. One possible problem with that since a directory entry
723 * identifies a file, '.' and all the '..' entries in subdirectories
724 * may get out of sync when the directory is updated since they're
725 * treated like separate files. We could fix that by looking for
726 * '.' and giving it the same attributes, and then looking for
727 * all the subdirectories and updating '..', but that's pretty
728 * expensive for something that doesn't seem likely to matter.
730 /* can't do some ops on directories anyway */
731 if ((vp->v_type == VDIR) &&
732 (mask & VATTR_SIZE)) {
733 return (EINVAL);
736 fsp = VFSTOPCFS(vp->v_vfsp);
737 error = pc_lockfs(fsp, 0, 0);
738 if (error)
739 return (error);
740 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
741 pc_unlockfs(fsp);
742 return (EIO);
745 if (fsp->pcfs_flags & PCFS_BOOTPART) {
746 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
747 pc_unlockfs(fsp);
748 return (EACCES);
753 * Change file access modes.
754 * If nobody has write permission, file is marked readonly.
755 * Otherwise file is writable by anyone.
757 if ((mask & VATTR_MODE) && (vap->va_mode != (mode_t)-1)) {
758 if ((vap->va_mode & 0222) == 0)
759 pcp->pc_entry.pcd_attr |= PCA_RDONLY;
760 else
761 pcp->pc_entry.pcd_attr &= ~PCA_RDONLY;
762 pcp->pc_flags |= PC_CHG;
765 * Truncate file. Must have write permission.
767 if ((mask & VATTR_SIZE) && (vap->va_size != (uoff_t)-1)) {
768 if (pcp->pc_entry.pcd_attr & PCA_RDONLY) {
769 error = EACCES;
770 goto out;
772 if (vap->va_size > UINT32_MAX) {
773 error = EFBIG;
774 goto out;
776 error = pc_truncate(pcp, (uint_t)vap->va_size);
778 if (error)
779 goto out;
781 if (vap->va_size == 0)
782 vnevent_truncate(vp, ct);
785 * Change file modified times.
787 if (mask & (VATTR_MTIME | VATTR_CTIME)) {
789 * If SysV-compatible option to set access and
790 * modified times if privileged, owner, or write access,
791 * use current time rather than va_mtime.
793 * XXX - va_mtime.tv_sec == -1 flags this.
795 timep = &vap->va_mtime;
796 if (vap->va_mtime.tv_sec == -1) {
797 gethrestime(&now);
798 timep = &now;
800 if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 &&
801 timep->tv_sec > INT32_MAX) {
802 error = EOVERFLOW;
803 goto out;
805 error = pc_tvtopct(timep, &pcp->pc_entry.pcd_mtime);
806 if (error)
807 goto out;
808 pcp->pc_flags |= PC_CHG;
811 * Change file access times.
813 if (mask & VATTR_ATIME) {
815 * If SysV-compatible option to set access and
816 * modified times if privileged, owner, or write access,
817 * use current time rather than va_mtime.
819 * XXX - va_atime.tv_sec == -1 flags this.
821 struct pctime atime;
823 timep = &vap->va_atime;
824 if (vap->va_atime.tv_sec == -1) {
825 gethrestime(&now);
826 timep = &now;
828 if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 &&
829 timep->tv_sec > INT32_MAX) {
830 error = EOVERFLOW;
831 goto out;
833 error = pc_tvtopct(timep, &atime);
834 if (error)
835 goto out;
836 pcp->pc_entry.pcd_ladate = atime.pct_date;
837 pcp->pc_flags |= PC_CHG;
839 out:
840 pc_unlockfs(fsp);
841 return (error);
845 /*ARGSUSED*/
846 static int
847 pcfs_access(
848 struct vnode *vp,
849 int mode,
850 int flags,
851 struct cred *cr,
852 caller_context_t *ct)
854 struct pcnode *pcp;
855 struct pcfs *fsp;
858 fsp = VFSTOPCFS(vp->v_vfsp);
860 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL)
861 return (EIO);
862 if ((mode & VWRITE) && (pcp->pc_entry.pcd_attr & PCA_RDONLY))
863 return (EACCES);
866 * If this is a boot partition, privileged users have full access while
867 * others have read-only access.
869 if (fsp->pcfs_flags & PCFS_BOOTPART) {
870 if ((mode & VWRITE) &&
871 secpolicy_pcfs_modify_bootpartition(cr) != 0)
872 return (EACCES);
874 return (0);
878 /*ARGSUSED*/
879 static int
880 pcfs_fsync(
881 struct vnode *vp,
882 int syncflag,
883 struct cred *cr,
884 caller_context_t *ct)
886 struct pcfs *fsp;
887 struct pcnode *pcp;
888 int error;
890 fsp = VFSTOPCFS(vp->v_vfsp);
891 if (error = pc_verify(fsp))
892 return (error);
893 error = pc_lockfs(fsp, 0, 0);
894 if (error)
895 return (error);
896 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
897 pc_unlockfs(fsp);
898 return (EIO);
900 rw_enter(&pcnodes_lock, RW_WRITER);
901 error = pc_nodesync(pcp);
902 rw_exit(&pcnodes_lock);
903 pc_unlockfs(fsp);
904 return (error);
908 /*ARGSUSED*/
909 static void
910 pcfs_inactive(
911 struct vnode *vp,
912 struct cred *cr,
913 caller_context_t *ct)
915 struct pcnode *pcp;
916 struct pcfs *fsp;
917 int error;
919 fsp = VFSTOPCFS(vp->v_vfsp);
920 error = pc_lockfs(fsp, 0, 1);
923 * If the filesystem was umounted by force, all dirty
924 * pages associated with this vnode are invalidated
925 * and then the vnode will be freed.
927 if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) {
928 pcp = VTOPC(vp);
929 if (vn_has_cached_data(vp)) {
930 (void) pvn_vplist_dirty(vp, 0,
931 pcfs_putapage, B_INVAL, NULL);
933 remque(pcp);
934 if (error == 0)
935 pc_unlockfs(fsp);
936 vn_free(vp);
937 kmem_free(pcp, sizeof (struct pcnode));
938 VFS_RELE(PCFSTOVFS(fsp));
939 return;
942 mutex_enter(&vp->v_lock);
943 ASSERT(vp->v_count >= 1);
944 if (vp->v_count > 1) {
945 VN_RELE_LOCKED(vp);
946 mutex_exit(&vp->v_lock);
947 pc_unlockfs(fsp);
948 return;
950 mutex_exit(&vp->v_lock);
953 * Check again to confirm that no intervening I/O error
954 * with a subsequent pc_diskchanged() call has released
955 * the pcnode. If it has then release the vnode as above.
957 pcp = VTOPC(vp);
958 if (pcp == NULL || pcp->pc_flags & PC_INVAL) {
959 if (vn_has_cached_data(vp))
960 (void) pvn_vplist_dirty(vp, 0,
961 pcfs_putapage, B_INVAL | B_TRUNC, NULL);
964 if (pcp == NULL) {
965 vn_free(vp);
966 } else {
967 pc_rele(pcp);
970 if (!error)
971 pc_unlockfs(fsp);
974 /*ARGSUSED*/
975 static int
976 pcfs_lookup(
977 struct vnode *dvp,
978 char *nm,
979 struct vnode **vpp,
980 struct pathname *pnp,
981 int flags,
982 struct vnode *rdir,
983 struct cred *cr,
984 caller_context_t *ct,
985 int *direntflags,
986 pathname_t *realpnp)
988 struct pcfs *fsp;
989 struct pcnode *pcp;
990 int error;
993 * If the filesystem was umounted by force, return immediately.
995 if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
996 return (EIO);
999 * verify that the dvp is still valid on the disk
1001 fsp = VFSTOPCFS(dvp->v_vfsp);
1002 if (error = pc_verify(fsp))
1003 return (error);
1004 error = pc_lockfs(fsp, 0, 0);
1005 if (error)
1006 return (error);
1007 if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
1008 pc_unlockfs(fsp);
1009 return (EIO);
1012 * Null component name is a synonym for directory being searched.
1014 if (*nm == '\0') {
1015 VN_HOLD(dvp);
1016 *vpp = dvp;
1017 pc_unlockfs(fsp);
1018 return (0);
1021 error = pc_dirlook(VTOPC(dvp), nm, &pcp);
1022 if (!error) {
1023 *vpp = PCTOV(pcp);
1024 pcp->pc_flags |= PC_EXTERNAL;
1026 pc_unlockfs(fsp);
1027 return (error);
1031 /*ARGSUSED*/
1032 static int
1033 pcfs_create(
1034 struct vnode *dvp,
1035 char *nm,
1036 struct vattr *vap,
1037 enum vcexcl exclusive,
1038 int mode,
1039 struct vnode **vpp,
1040 struct cred *cr,
1041 int flag,
1042 caller_context_t *ct,
1043 vsecattr_t *vsecp)
1045 int error;
1046 struct pcnode *pcp;
1047 struct vnode *vp;
1048 struct pcfs *fsp;
1051 * can't create directories. use pcfs_mkdir.
1052 * can't create anything other than files.
1054 if (vap->va_type == VDIR)
1055 return (EISDIR);
1056 else if (vap->va_type != VREG)
1057 return (EINVAL);
1059 pcp = NULL;
1060 fsp = VFSTOPCFS(dvp->v_vfsp);
1061 error = pc_lockfs(fsp, 0, 0);
1062 if (error)
1063 return (error);
1064 if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
1065 pc_unlockfs(fsp);
1066 return (EIO);
1069 if (fsp->pcfs_flags & PCFS_BOOTPART) {
1070 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
1071 pc_unlockfs(fsp);
1072 return (EACCES);
1076 if (*nm == '\0') {
1078 * Null component name refers to the directory itself.
1080 VN_HOLD(dvp);
1081 pcp = VTOPC(dvp);
1082 error = EEXIST;
1083 } else {
1084 error = pc_direnter(VTOPC(dvp), nm, vap, &pcp);
1087 * if file exists and this is a nonexclusive create,
1088 * check for access permissions
1090 if (error == EEXIST) {
1091 vp = PCTOV(pcp);
1092 if (exclusive == NONEXCL) {
1093 if (vp->v_type == VDIR) {
1094 error = EISDIR;
1095 } else if (mode) {
1096 error = pcfs_access(PCTOV(pcp), mode, 0,
1097 cr, ct);
1098 } else {
1099 error = 0;
1102 if (error) {
1103 VN_RELE(PCTOV(pcp));
1104 } else if ((vp->v_type == VREG) && (vap->va_mask & VATTR_SIZE) &&
1105 (vap->va_size == 0)) {
1106 error = pc_truncate(pcp, 0L);
1107 if (error) {
1108 VN_RELE(PCTOV(pcp));
1109 } else {
1110 vnevent_create(PCTOV(pcp), ct);
1114 if (error) {
1115 pc_unlockfs(fsp);
1116 return (error);
1118 *vpp = PCTOV(pcp);
1119 pcp->pc_flags |= PC_EXTERNAL;
1120 pc_unlockfs(fsp);
1121 return (error);
1124 /*ARGSUSED*/
1125 static int
1126 pcfs_remove(
1127 struct vnode *vp,
1128 char *nm,
1129 struct cred *cr,
1130 caller_context_t *ct,
1131 int flags)
1133 struct pcfs *fsp;
1134 struct pcnode *pcp;
1135 int error;
1137 fsp = VFSTOPCFS(vp->v_vfsp);
1138 if (error = pc_verify(fsp))
1139 return (error);
1140 error = pc_lockfs(fsp, 0, 0);
1141 if (error)
1142 return (error);
1143 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
1144 pc_unlockfs(fsp);
1145 return (EIO);
1147 if (fsp->pcfs_flags & PCFS_BOOTPART) {
1148 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
1149 pc_unlockfs(fsp);
1150 return (EACCES);
1153 error = pc_dirremove(pcp, nm, NULL, VREG, ct);
1154 pc_unlockfs(fsp);
1155 return (error);
1159 * Rename a file or directory
1160 * This rename is restricted to only rename files within a directory.
1161 * XX should make rename more general
1163 /*ARGSUSED*/
1164 static int
1165 pcfs_rename(
1166 struct vnode *sdvp, /* old (source) parent vnode */
1167 char *snm, /* old (source) entry name */
1168 struct vnode *tdvp, /* new (target) parent vnode */
1169 char *tnm, /* new (target) entry name */
1170 struct cred *cr,
1171 caller_context_t *ct,
1172 int flags)
1174 struct pcfs *fsp;
1175 struct pcnode *dp; /* parent pcnode */
1176 struct pcnode *tdp;
1177 int error;
1179 fsp = VFSTOPCFS(sdvp->v_vfsp);
1180 if (error = pc_verify(fsp))
1181 return (error);
1184 * make sure we can muck with this directory.
1186 error = pcfs_access(sdvp, VWRITE, 0, cr, ct);
1187 if (error) {
1188 return (error);
1190 error = pc_lockfs(fsp, 0, 0);
1191 if (error)
1192 return (error);
1193 if (((dp = VTOPC(sdvp)) == NULL) || ((tdp = VTOPC(tdvp)) == NULL) ||
1194 (dp->pc_flags & PC_INVAL) || (tdp->pc_flags & PC_INVAL)) {
1195 pc_unlockfs(fsp);
1196 return (EIO);
1198 error = pc_rename(dp, tdp, snm, tnm, ct);
1199 pc_unlockfs(fsp);
1200 return (error);
1203 /*ARGSUSED*/
1204 static int
1205 pcfs_mkdir(
1206 struct vnode *dvp,
1207 char *nm,
1208 struct vattr *vap,
1209 struct vnode **vpp,
1210 struct cred *cr,
1211 caller_context_t *ct,
1212 int flags,
1213 vsecattr_t *vsecp)
1215 struct pcfs *fsp;
1216 struct pcnode *pcp;
1217 int error;
1219 fsp = VFSTOPCFS(dvp->v_vfsp);
1220 if (error = pc_verify(fsp))
1221 return (error);
1222 error = pc_lockfs(fsp, 0, 0);
1223 if (error)
1224 return (error);
1225 if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
1226 pc_unlockfs(fsp);
1227 return (EIO);
1230 if (fsp->pcfs_flags & PCFS_BOOTPART) {
1231 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
1232 pc_unlockfs(fsp);
1233 return (EACCES);
1237 error = pc_direnter(VTOPC(dvp), nm, vap, &pcp);
1239 if (!error) {
1240 pcp -> pc_flags |= PC_EXTERNAL;
1241 *vpp = PCTOV(pcp);
1242 } else if (error == EEXIST) {
1243 VN_RELE(PCTOV(pcp));
1245 pc_unlockfs(fsp);
1246 return (error);
1249 /*ARGSUSED*/
1250 static int
1251 pcfs_rmdir(
1252 struct vnode *dvp,
1253 char *nm,
1254 struct vnode *cdir,
1255 struct cred *cr,
1256 caller_context_t *ct,
1257 int flags)
1259 struct pcfs *fsp;
1260 struct pcnode *pcp;
1261 int error;
1263 fsp = VFSTOPCFS(dvp -> v_vfsp);
1264 if (error = pc_verify(fsp))
1265 return (error);
1266 if (error = pc_lockfs(fsp, 0, 0))
1267 return (error);
1269 if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) {
1270 pc_unlockfs(fsp);
1271 return (EIO);
1274 if (fsp->pcfs_flags & PCFS_BOOTPART) {
1275 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
1276 pc_unlockfs(fsp);
1277 return (EACCES);
1281 error = pc_dirremove(pcp, nm, cdir, VDIR, ct);
1282 pc_unlockfs(fsp);
1283 return (error);
1287 * read entries in a directory.
1288 * we must convert pc format to unix format
1291 /*ARGSUSED*/
1292 static int
1293 pcfs_readdir(
1294 struct vnode *dvp,
1295 struct uio *uiop,
1296 struct cred *cr,
1297 int *eofp,
1298 caller_context_t *ct,
1299 int flags)
1301 struct pcnode *pcp;
1302 struct pcfs *fsp;
1303 struct pcdir *ep;
1304 struct buf *bp = NULL;
1305 offset_t offset;
1306 int boff;
1307 struct pc_dirent lbp;
1308 struct pc_dirent *ld = &lbp;
1309 int error;
1312 * If the filesystem was umounted by force, return immediately.
1314 if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1315 return (EIO);
1317 if ((uiop->uio_iovcnt != 1) ||
1318 (uiop->uio_loffset % sizeof (struct pcdir)) != 0) {
1319 return (EINVAL);
1321 fsp = VFSTOPCFS(dvp->v_vfsp);
1323 * verify that the dp is still valid on the disk
1325 if (error = pc_verify(fsp)) {
1326 return (error);
1328 error = pc_lockfs(fsp, 0, 0);
1329 if (error)
1330 return (error);
1331 if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) {
1332 pc_unlockfs(fsp);
1333 return (EIO);
1336 bzero(ld, sizeof (*ld));
1338 if (eofp != NULL)
1339 *eofp = 0;
1340 offset = uiop->uio_loffset;
1342 if (dvp->v_flag & VROOT) {
1344 * kludge up entries for "." and ".." in the root.
1346 if (offset == 0) {
1347 (void) strcpy(ld->d_name, ".");
1348 ld->d_reclen = DIRENT64_RECLEN(1);
1349 ld->d_off = (off64_t)sizeof (struct pcdir);
1350 ld->d_ino = (ino64_t)UINT_MAX;
1351 if (ld->d_reclen > uiop->uio_resid) {
1352 pc_unlockfs(fsp);
1353 return (ENOSPC);
1355 (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop);
1356 uiop->uio_loffset = ld->d_off;
1357 offset = uiop->uio_loffset;
1359 if (offset == sizeof (struct pcdir)) {
1360 (void) strcpy(ld->d_name, "..");
1361 ld->d_reclen = DIRENT64_RECLEN(2);
1362 if (ld->d_reclen > uiop->uio_resid) {
1363 pc_unlockfs(fsp);
1364 return (ENOSPC);
1366 ld->d_off = (off64_t)(uiop->uio_loffset +
1367 sizeof (struct pcdir));
1368 ld->d_ino = (ino64_t)UINT_MAX;
1369 (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop);
1370 uiop->uio_loffset = ld->d_off;
1371 offset = uiop->uio_loffset;
1373 offset -= 2 * sizeof (struct pcdir);
1374 /* offset now has the real offset value into directory file */
1377 for (;;) {
1378 boff = pc_blkoff(fsp, offset);
1379 if (boff == 0 || bp == NULL || boff >= bp->b_bcount) {
1380 if (bp != NULL) {
1381 brelse(bp);
1382 bp = NULL;
1384 error = pc_blkatoff(pcp, offset, &bp, &ep);
1385 if (error) {
1386 if (error == ENOENT) {
1387 error = 0;
1388 if (eofp)
1389 *eofp = 1;
1391 break;
1394 if (ep->pcd_filename[0] == PCD_UNUSED) {
1395 if (eofp)
1396 *eofp = 1;
1397 break;
1400 * Don't display label because it may contain funny characters.
1402 if (ep->pcd_filename[0] == PCD_ERASED) {
1403 uiop->uio_loffset += sizeof (struct pcdir);
1404 offset += sizeof (struct pcdir);
1405 ep++;
1406 continue;
1408 if (PCDL_IS_LFN(ep)) {
1409 if (pc_read_long_fn(dvp, uiop, ld, &ep, &offset, &bp) !=
1411 break;
1412 continue;
1415 if (pc_read_short_fn(dvp, uiop, ld, &ep, &offset, &bp) != 0)
1416 break;
1418 if (bp)
1419 brelse(bp);
1420 pc_unlockfs(fsp);
1421 return (error);
1426 * Called from pvn_getpages to get a particular page. When we are called
1427 * the pcfs is already locked.
1429 /*ARGSUSED*/
1430 static int
1431 pcfs_getapage(
1432 struct vnode *vp,
1433 uoff_t off,
1434 size_t len,
1435 uint_t *protp,
1436 page_t *pl[], /* NULL if async IO is requested */
1437 size_t plsz,
1438 struct seg *seg,
1439 caddr_t addr,
1440 enum seg_rw rw,
1441 struct cred *cr)
1443 struct pcnode *pcp;
1444 struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
1445 struct vnode *devvp;
1446 page_t *pp;
1447 page_t *pagefound;
1448 int err;
1451 * If the filesystem was umounted by force, return immediately.
1453 if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1454 return (EIO);
1456 PC_DPRINTF3(5, "pcfs_getapage: vp=%p off=%lld len=%lu\n",
1457 (void *)vp, off, len);
1459 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL)
1460 return (EIO);
1461 devvp = fsp->pcfs_devvp;
1463 /* pcfs doesn't do readaheads */
1464 if (pl == NULL)
1465 return (0);
1467 pl[0] = NULL;
1468 err = 0;
1470 * If the accessed time on the pcnode has not already been
1471 * set elsewhere (e.g. for read/setattr) we set the time now.
1472 * This gives us approximate modified times for mmap'ed files
1473 * which are accessed via loads in the user address space.
1475 if ((pcp->pc_flags & PC_ACC) == 0 &&
1476 ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0)) {
1477 pc_mark_acc(fsp, pcp);
1479 reread:
1480 if ((pagefound = page_exists(&vp->v_object, off)) == NULL) {
1482 * Need to really do disk IO to get the page(s).
1484 struct buf *bp;
1485 daddr_t lbn, bn;
1486 uoff_t io_off;
1487 size_t io_len;
1488 uoff_t lbnoff, xferoffset;
1489 uoff_t pgoff;
1490 uint_t xfersize;
1491 int err1;
1493 lbn = pc_lblkno(fsp, off);
1494 lbnoff = off & ~(fsp->pcfs_clsize - 1);
1495 xferoffset = off & ~(fsp->pcfs_secsize - 1);
1497 pp = pvn_read_kluster(vp, off, seg, addr, &io_off, &io_len,
1498 off, (size_t)MIN(pc_blksize(fsp, pcp, off), PAGESIZE), 0);
1499 if (pp == NULL)
1501 * XXX - If pcfs is made MT-hot, this should go
1502 * back to reread.
1504 panic("pcfs_getapage pvn_read_kluster");
1506 for (pgoff = 0; pgoff < PAGESIZE && xferoffset < pcp->pc_size;
1507 pgoff += xfersize,
1508 lbn += howmany(xfersize, fsp->pcfs_clsize),
1509 lbnoff += xfersize, xferoffset += xfersize) {
1511 * read as many contiguous blocks as possible to
1512 * fill this page
1514 xfersize = PAGESIZE - pgoff;
1515 err1 = pc_bmap(pcp, lbn, &bn, &xfersize);
1516 if (err1) {
1517 PC_DPRINTF1(1, "pc_getapage err=%d", err1);
1518 err = err1;
1519 goto out;
1521 bp = pageio_setup(pp, xfersize, devvp, B_READ);
1522 bp->b_edev = devvp->v_rdev;
1523 bp->b_dev = cmpdev(devvp->v_rdev);
1524 bp->b_blkno = bn + btodt(xferoffset - lbnoff);
1525 bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff;
1526 bp->b_file = vp;
1527 bp->b_offset = (offset_t)(off + pgoff);
1529 (void) bdev_strategy(bp);
1531 lwp_stat_update(LWP_STAT_INBLK, 1);
1533 if (err == 0)
1534 err = biowait(bp);
1535 else
1536 (void) biowait(bp);
1537 pageio_done(bp);
1538 if (err)
1539 goto out;
1541 if (pgoff < PAGESIZE) {
1542 pagezero(pp->p_prev, pgoff, PAGESIZE - pgoff);
1544 pvn_plist_init(pp, pl, plsz, off, io_len, rw);
1546 out:
1547 if (err) {
1548 if (pp != NULL)
1549 pvn_read_done(pp, B_ERROR);
1550 return (err);
1553 if (pagefound) {
1555 * Page exists in the cache, acquire the "shared"
1556 * lock. If this fails, go back to reread.
1558 if ((pp = page_lookup(&vp->v_object, off, SE_SHARED)) == NULL) {
1559 goto reread;
1561 pl[0] = pp;
1562 pl[1] = NULL;
1564 return (err);
1568 * Return all the pages from [off..off+len] in given file
1570 /* ARGSUSED */
1571 static int
1572 pcfs_getpage(
1573 struct vnode *vp,
1574 offset_t off,
1575 size_t len,
1576 uint_t *protp,
1577 page_t *pl[],
1578 size_t plsz,
1579 struct seg *seg,
1580 caddr_t addr,
1581 enum seg_rw rw,
1582 struct cred *cr,
1583 caller_context_t *ct)
1585 struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
1586 int err;
1588 PC_DPRINTF0(6, "pcfs_getpage\n");
1589 if (err = pc_verify(fsp))
1590 return (err);
1591 if (vp->v_flag & VNOMAP)
1592 return (ENOSYS);
1593 ASSERT(off <= UINT32_MAX);
1594 err = pc_lockfs(fsp, 0, 0);
1595 if (err)
1596 return (err);
1597 if (protp != NULL)
1598 *protp = PROT_ALL;
1600 ASSERT((off & PAGEOFFSET) == 0);
1601 err = pvn_getpages(pcfs_getapage, vp, off, len, protp, pl, plsz,
1602 seg, addr, rw, cr);
1604 pc_unlockfs(fsp);
1605 return (err);
1610 * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE}
1611 * If len == 0, do from off to EOF.
1613 * The normal cases should be len == 0 & off == 0 (entire vp list),
1614 * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
1615 * (from pageout).
1618 /*ARGSUSED*/
1619 static int
1620 pcfs_putpage(
1621 struct vnode *vp,
1622 offset_t off,
1623 size_t len,
1624 int flags,
1625 struct cred *cr,
1626 caller_context_t *ct)
1628 struct pcnode *pcp;
1629 page_t *pp;
1630 struct pcfs *fsp;
1631 uoff_t io_off;
1632 size_t io_len;
1633 offset_t eoff;
1634 int err;
1637 * If the filesystem was umounted by force, return immediately.
1639 if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1640 return (EIO);
1642 PC_DPRINTF1(6, "pcfs_putpage vp=0x%p\n", (void *)vp);
1643 if (vp->v_flag & VNOMAP)
1644 return (ENOSYS);
1646 fsp = VFSTOPCFS(vp->v_vfsp);
1648 if (err = pc_verify(fsp))
1649 return (err);
1650 if ((pcp = VTOPC(vp)) == NULL) {
1651 PC_DPRINTF1(3, "pcfs_putpage NULL vp=0x%p\n", (void *)vp);
1652 return (EIO);
1654 if (pcp->pc_flags & PC_INVAL)
1655 return (EIO);
1657 if (curproc == proc_pageout) {
1659 * XXX - This is a quick hack to avoid blocking
1660 * pageout. Also to avoid pcfs_getapage deadlocking
1661 * with putpage when memory is running out,
1662 * since we only have one global lock and we don't
1663 * support async putpage.
1664 * It should be fixed someday.
1666 * Interestingly, this used to be a test of NOMEMWAIT().
1667 * We only ever got here once pcfs started supporting
1668 * NFS sharing, and then only because the NFS server
1669 * threads seem to do writes in sched's process context.
1670 * Since everyone else seems to just care about pageout,
1671 * the test was changed to look for pageout directly.
1673 return (ENOMEM);
1676 ASSERT(off <= UINT32_MAX);
1678 flags &= ~B_ASYNC; /* XXX should fix this later */
1680 err = pc_lockfs(fsp, 0, 0);
1681 if (err)
1682 return (err);
1683 if (!vn_has_cached_data(vp) || off >= pcp->pc_size) {
1684 pc_unlockfs(fsp);
1685 return (0);
1688 if (len == 0) {
1690 * Search the entire vp list for pages >= off
1692 err = pvn_vplist_dirty(vp, off,
1693 pcfs_putapage, flags, cr);
1694 } else {
1695 eoff = off + len;
1697 for (io_off = off; io_off < eoff &&
1698 io_off < pcp->pc_size; io_off += io_len) {
1700 * If we are not invalidating, synchronously
1701 * freeing or writing pages use the routine
1702 * page_lookup_nowait() to prevent reclaiming
1703 * them from the free list.
1705 if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) {
1706 pp = page_lookup(&vp->v_object, io_off,
1707 (flags & (B_INVAL | B_FREE)) ? SE_EXCL : SE_SHARED);
1708 } else {
1709 pp = page_lookup_nowait(&vp->v_object,
1710 io_off,
1711 (flags & B_FREE) ? SE_EXCL : SE_SHARED);
1714 if (pp == NULL || pvn_getdirty(pp, flags) == 0)
1715 io_len = PAGESIZE;
1716 else {
1717 err = pcfs_putapage(vp, pp, &io_off, &io_len,
1718 flags, cr);
1719 if (err != 0)
1720 break;
1722 * "io_off" and "io_len" are returned as
1723 * the range of pages we actually wrote.
1724 * This allows us to skip ahead more quickly
1725 * since several pages may've been dealt
1726 * with by this iteration of the loop.
1731 if (err == 0 && (flags & B_INVAL) &&
1732 off == 0 && len == 0 && vn_has_cached_data(vp)) {
1734 * If doing "invalidation", make sure that
1735 * all pages on the vnode list are actually
1736 * gone.
1738 cmn_err(CE_PANIC,
1739 "pcfs_putpage: B_INVAL, pages not gone");
1740 } else if (err) {
1741 PC_DPRINTF1(1, "pcfs_putpage err=%d\n", err);
1743 pc_unlockfs(fsp);
1744 return (err);
1748 * Write out a single page, possibly klustering adjacent dirty pages.
1750 /*ARGSUSED*/
1752 pcfs_putapage(
1753 struct vnode *vp,
1754 page_t *pp,
1755 uoff_t *offp,
1756 size_t *lenp,
1757 int flags,
1758 struct cred *cr)
1760 struct pcnode *pcp;
1761 struct pcfs *fsp;
1762 struct vnode *devvp;
1763 size_t io_len;
1764 daddr_t bn;
1765 uoff_t lbn, lbnoff, xferoffset;
1766 uint_t pgoff, xfersize;
1767 int err = 0;
1768 uoff_t io_off;
1770 pcp = VTOPC(vp);
1771 fsp = VFSTOPCFS(vp->v_vfsp);
1772 devvp = fsp->pcfs_devvp;
1775 * If the modified time on the inode has not already been
1776 * set elsewhere (e.g. for write/setattr) and this is not
1777 * a call from msync (B_FORCE) we set the time now.
1778 * This gives us approximate modified times for mmap'ed files
1779 * which are modified via stores in the user address space.
1781 if ((pcp->pc_flags & PC_MOD) == 0 || (flags & B_FORCE)) {
1782 pcp->pc_flags |= PC_MOD;
1783 pc_mark_mod(fsp, pcp);
1785 pp = pvn_write_kluster(vp, pp, &io_off, &io_len, pp->p_offset,
1786 PAGESIZE, flags);
1788 if (fsp->pcfs_flags & PCFS_IRRECOV) {
1789 goto out;
1792 PC_DPRINTF1(7, "pc_putpage writing dirty page off=%llu\n", io_off);
1794 lbn = pc_lblkno(fsp, io_off);
1795 lbnoff = io_off & ~(fsp->pcfs_clsize - 1);
1796 xferoffset = io_off & ~(fsp->pcfs_secsize - 1);
1798 for (pgoff = 0; pgoff < io_len && xferoffset < pcp->pc_size;
1799 pgoff += xfersize,
1800 lbn += howmany(xfersize, fsp->pcfs_clsize),
1801 lbnoff += xfersize, xferoffset += xfersize) {
1803 struct buf *bp;
1804 int err1;
1807 * write as many contiguous blocks as possible from this page
1809 xfersize = io_len - pgoff;
1810 err1 = pc_bmap(pcp, (daddr_t)lbn, &bn, &xfersize);
1811 if (err1) {
1812 err = err1;
1813 goto out;
1815 bp = pageio_setup(pp, xfersize, devvp, B_WRITE | flags);
1816 bp->b_edev = devvp->v_rdev;
1817 bp->b_dev = cmpdev(devvp->v_rdev);
1818 bp->b_blkno = bn + btodt(xferoffset - lbnoff);
1819 bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff;
1820 bp->b_file = vp;
1821 bp->b_offset = (offset_t)(io_off + pgoff);
1823 (void) bdev_strategy(bp);
1825 lwp_stat_update(LWP_STAT_OUBLK, 1);
1827 if (err == 0)
1828 err = biowait(bp);
1829 else
1830 (void) biowait(bp);
1831 pageio_done(bp);
1833 pvn_write_done(pp, ((err) ? B_ERROR : 0) | B_WRITE | flags);
1834 pp = NULL;
1836 out:
1837 if ((fsp->pcfs_flags & PCFS_IRRECOV) && pp != NULL) {
1838 pvn_write_done(pp, B_WRITE | flags);
1839 } else if (err != 0 && pp != NULL) {
1840 pvn_write_done(pp, B_ERROR | B_WRITE | flags);
1843 if (offp)
1844 *offp = io_off;
1845 if (lenp)
1846 *lenp = io_len;
1847 PC_DPRINTF4(4, "pcfs_putapage: vp=%p pp=%p off=%lld len=%lu\n",
1848 (void *)vp, (void *)pp, io_off, io_len);
1849 if (err) {
1850 PC_DPRINTF1(1, "pcfs_putapage err=%d", err);
1852 return (err);
1855 /*ARGSUSED*/
1856 static int
1857 pcfs_map(
1858 struct vnode *vp,
1859 offset_t off,
1860 struct as *as,
1861 caddr_t *addrp,
1862 size_t len,
1863 uchar_t prot,
1864 uchar_t maxprot,
1865 uint_t flags,
1866 struct cred *cr,
1867 caller_context_t *ct)
1869 struct segvn_crargs vn_a;
1870 int error;
1872 PC_DPRINTF0(6, "pcfs_map\n");
1873 if (vp->v_flag & VNOMAP)
1874 return (ENOSYS);
1876 if (off > UINT32_MAX || off + len > UINT32_MAX)
1877 return (ENXIO);
1879 as_rangelock(as);
1880 error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
1881 if (error != 0) {
1882 as_rangeunlock(as);
1883 return (error);
1886 vn_a.vp = vp;
1887 vn_a.offset = off;
1888 vn_a.type = flags & MAP_TYPE;
1889 vn_a.prot = prot;
1890 vn_a.maxprot = maxprot;
1891 vn_a.flags = flags & ~MAP_TYPE;
1892 vn_a.cred = cr;
1893 vn_a.amp = NULL;
1894 vn_a.szc = 0;
1895 vn_a.lgrp_mem_policy_flags = 0;
1897 error = as_map(as, *addrp, len, segvn_create, &vn_a);
1898 as_rangeunlock(as);
1899 return (error);
1902 /* ARGSUSED */
1903 static int
1904 pcfs_seek(
1905 struct vnode *vp,
1906 offset_t ooff,
1907 offset_t *noffp,
1908 caller_context_t *ct)
1910 if (*noffp < 0)
1911 return (EINVAL);
1912 else if (*noffp > MAXOFFSET_T)
1913 return (EINVAL);
1914 else
1915 return (0);
1918 /* ARGSUSED */
1919 static int
1920 pcfs_addmap(
1921 struct vnode *vp,
1922 offset_t off,
1923 struct as *as,
1924 caddr_t addr,
1925 size_t len,
1926 uchar_t prot,
1927 uchar_t maxprot,
1928 uint_t flags,
1929 struct cred *cr,
1930 caller_context_t *ct)
1932 if (vp->v_flag & VNOMAP)
1933 return (ENOSYS);
1934 return (0);
1937 /*ARGSUSED*/
1938 static int
1939 pcfs_delmap(
1940 struct vnode *vp,
1941 offset_t off,
1942 struct as *as,
1943 caddr_t addr,
1944 size_t len,
1945 uint_t prot,
1946 uint_t maxprot,
1947 uint_t flags,
1948 struct cred *cr,
1949 caller_context_t *ct)
1951 if (vp->v_flag & VNOMAP)
1952 return (ENOSYS);
1953 return (0);
1957 * POSIX pathconf() support.
1959 /* ARGSUSED */
1960 static int
1961 pcfs_pathconf(
1962 struct vnode *vp,
1963 int cmd,
1964 ulong_t *valp,
1965 struct cred *cr,
1966 caller_context_t *ct)
1968 struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
1970 switch (cmd) {
1971 case _PC_LINK_MAX:
1972 *valp = 1;
1973 return (0);
1975 case _PC_CASE_BEHAVIOR:
1976 return (EINVAL);
1978 case _PC_FILESIZEBITS:
1980 * Both FAT16 and FAT32 support 4GB - 1 byte for file size.
1981 * FAT12 can only go up to the maximum filesystem capacity
1982 * which is ~509MB.
1984 *valp = IS_FAT12(fsp) ? 30 : 33;
1985 return (0);
1987 case _PC_TIMESTAMP_RESOLUTION:
1989 * PCFS keeps track of modification times, it its own
1990 * internal format, to a resolution of 2 seconds.
1991 * Since 2000 million is representable in an int32_t
1992 * without overflow (or becoming negative), we allow
1993 * this value to be returned.
1995 *valp = 2000000000L;
1996 return (0);
1998 default:
1999 return (fs_pathconf(vp, cmd, valp, cr, ct));
2004 /* ARGSUSED */
2005 static int
2006 pcfs_space(
2007 struct vnode *vp,
2008 int cmd,
2009 struct flock64 *bfp,
2010 int flag,
2011 offset_t offset,
2012 cred_t *cr,
2013 caller_context_t *ct)
2015 struct vattr vattr;
2016 int error;
2018 if (cmd != F_FREESP)
2019 return (EINVAL);
2021 if ((error = convoff(vp, bfp, 0, offset)) == 0) {
2022 if ((bfp->l_start > UINT32_MAX) || (bfp->l_len > UINT32_MAX))
2023 return (EFBIG);
2025 * we only support the special case of l_len == 0,
2026 * meaning free to end of file at this moment.
2028 if (bfp->l_len != 0)
2029 return (EINVAL);
2030 vattr.va_mask = VATTR_SIZE;
2031 vattr.va_size = bfp->l_start;
2032 error = fop_setattr(vp, (vattr_t *)&vattr, 0, cr, ct);
2034 return (error);
2038 * Break up 'len' chars from 'buf' into a long file name chunk.
2039 * Pad with '0xff' to make Norton Disk Doctor and Microsoft ScanDisk happy.
2041 void
2042 set_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int len)
2044 int i;
2046 ASSERT(buf != NULL);
2048 for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2) {
2049 if (len > 0) {
2050 ep->pcdl_firstfilename[i] = *buf++;
2051 ep->pcdl_firstfilename[i + 1] = *buf++;
2052 len -= 2;
2053 } else {
2054 ep->pcdl_firstfilename[i] = (uchar_t)0xff;
2055 ep->pcdl_firstfilename[i + 1] = (uchar_t)0xff;
2059 for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2) {
2060 if (len > 0) {
2061 ep->pcdl_secondfilename[i] = *buf++;
2062 ep->pcdl_secondfilename[i + 1] = *buf++;
2063 len -= 2;
2064 } else {
2065 ep->pcdl_secondfilename[i] = (uchar_t)0xff;
2066 ep->pcdl_secondfilename[i + 1] = (uchar_t)0xff;
2069 for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2) {
2070 if (len > 0) {
2071 ep->pcdl_thirdfilename[i] = *buf++;
2072 ep->pcdl_thirdfilename[i + 1] = *buf++;
2073 len -= 2;
2074 } else {
2075 ep->pcdl_thirdfilename[i] = (uchar_t)0xff;
2076 ep->pcdl_thirdfilename[i + 1] = (uchar_t)0xff;
2082 * Extract the characters from the long filename chunk into 'buf'.
2083 * Return the number of characters extracted.
2085 static int
2086 get_long_fn_chunk(struct pcdir_lfn *ep, char *buf)
2088 char *tmp = buf;
2089 int i;
2091 /* Copy all the names, no filtering now */
2093 for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2, tmp += 2) {
2094 *tmp = ep->pcdl_firstfilename[i];
2095 *(tmp + 1) = ep->pcdl_firstfilename[i + 1];
2097 if ((*tmp == '\0') && (*(tmp+1) == '\0'))
2098 return (tmp - buf);
2100 for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2, tmp += 2) {
2101 *tmp = ep->pcdl_secondfilename[i];
2102 *(tmp + 1) = ep->pcdl_secondfilename[i + 1];
2104 if ((*tmp == '\0') && (*(tmp+1) == '\0'))
2105 return (tmp - buf);
2107 for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2, tmp += 2) {
2108 *tmp = ep->pcdl_thirdfilename[i];
2109 *(tmp + 1) = ep->pcdl_thirdfilename[i + 1];
2111 if ((*tmp == '\0') && (*(tmp+1) == '\0'))
2112 return (tmp - buf);
2114 return (tmp - buf);
2119 * Checksum the passed in short filename.
2120 * This is used to validate each component of the long name to make
2121 * sure the long name is valid (it hasn't been "detached" from the
2122 * short filename). This algorithm was found in FreeBSD.
2123 * (sys/fs/msdosfs/msdosfs_conv.c:winChksum(), Wolfgang Solfrank)
2126 uchar_t
2127 pc_checksum_long_fn(char *name, char *ext)
2129 uchar_t c;
2130 char b[11];
2132 bcopy(name, b, 8);
2133 bcopy(ext, b+8, 3);
2135 c = b[0];
2136 c = ((c << 7) | (c >> 1)) + b[1];
2137 c = ((c << 7) | (c >> 1)) + b[2];
2138 c = ((c << 7) | (c >> 1)) + b[3];
2139 c = ((c << 7) | (c >> 1)) + b[4];
2140 c = ((c << 7) | (c >> 1)) + b[5];
2141 c = ((c << 7) | (c >> 1)) + b[6];
2142 c = ((c << 7) | (c >> 1)) + b[7];
2143 c = ((c << 7) | (c >> 1)) + b[8];
2144 c = ((c << 7) | (c >> 1)) + b[9];
2145 c = ((c << 7) | (c >> 1)) + b[10];
2147 return (c);
2151 * Read a chunk of long filename entries into 'namep'.
2152 * Return with offset pointing to short entry (on success), or next
2153 * entry to read (if this wasn't a valid lfn really).
2154 * Uses the passed-in buffer if it can, otherwise kmem_allocs() room for
2155 * a long filename.
2157 * Can also be called with a NULL namep, in which case it just returns
2158 * whether this was really a valid long filename and consumes it
2159 * (used by pc_dirempty()).
2162 pc_extract_long_fn(struct pcnode *pcp, char *namep,
2163 struct pcdir **epp, offset_t *offset, struct buf **bp)
2165 struct pcdir *ep = *epp;
2166 struct pcdir_lfn *lep = (struct pcdir_lfn *)ep;
2167 struct vnode *dvp = PCTOV(pcp);
2168 struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
2169 char *lfn;
2170 char *lfn_base;
2171 int boff;
2172 int i, cs;
2173 char *buf;
2174 uchar_t cksum;
2175 int detached = 0;
2176 int error = 0;
2177 int foldcase;
2178 int count = 0;
2179 size_t u16l = 0, u8l = 0;
2180 char *outbuf;
2181 size_t ret, inlen, outlen;
2183 foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE);
2184 lfn_base = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP);
2185 lfn = lfn_base + PCMAXNAM_UTF16 - sizeof (uint16_t);
2186 *lfn = '\0';
2187 *(lfn + 1) = '\0';
2188 cksum = lep->pcdl_checksum;
2190 buf = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP);
2191 for (i = (lep->pcdl_ordinal & ~0xc0); i > 0; i--) {
2192 /* read next block if necessary */
2193 boff = pc_blkoff(fsp, *offset);
2194 if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) {
2195 if (*bp != NULL) {
2196 brelse(*bp);
2197 *bp = NULL;
2199 error = pc_blkatoff(pcp, *offset, bp, &ep);
2200 if (error) {
2201 kmem_free(lfn_base, PCMAXNAM_UTF16);
2202 kmem_free(buf, PCMAXNAM_UTF16);
2203 return (error);
2205 lep = (struct pcdir_lfn *)ep;
2207 /* can this happen? Bad fs? */
2208 if (!PCDL_IS_LFN((struct pcdir *)lep)) {
2209 detached = 1;
2210 break;
2212 if (cksum != lep->pcdl_checksum)
2213 detached = 1;
2214 /* process current entry */
2215 cs = get_long_fn_chunk(lep, buf);
2216 count += cs;
2217 for (; cs > 0; cs--) {
2218 /* see if we underflow */
2219 if (lfn >= lfn_base)
2220 *--lfn = buf[cs - 1];
2221 else
2222 detached = 1;
2224 lep++;
2225 *offset += sizeof (struct pcdir);
2227 kmem_free(buf, PCMAXNAM_UTF16);
2228 /* read next block if necessary */
2229 boff = pc_blkoff(fsp, *offset);
2230 ep = (struct pcdir *)lep;
2231 if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) {
2232 if (*bp != NULL) {
2233 brelse(*bp);
2234 *bp = NULL;
2236 error = pc_blkatoff(pcp, *offset, bp, &ep);
2237 if (error) {
2238 kmem_free(lfn_base, PCMAXNAM_UTF16);
2239 return (error);
2242 /* should be on the short one */
2243 if (PCDL_IS_LFN(ep) || ((ep->pcd_filename[0] == PCD_UNUSED) ||
2244 (ep->pcd_filename[0] == PCD_ERASED))) {
2245 detached = 1;
2247 if (detached ||
2248 (cksum != pc_checksum_long_fn(ep->pcd_filename, ep->pcd_ext)) ||
2249 !pc_valid_long_fn(lfn, 0)) {
2251 * process current entry again. This may end up another lfn
2252 * or a short name.
2254 *epp = ep;
2255 kmem_free(lfn_base, PCMAXNAM_UTF16);
2256 return (EINVAL);
2258 if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) {
2260 * Don't display label because it may contain
2261 * funny characters.
2263 *offset += sizeof (struct pcdir);
2264 ep++;
2265 *epp = ep;
2266 kmem_free(lfn_base, PCMAXNAM_UTF16);
2267 return (EINVAL);
2269 if (namep) {
2270 u16l = count / 2;
2271 u8l = PCMAXNAMLEN;
2272 error = uconv_u16tou8((const uint16_t *)lfn, &u16l,
2273 (uchar_t *)namep, &u8l, UCONV_IN_LITTLE_ENDIAN);
2275 * uconv_u16tou8() will catch conversion errors including
2276 * the case where there is not enough room to write the
2277 * converted result and the u8l will never go over the given
2278 * PCMAXNAMLEN.
2280 if (error != 0) {
2281 kmem_free(lfn_base, PCMAXNAM_UTF16);
2282 return (EINVAL);
2284 namep[u8l] = '\0';
2285 if (foldcase) {
2286 inlen = strlen(namep);
2287 outlen = PCMAXNAMLEN;
2288 outbuf = kmem_alloc(PCMAXNAMLEN + 1, KM_SLEEP);
2289 ret = u8_textprep_str(namep, &inlen, outbuf,
2290 &outlen, U8_TEXTPREP_TOLOWER, U8_UNICODE_LATEST,
2291 &error);
2292 if (ret == -1) {
2293 kmem_free(outbuf, PCMAXNAMLEN + 1);
2294 kmem_free(lfn_base, PCMAXNAM_UTF16);
2295 return (EINVAL);
2297 outbuf[PCMAXNAMLEN - outlen] = '\0';
2298 (void) strncpy(namep, outbuf, PCMAXNAMLEN + 1);
2299 kmem_free(outbuf, PCMAXNAMLEN + 1);
2302 kmem_free(lfn_base, PCMAXNAM_UTF16);
2303 *epp = ep;
2304 return (0);
2307 * Read a long filename into the pc_dirent structure and copy it out.
2310 pc_read_long_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld,
2311 struct pcdir **epp, offset_t *offset, struct buf **bp)
2313 struct pcdir *ep;
2314 struct pcnode *pcp = VTOPC(dvp);
2315 struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
2316 offset_t uiooffset = uiop->uio_loffset;
2317 int error = 0;
2318 offset_t oldoffset;
2320 oldoffset = *offset;
2321 error = pc_extract_long_fn(pcp, ld->d_name, epp, offset, bp);
2322 if (error) {
2323 if (error == EINVAL) {
2324 uiop->uio_loffset += *offset - oldoffset;
2325 return (0);
2326 } else
2327 return (error);
2330 ep = *epp;
2331 uiop->uio_loffset += *offset - oldoffset;
2332 ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name));
2333 if (ld->d_reclen > uiop->uio_resid) {
2334 uiop->uio_loffset = uiooffset;
2335 return (ENOSPC);
2337 ld->d_off = uiop->uio_loffset + sizeof (struct pcdir);
2338 ld->d_ino = pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno),
2339 pc_blkoff(fsp, *offset), ep->pcd_attr,
2340 pc_getstartcluster(fsp, ep), pc_direntpersec(fsp));
2341 (void) uiomove((caddr_t)ld, ld->d_reclen, UIO_READ, uiop);
2342 uiop->uio_loffset = ld->d_off;
2343 *offset += sizeof (struct pcdir);
2344 ep++;
2345 *epp = ep;
2346 return (0);
2350 * Read a short filename into the pc_dirent structure and copy it out.
2353 pc_read_short_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld,
2354 struct pcdir **epp, offset_t *offset, struct buf **bp)
2356 struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
2357 int boff = pc_blkoff(fsp, *offset);
2358 struct pcdir *ep = *epp;
2359 offset_t oldoffset = uiop->uio_loffset;
2360 int error;
2361 int foldcase;
2363 if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) {
2364 uiop->uio_loffset += sizeof (struct pcdir);
2365 *offset += sizeof (struct pcdir);
2366 ep++;
2367 *epp = ep;
2368 return (0);
2370 ld->d_ino = (ino64_t)pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno),
2371 boff, ep->pcd_attr, pc_getstartcluster(fsp, ep),
2372 pc_direntpersec(fsp));
2373 foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE);
2374 error = pc_fname_ext_to_name(&ld->d_name[0], &ep->pcd_filename[0],
2375 &ep->pcd_ext[0], foldcase);
2376 if (error == 0) {
2377 ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name));
2378 if (ld->d_reclen > uiop->uio_resid) {
2379 uiop->uio_loffset = oldoffset;
2380 return (ENOSPC);
2382 ld->d_off = (off64_t)(uiop->uio_loffset +
2383 sizeof (struct pcdir));
2384 (void) uiomove((caddr_t)ld,
2385 ld->d_reclen, UIO_READ, uiop);
2386 uiop->uio_loffset = ld->d_off;
2387 } else {
2388 uiop->uio_loffset += sizeof (struct pcdir);
2390 *offset += sizeof (struct pcdir);
2391 ep++;
2392 *epp = ep;
2393 return (0);
2396 /* ARGSUSED */
2397 static int
2398 pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
2400 struct pc_fid *pcfid;
2401 struct pcnode *pcp;
2402 struct pcfs *fsp;
2403 int error;
2405 fsp = VFSTOPCFS(vp->v_vfsp);
2406 if (fsp == NULL)
2407 return (EIO);
2408 error = pc_lockfs(fsp, 0, 0);
2409 if (error)
2410 return (error);
2411 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
2412 pc_unlockfs(fsp);
2413 return (EIO);
2415 if (fidp->fid_len < (sizeof (struct pc_fid) - sizeof (ushort_t))) {
2416 fidp->fid_len = sizeof (struct pc_fid) - sizeof (ushort_t);
2417 pc_unlockfs(fsp);
2418 return (ENOSPC);
2421 pcfid = (struct pc_fid *)fidp;
2422 bzero(pcfid, sizeof (struct pc_fid));
2423 pcfid->pcfid_len = sizeof (struct pc_fid) - sizeof (ushort_t);
2424 if (vp->v_flag & VROOT) {
2425 pcfid->pcfid_block = 0;
2426 pcfid->pcfid_offset = 0;
2427 pcfid->pcfid_ctime = 0;
2428 } else {
2429 pcfid->pcfid_block = pcp->pc_eblkno;
2430 pcfid->pcfid_offset = pcp->pc_eoffset;
2431 pcfid->pcfid_ctime = pcp->pc_entry.pcd_crtime.pct_time;
2433 pc_unlockfs(fsp);
2434 return (0);