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]
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>
41 #include <sys/dirent.h>
42 #include <sys/vnode.h>
45 #include <sys/fcntl.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>
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>
60 #include <sys/flock.h>
61 #include <sys/policy.h>
63 #include <sys/sunddi.h>
64 #include <sys/types.h>
65 #include <sys/errno.h>
70 #include <vm/seg_map.h>
71 #include <vm/seg_vn.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
*,
83 static int pcfs_write(struct vnode
*, struct uio
*, int, struct cred
*,
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
*,
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
*,
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
*,
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
*,
127 static int pcfs_pathconf(struct vnode
*, int, ulong_t
*, struct cred
*,
130 int pcfs_putapage(struct vnode
*, page_t
*, uoff_t
*, size_t *, int,
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
= {
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
,
154 .vop_seek
= pcfs_seek
,
155 .vop_space
= pcfs_space
,
156 .vop_getpage
= pcfs_getpage
,
157 .vop_putpage
= pcfs_putpage
,
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
= {
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
,
182 .vop_seek
= pcfs_seek
,
183 .vop_pathconf
= pcfs_pathconf
,
184 .vop_vnevent
= fs_vnevent_support
,
194 caller_context_t
*ct
)
200 * files are sync'ed on close to keep floppy up to date
211 caller_context_t
*ct
)
223 struct caller_context
*ct
)
229 fsp
= VFSTOPCFS(vp
->v_vfsp
);
230 if (error
= pc_verify(fsp
))
232 error
= pc_lockfs(fsp
, 0, 0);
235 if ((pcp
= VTOPC(vp
)) == NULL
|| pcp
->pc_flags
& PC_INVAL
) {
239 error
= rwpcp(pcp
, uiop
, UIO_READ
, ioflag
);
240 if ((fsp
->pcfs_vfs
->vfs_flag
& VFS_RDONLY
) == 0) {
241 pc_mark_acc(fsp
, pcp
);
245 PC_DPRINTF1(1, "pcfs_read: io error = %d\n", error
);
257 struct caller_context
*ct
)
263 fsp
= VFSTOPCFS(vp
->v_vfsp
);
264 if (error
= pc_verify(fsp
))
266 error
= pc_lockfs(fsp
, 0, 0);
269 if ((pcp
= VTOPC(vp
)) == NULL
|| pcp
->pc_flags
& PC_INVAL
) {
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
);
287 PC_DPRINTF1(1, "pcfs_write: io error = %d\n", error
);
293 * read or write a vnode
302 struct vnode
*vp
= PCTOV(pcp
);
304 daddr_t bn
; /* phys block number */
308 int mapon
, pagecreate
;
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
)
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
) {
330 if (uio
->uio_loffset
< 0)
333 if (limit
== RLIM64_INFINITY
|| 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
);
346 /* the following condition will occur only for write */
348 if (uio
->uio_loffset
>= UINT32_MAX
)
351 if (uio
->uio_resid
== 0)
354 if (limit
> UINT32_MAX
)
357 fsp
= VFSTOPCFS(vp
->v_vfsp
);
358 if (fsp
->pcfs_flags
& PCFS_IRRECOV
)
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
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
) {
376 diff
= pcp
->pc_size
- uio
->uio_loffset
;
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
) {
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
402 uio_prefaultpages((long)n
, uio
);
404 base
= segmap_getmap(segkmap
, vp
, (uoff_t
)off
);
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
414 if (uio
->uio_loffset
+ n
> pcp
->pc_size
) {
417 ncl
= (uint_t
)howmany((offset_t
)pcp
->pc_size
,
419 if (uio
->uio_loffset
> pcp
->pc_size
&&
420 ncl
< (uint_t
)howmany(uio
->uio_loffset
,
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
,
435 ncl
< (uint_t
)howmany(uio
->uio_loffset
+ n
,
438 * allocate clusters w/o zerofill
440 error
= pc_balloc(pcp
,
441 (daddr_t
)pc_lblkno(fsp
,
442 uio
->uio_loffset
+ n
- 1),
445 pcp
->pc_flags
|= PC_CHG
;
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
);
467 pcp
->pc_flags
|= PC_INVAL
;
469 (void) segmap_release(segkmap
,
473 pcp
->pc_size
= fsp
->pcfs_clsize
* ncl
;
475 if (error
== ENOSPC
&&
476 (pcp
->pc_size
- uio
->uio_loffset
)
478 PC_DPRINTF3(2, "rwpcp ENOSPC "
479 "off=%lld n=%d size=%d\n",
482 n
= (int)(pcp
->pc_size
-
486 "rwpcp error1=%d\n", error
);
487 (void) segmap_release(segkmap
,
493 (uint_t
)(uio
->uio_loffset
+ n
);
496 newpage
= segmap_pagecreate(segkmap
,
500 } else if (n
== MAXBSIZE
) {
501 newpage
= segmap_pagecreate(segkmap
, base
,
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().
522 segmap_pageunlock(segkmap
, base
, (size_t)n
,
523 rw
== UIO_WRITE
? S_WRITE
: S_READ
);
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
536 (void) segmap_release(segkmap
, base
, SM_INVAL
);
538 (void) segmap_release(segkmap
, base
, 0);
542 if (rw
== UIO_READ
) {
543 if (n
+ mapon
== MAXBSIZE
||
544 uio
->uio_loffset
== pcp
->pc_size
)
546 } else if (ioflag
& (FSYNC
|FDSYNC
)) {
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
)
568 caller_context_t
*ct
)
577 PC_DPRINTF1(8, "pcfs_getattr: vp=%p\n", (void *)vp
);
579 fsp
= VFSTOPCFS(vp
->v_vfsp
);
580 error
= pc_lockfs(fsp
, 0, 0);
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
) {
596 vap
->va_type
= vp
->v_type
;
597 attr
= pcp
->pc_entry
.pcd_attr
;
598 if (PCA_IS_HIDDEN(fsp
, attr
))
600 else if (attr
& PCA_LABEL
)
602 else if (attr
& PCA_RDONLY
)
604 else if (fsp
->pcfs_flags
& PCFS_BOOTPART
) {
611 vap
->va_mode
|= S_IFDIR
;
613 vap
->va_mode
|= S_IFREG
;
614 if (fsp
->pcfs_flags
& PCFS_BOOTPART
) {
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
));
626 vap
->va_size
= (uoff_t
)pcp
->pc_size
;
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
;
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
) {
653 DTRACE_PROBE1(pcfs__mtimeoverflowed
, int64_t, unixtime
);
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
;
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
) {
684 DTRACE_PROBE1(pcfs__atimeoverflowed
, int64_t, unixtime
);
688 vap
->va_atime
.tv_sec
= (time_t)unixtime
;
689 vap
->va_atime
.tv_nsec
= 0;
703 caller_context_t
*ct
)
706 mode_t mask
= vap
->va_mask
;
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
& (AT_NOSET
| AT_UID
| AT_GID
)) {
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
) &&
736 fsp
= VFSTOPCFS(vp
->v_vfsp
);
737 error
= pc_lockfs(fsp
, 0, 0);
740 if ((pcp
= VTOPC(vp
)) == NULL
|| pcp
->pc_flags
& PC_INVAL
) {
745 if (fsp
->pcfs_flags
& PCFS_BOOTPART
) {
746 if (secpolicy_pcfs_modify_bootpartition(cr
) != 0) {
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
& AT_MODE
) && (vap
->va_mode
!= (mode_t
)-1)) {
758 if ((vap
->va_mode
& 0222) == 0)
759 pcp
->pc_entry
.pcd_attr
|= PCA_RDONLY
;
761 pcp
->pc_entry
.pcd_attr
&= ~PCA_RDONLY
;
762 pcp
->pc_flags
|= PC_CHG
;
765 * Truncate file. Must have write permission.
767 if ((mask
& AT_SIZE
) && (vap
->va_size
!= (uoff_t
)-1)) {
768 if (pcp
->pc_entry
.pcd_attr
& PCA_RDONLY
) {
772 if (vap
->va_size
> UINT32_MAX
) {
776 error
= pc_truncate(pcp
, (uint_t
)vap
->va_size
);
781 if (vap
->va_size
== 0)
782 vnevent_truncate(vp
, ct
);
785 * Change file modified times.
787 if (mask
& (AT_MTIME
| AT_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) {
800 if ((fsp
->pcfs_flags
& PCFS_NOCLAMPTIME
) == 0 &&
801 timep
->tv_sec
> INT32_MAX
) {
805 error
= pc_tvtopct(timep
, &pcp
->pc_entry
.pcd_mtime
);
808 pcp
->pc_flags
|= PC_CHG
;
811 * Change file access times.
813 if (mask
& AT_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.
823 timep
= &vap
->va_atime
;
824 if (vap
->va_atime
.tv_sec
== -1) {
828 if ((fsp
->pcfs_flags
& PCFS_NOCLAMPTIME
) == 0 &&
829 timep
->tv_sec
> INT32_MAX
) {
833 error
= pc_tvtopct(timep
, &atime
);
836 pcp
->pc_entry
.pcd_ladate
= atime
.pct_date
;
837 pcp
->pc_flags
|= PC_CHG
;
852 caller_context_t
*ct
)
858 fsp
= VFSTOPCFS(vp
->v_vfsp
);
860 if ((pcp
= VTOPC(vp
)) == NULL
|| pcp
->pc_flags
& PC_INVAL
)
862 if ((mode
& VWRITE
) && (pcp
->pc_entry
.pcd_attr
& PCA_RDONLY
))
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)
884 caller_context_t
*ct
)
890 fsp
= VFSTOPCFS(vp
->v_vfsp
);
891 if (error
= pc_verify(fsp
))
893 error
= pc_lockfs(fsp
, 0, 0);
896 if ((pcp
= VTOPC(vp
)) == NULL
|| pcp
->pc_flags
& PC_INVAL
) {
900 rw_enter(&pcnodes_lock
, RW_WRITER
);
901 error
= pc_nodesync(pcp
);
902 rw_exit(&pcnodes_lock
);
913 caller_context_t
*ct
)
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
) {
929 if (vn_has_cached_data(vp
)) {
930 (void) pvn_vplist_dirty(vp
, 0,
931 pcfs_putapage
, B_INVAL
, NULL
);
937 kmem_free(pcp
, sizeof (struct pcnode
));
938 VFS_RELE(PCFSTOVFS(fsp
));
942 mutex_enter(&vp
->v_lock
);
943 ASSERT(vp
->v_count
>= 1);
944 if (vp
->v_count
> 1) {
946 mutex_exit(&vp
->v_lock
);
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.
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
);
980 struct pathname
*pnp
,
984 caller_context_t
*ct
,
993 * If the filesystem was umounted by force, return immediately.
995 if (dvp
->v_vfsp
->vfs_flag
& VFS_UNMOUNTED
)
999 * verify that the dvp is still valid on the disk
1001 fsp
= VFSTOPCFS(dvp
->v_vfsp
);
1002 if (error
= pc_verify(fsp
))
1004 error
= pc_lockfs(fsp
, 0, 0);
1007 if (VTOPC(dvp
) == NULL
|| VTOPC(dvp
)->pc_flags
& PC_INVAL
) {
1012 * Null component name is a synonym for directory being searched.
1021 error
= pc_dirlook(VTOPC(dvp
), nm
, &pcp
);
1024 pcp
->pc_flags
|= PC_EXTERNAL
;
1037 enum vcexcl exclusive
,
1042 caller_context_t
*ct
,
1051 * can't create directories. use pcfs_mkdir.
1052 * can't create anything other than files.
1054 if (vap
->va_type
== VDIR
)
1056 else if (vap
->va_type
!= VREG
)
1060 fsp
= VFSTOPCFS(dvp
->v_vfsp
);
1061 error
= pc_lockfs(fsp
, 0, 0);
1064 if (VTOPC(dvp
) == NULL
|| VTOPC(dvp
)->pc_flags
& PC_INVAL
) {
1069 if (fsp
->pcfs_flags
& PCFS_BOOTPART
) {
1070 if (secpolicy_pcfs_modify_bootpartition(cr
) != 0) {
1078 * Null component name refers to the directory itself.
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
) {
1092 if (exclusive
== NONEXCL
) {
1093 if (vp
->v_type
== VDIR
) {
1096 error
= pcfs_access(PCTOV(pcp
), mode
, 0,
1103 VN_RELE(PCTOV(pcp
));
1104 } else if ((vp
->v_type
== VREG
) && (vap
->va_mask
& AT_SIZE
) &&
1105 (vap
->va_size
== 0)) {
1106 error
= pc_truncate(pcp
, 0L);
1108 VN_RELE(PCTOV(pcp
));
1110 vnevent_create(PCTOV(pcp
), ct
);
1119 pcp
->pc_flags
|= PC_EXTERNAL
;
1130 caller_context_t
*ct
,
1137 fsp
= VFSTOPCFS(vp
->v_vfsp
);
1138 if (error
= pc_verify(fsp
))
1140 error
= pc_lockfs(fsp
, 0, 0);
1143 if ((pcp
= VTOPC(vp
)) == NULL
|| pcp
->pc_flags
& PC_INVAL
) {
1147 if (fsp
->pcfs_flags
& PCFS_BOOTPART
) {
1148 if (secpolicy_pcfs_modify_bootpartition(cr
) != 0) {
1153 error
= pc_dirremove(pcp
, nm
, NULL
, VREG
, ct
);
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
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 */
1171 caller_context_t
*ct
,
1175 struct pcnode
*dp
; /* parent pcnode */
1179 fsp
= VFSTOPCFS(sdvp
->v_vfsp
);
1180 if (error
= pc_verify(fsp
))
1184 * make sure we can muck with this directory.
1186 error
= pcfs_access(sdvp
, VWRITE
, 0, cr
, ct
);
1190 error
= pc_lockfs(fsp
, 0, 0);
1193 if (((dp
= VTOPC(sdvp
)) == NULL
) || ((tdp
= VTOPC(tdvp
)) == NULL
) ||
1194 (dp
->pc_flags
& PC_INVAL
) || (tdp
->pc_flags
& PC_INVAL
)) {
1198 error
= pc_rename(dp
, tdp
, snm
, tnm
, ct
);
1211 caller_context_t
*ct
,
1219 fsp
= VFSTOPCFS(dvp
->v_vfsp
);
1220 if (error
= pc_verify(fsp
))
1222 error
= pc_lockfs(fsp
, 0, 0);
1225 if (VTOPC(dvp
) == NULL
|| VTOPC(dvp
)->pc_flags
& PC_INVAL
) {
1230 if (fsp
->pcfs_flags
& PCFS_BOOTPART
) {
1231 if (secpolicy_pcfs_modify_bootpartition(cr
) != 0) {
1237 error
= pc_direnter(VTOPC(dvp
), nm
, vap
, &pcp
);
1240 pcp
-> pc_flags
|= PC_EXTERNAL
;
1242 } else if (error
== EEXIST
) {
1243 VN_RELE(PCTOV(pcp
));
1256 caller_context_t
*ct
,
1263 fsp
= VFSTOPCFS(dvp
-> v_vfsp
);
1264 if (error
= pc_verify(fsp
))
1266 if (error
= pc_lockfs(fsp
, 0, 0))
1269 if ((pcp
= VTOPC(dvp
)) == NULL
|| pcp
->pc_flags
& PC_INVAL
) {
1274 if (fsp
->pcfs_flags
& PCFS_BOOTPART
) {
1275 if (secpolicy_pcfs_modify_bootpartition(cr
) != 0) {
1281 error
= pc_dirremove(pcp
, nm
, cdir
, VDIR
, ct
);
1287 * read entries in a directory.
1288 * we must convert pc format to unix format
1298 caller_context_t
*ct
,
1304 struct buf
*bp
= NULL
;
1307 struct pc_dirent lbp
;
1308 struct pc_dirent
*ld
= &lbp
;
1312 * If the filesystem was umounted by force, return immediately.
1314 if (dvp
->v_vfsp
->vfs_flag
& VFS_UNMOUNTED
)
1317 if ((uiop
->uio_iovcnt
!= 1) ||
1318 (uiop
->uio_loffset
% sizeof (struct pcdir
)) != 0) {
1321 fsp
= VFSTOPCFS(dvp
->v_vfsp
);
1323 * verify that the dp is still valid on the disk
1325 if (error
= pc_verify(fsp
)) {
1328 error
= pc_lockfs(fsp
, 0, 0);
1331 if ((pcp
= VTOPC(dvp
)) == NULL
|| pcp
->pc_flags
& PC_INVAL
) {
1336 bzero(ld
, sizeof (*ld
));
1340 offset
= uiop
->uio_loffset
;
1342 if (dvp
->v_flag
& VROOT
) {
1344 * kludge up entries for "." and ".." in the root.
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
) {
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
) {
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 */
1378 boff
= pc_blkoff(fsp
, offset
);
1379 if (boff
== 0 || bp
== NULL
|| boff
>= bp
->b_bcount
) {
1384 error
= pc_blkatoff(pcp
, offset
, &bp
, &ep
);
1386 if (error
== ENOENT
) {
1394 if (ep
->pcd_filename
[0] == PCD_UNUSED
) {
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
);
1408 if (PCDL_IS_LFN(ep
)) {
1409 if (pc_read_long_fn(dvp
, uiop
, ld
, &ep
, &offset
, &bp
) !=
1415 if (pc_read_short_fn(dvp
, uiop
, ld
, &ep
, &offset
, &bp
) != 0)
1426 * Called from pvn_getpages to get a particular page. When we are called
1427 * the pcfs is already locked.
1436 page_t
*pl
[], /* NULL if async IO is requested */
1444 struct pcfs
*fsp
= VFSTOPCFS(vp
->v_vfsp
);
1445 struct vnode
*devvp
;
1451 * If the filesystem was umounted by force, return immediately.
1453 if (vp
->v_vfsp
->vfs_flag
& VFS_UNMOUNTED
)
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
)
1461 devvp
= fsp
->pcfs_devvp
;
1463 /* pcfs doesn't do readaheads */
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
);
1480 if ((pagefound
= page_exists(&vp
->v_object
, off
)) == NULL
) {
1482 * Need to really do disk IO to get the page(s).
1488 uoff_t lbnoff
, xferoffset
;
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);
1501 * XXX - If pcfs is made MT-hot, this should go
1504 panic("pcfs_getapage pvn_read_kluster");
1506 for (pgoff
= 0; pgoff
< PAGESIZE
&& xferoffset
< pcp
->pc_size
;
1508 lbn
+= howmany(xfersize
, fsp
->pcfs_clsize
),
1509 lbnoff
+= xfersize
, xferoffset
+= xfersize
) {
1511 * read as many contiguous blocks as possible to
1514 xfersize
= PAGESIZE
- pgoff
;
1515 err1
= pc_bmap(pcp
, lbn
, &bn
, &xfersize
);
1517 PC_DPRINTF1(1, "pc_getapage err=%d", err1
);
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
;
1527 bp
->b_offset
= (offset_t
)(off
+ pgoff
);
1529 (void) bdev_strategy(bp
);
1531 lwp_stat_update(LWP_STAT_INBLK
, 1);
1541 if (pgoff
< PAGESIZE
) {
1542 pagezero(pp
->p_prev
, pgoff
, PAGESIZE
- pgoff
);
1544 pvn_plist_init(pp
, pl
, plsz
, off
, io_len
, rw
);
1549 pvn_read_done(pp
, B_ERROR
);
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
) {
1568 * Return all the pages from [off..off+len] in given file
1583 caller_context_t
*ct
)
1585 struct pcfs
*fsp
= VFSTOPCFS(vp
->v_vfsp
);
1588 PC_DPRINTF0(6, "pcfs_getpage\n");
1589 if (err
= pc_verify(fsp
))
1591 if (vp
->v_flag
& VNOMAP
)
1593 ASSERT(off
<= UINT32_MAX
);
1594 err
= pc_lockfs(fsp
, 0, 0);
1600 ASSERT((off
& PAGEOFFSET
) == 0);
1601 err
= pvn_getpages(pcfs_getapage
, vp
, off
, len
, protp
, pl
, plsz
,
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
1626 caller_context_t
*ct
)
1637 * If the filesystem was umounted by force, return immediately.
1639 if (vp
->v_vfsp
->vfs_flag
& VFS_UNMOUNTED
)
1642 PC_DPRINTF1(6, "pcfs_putpage vp=0x%p\n", (void *)vp
);
1643 if (vp
->v_flag
& VNOMAP
)
1646 fsp
= VFSTOPCFS(vp
->v_vfsp
);
1648 if (err
= pc_verify(fsp
))
1650 if ((pcp
= VTOPC(vp
)) == NULL
) {
1651 PC_DPRINTF1(3, "pcfs_putpage NULL vp=0x%p\n", (void *)vp
);
1654 if (pcp
->pc_flags
& PC_INVAL
)
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.
1676 ASSERT(off
<= UINT32_MAX
);
1678 flags
&= ~B_ASYNC
; /* XXX should fix this later */
1680 err
= pc_lockfs(fsp
, 0, 0);
1683 if (!vn_has_cached_data(vp
) || off
>= pcp
->pc_size
) {
1690 * Search the entire vp list for pages >= off
1692 err
= pvn_vplist_dirty(vp
, off
,
1693 pcfs_putapage
, flags
, cr
);
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
);
1709 pp
= page_lookup_nowait(&vp
->v_object
,
1711 (flags
& B_FREE
) ? SE_EXCL
: SE_SHARED
);
1714 if (pp
== NULL
|| pvn_getdirty(pp
, flags
) == 0)
1717 err
= pcfs_putapage(vp
, pp
, &io_off
, &io_len
,
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
1739 "pcfs_putpage: B_INVAL, pages not gone");
1741 PC_DPRINTF1(1, "pcfs_putpage err=%d\n", err
);
1748 * Write out a single page, possibly klustering adjacent dirty pages.
1762 struct vnode
*devvp
;
1765 uoff_t lbn
, lbnoff
, xferoffset
;
1766 uint_t pgoff
, xfersize
;
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
,
1788 if (fsp
->pcfs_flags
& PCFS_IRRECOV
) {
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
;
1800 lbn
+= howmany(xfersize
, fsp
->pcfs_clsize
),
1801 lbnoff
+= xfersize
, xferoffset
+= xfersize
) {
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
);
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
;
1821 bp
->b_offset
= (offset_t
)(io_off
+ pgoff
);
1823 (void) bdev_strategy(bp
);
1825 lwp_stat_update(LWP_STAT_OUBLK
, 1);
1833 pvn_write_done(pp
, ((err
) ? B_ERROR
: 0) | B_WRITE
| flags
);
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
);
1847 PC_DPRINTF4(4, "pcfs_putapage: vp=%p pp=%p off=%lld len=%lu\n",
1848 (void *)vp
, (void *)pp
, io_off
, io_len
);
1850 PC_DPRINTF1(1, "pcfs_putapage err=%d", err
);
1867 caller_context_t
*ct
)
1869 struct segvn_crargs vn_a
;
1872 PC_DPRINTF0(6, "pcfs_map\n");
1873 if (vp
->v_flag
& VNOMAP
)
1876 if (off
> UINT32_MAX
|| off
+ len
> UINT32_MAX
)
1880 error
= choose_addr(as
, addrp
, len
, off
, ADDR_VACALIGN
, flags
);
1888 vn_a
.type
= flags
& MAP_TYPE
;
1890 vn_a
.maxprot
= maxprot
;
1891 vn_a
.flags
= flags
& ~MAP_TYPE
;
1895 vn_a
.lgrp_mem_policy_flags
= 0;
1897 error
= as_map(as
, *addrp
, len
, segvn_create
, &vn_a
);
1908 caller_context_t
*ct
)
1912 else if (*noffp
> MAXOFFSET_T
)
1930 caller_context_t
*ct
)
1932 if (vp
->v_flag
& VNOMAP
)
1949 caller_context_t
*ct
)
1951 if (vp
->v_flag
& VNOMAP
)
1957 * POSIX pathconf() support.
1966 caller_context_t
*ct
)
1968 struct pcfs
*fsp
= VFSTOPCFS(vp
->v_vfsp
);
1975 case _PC_CASE_BEHAVIOR
:
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
1984 *valp
= IS_FAT12(fsp
) ? 30 : 33;
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;
1999 return (fs_pathconf(vp
, cmd
, valp
, cr
, ct
));
2009 struct flock64
*bfp
,
2013 caller_context_t
*ct
)
2018 if (cmd
!= F_FREESP
)
2021 if ((error
= convoff(vp
, bfp
, 0, offset
)) == 0) {
2022 if ((bfp
->l_start
> UINT32_MAX
) || (bfp
->l_len
> UINT32_MAX
))
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)
2030 vattr
.va_mask
= AT_SIZE
;
2031 vattr
.va_size
= bfp
->l_start
;
2032 error
= fop_setattr(vp
, (vattr_t
*)&vattr
, 0, cr
, ct
);
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.
2042 set_long_fn_chunk(struct pcdir_lfn
*ep
, char *buf
, int len
)
2046 ASSERT(buf
!= NULL
);
2048 for (i
= 0; i
< PCLF_FIRSTNAMESIZE
; i
+= 2) {
2050 ep
->pcdl_firstfilename
[i
] = *buf
++;
2051 ep
->pcdl_firstfilename
[i
+ 1] = *buf
++;
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) {
2061 ep
->pcdl_secondfilename
[i
] = *buf
++;
2062 ep
->pcdl_secondfilename
[i
+ 1] = *buf
++;
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) {
2071 ep
->pcdl_thirdfilename
[i
] = *buf
++;
2072 ep
->pcdl_thirdfilename
[i
+ 1] = *buf
++;
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.
2086 get_long_fn_chunk(struct pcdir_lfn
*ep
, char *buf
)
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'))
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'))
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'))
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)
2127 pc_checksum_long_fn(char *name
, char *ext
)
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];
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
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
);
2179 size_t u16l
= 0, u8l
= 0;
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);
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
) {
2199 error
= pc_blkatoff(pcp
, *offset
, bp
, &ep
);
2201 kmem_free(lfn_base
, PCMAXNAM_UTF16
);
2202 kmem_free(buf
, PCMAXNAM_UTF16
);
2205 lep
= (struct pcdir_lfn
*)ep
;
2207 /* can this happen? Bad fs? */
2208 if (!PCDL_IS_LFN((struct pcdir
*)lep
)) {
2212 if (cksum
!= lep
->pcdl_checksum
)
2214 /* process current entry */
2215 cs
= get_long_fn_chunk(lep
, buf
);
2217 for (; cs
> 0; cs
--) {
2218 /* see if we underflow */
2219 if (lfn
>= lfn_base
)
2220 *--lfn
= buf
[cs
- 1];
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
) {
2236 error
= pc_blkatoff(pcp
, *offset
, bp
, &ep
);
2238 kmem_free(lfn_base
, PCMAXNAM_UTF16
);
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
))) {
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
2255 kmem_free(lfn_base
, PCMAXNAM_UTF16
);
2258 if (PCA_IS_HIDDEN(fsp
, ep
->pcd_attr
)) {
2260 * Don't display label because it may contain
2263 *offset
+= sizeof (struct pcdir
);
2266 kmem_free(lfn_base
, PCMAXNAM_UTF16
);
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
2281 kmem_free(lfn_base
, PCMAXNAM_UTF16
);
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
,
2293 kmem_free(outbuf
, PCMAXNAMLEN
+ 1);
2294 kmem_free(lfn_base
, PCMAXNAM_UTF16
);
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
);
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
)
2314 struct pcnode
*pcp
= VTOPC(dvp
);
2315 struct pcfs
*fsp
= VFSTOPCFS(dvp
->v_vfsp
);
2316 offset_t uiooffset
= uiop
->uio_loffset
;
2320 oldoffset
= *offset
;
2321 error
= pc_extract_long_fn(pcp
, ld
->d_name
, epp
, offset
, bp
);
2323 if (error
== EINVAL
) {
2324 uiop
->uio_loffset
+= *offset
- oldoffset
;
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
;
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
);
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
;
2363 if (PCA_IS_HIDDEN(fsp
, ep
->pcd_attr
)) {
2364 uiop
->uio_loffset
+= sizeof (struct pcdir
);
2365 *offset
+= sizeof (struct pcdir
);
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
);
2377 ld
->d_reclen
= DIRENT64_RECLEN(strlen(ld
->d_name
));
2378 if (ld
->d_reclen
> uiop
->uio_resid
) {
2379 uiop
->uio_loffset
= oldoffset
;
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
;
2388 uiop
->uio_loffset
+= sizeof (struct pcdir
);
2390 *offset
+= sizeof (struct pcdir
);
2398 pcfs_fid(struct vnode
*vp
, struct fid
*fidp
, caller_context_t
*ct
)
2400 struct pc_fid
*pcfid
;
2405 fsp
= VFSTOPCFS(vp
->v_vfsp
);
2408 error
= pc_lockfs(fsp
, 0, 0);
2411 if ((pcp
= VTOPC(vp
)) == NULL
|| pcp
->pc_flags
& PC_INVAL
) {
2415 if (fidp
->fid_len
< (sizeof (struct pc_fid
) - sizeof (ushort_t
))) {
2416 fidp
->fid_len
= sizeof (struct pc_fid
) - sizeof (ushort_t
);
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;
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
;