1 /* $NetBSD: ulfs_vnops.c,v 1.34 2015/09/21 01:24:23 dholland Exp $ */
2 /* from NetBSD: ufs_vnops.c,v 1.213 2013/06/08 05:47:02 kardel Exp */
5 * Copyright (c) 2008 The NetBSD Foundation, Inc.
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Wasabi Systems, Inc.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 * Copyright (c) 1982, 1986, 1989, 1993, 1995
35 * The Regents of the University of California. All rights reserved.
36 * (c) UNIX System Laboratories, Inc.
37 * All or some portions of this file are derived from material licensed
38 * to the University of California by American Telephone and Telegraph
39 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
40 * the permission of UNIX System Laboratories, Inc.
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * @(#)ufs_vnops.c 8.28 (Berkeley) 7/31/95
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: ulfs_vnops.c,v 1.34 2015/09/21 01:24:23 dholland Exp $");
72 #if defined(_KERNEL_OPT)
74 #include "opt_quota.h"
77 #include <sys/param.h>
78 #include <sys/systm.h>
79 #include <sys/namei.h>
80 #include <sys/resourcevar.h>
81 #include <sys/kernel.h>
86 #include <sys/mount.h>
87 #include <sys/vnode.h>
89 #include <sys/malloc.h>
90 #include <sys/dirent.h>
91 #include <sys/lockf.h>
92 #include <sys/kauth.h>
93 #include <sys/wapbl.h>
94 #include <sys/fstrans.h>
96 #include <miscfs/specfs/specdev.h>
97 #include <miscfs/fifofs/fifo.h>
98 #include <miscfs/genfs/genfs.h>
100 #include <ufs/lfs/lfs_extern.h>
101 #include <ufs/lfs/lfs.h>
102 #include <ufs/lfs/lfs_accessors.h>
104 #include <ufs/lfs/ulfs_inode.h>
105 #include <ufs/lfs/ulfsmount.h>
106 #include <ufs/lfs/ulfs_bswap.h>
107 #include <ufs/lfs/ulfs_extern.h>
109 #include <ufs/lfs/ulfs_dirhash.h>
114 static int ulfs_chmod(struct vnode
*, int, kauth_cred_t
, struct lwp
*);
115 static int ulfs_chown(struct vnode
*, uid_t
, gid_t
, kauth_cred_t
,
127 struct vop_open_args
/* {
134 * Files marked append-only must be opened for appending.
136 if ((VTOI(ap
->a_vp
)->i_flags
& APPEND
) &&
137 (ap
->a_mode
& (FWRITE
| O_APPEND
)) == FWRITE
)
143 ulfs_check_possible(struct vnode
*vp
, struct inode
*ip
, mode_t mode
,
146 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
151 * Disallow write attempts on read-only file systems;
152 * unless the file is a socket, fifo, or a block or
153 * character device resident on the file system.
156 switch (vp
->v_type
) {
160 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
162 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
163 fstrans_start(vp
->v_mount
, FSTRANS_SHARED
);
164 error
= lfs_chkdq(ip
, 0, cred
, 0);
165 fstrans_done(vp
->v_mount
);
181 /* If it is a snapshot, nobody gets access to it. */
182 if ((ip
->i_flags
& SF_SNAPSHOT
))
184 /* If immutable bit set, nobody gets to write it. */
185 if ((mode
& VWRITE
) && (ip
->i_flags
& IMMUTABLE
))
192 ulfs_check_permitted(struct vnode
*vp
, struct inode
*ip
, mode_t mode
,
196 return kauth_authorize_vnode(cred
, KAUTH_ACCESS_ACTION(mode
, vp
->v_type
,
197 ip
->i_mode
& ALLPERMS
), vp
, NULL
, genfs_can_access(vp
->v_type
,
198 ip
->i_mode
& ALLPERMS
, ip
->i_uid
, ip
->i_gid
, mode
, cred
));
204 struct vop_access_args
/* {
218 error
= ulfs_check_possible(vp
, ip
, mode
, ap
->a_cred
);
222 error
= ulfs_check_permitted(vp
, ip
, mode
, ap
->a_cred
);
228 * Set attribute vnode op. called from several syscalls
231 ulfs_setattr(void *v
)
233 struct vop_setattr_args
/* {
245 kauth_action_t action
;
246 bool changing_sysflags
;
254 action
= KAUTH_VNODE_WRITE_FLAGS
;
255 changing_sysflags
= false;
258 * Check for unsettable attributes.
260 if ((vap
->va_type
!= VNON
) || (vap
->va_nlink
!= VNOVAL
) ||
261 (vap
->va_fsid
!= VNOVAL
) || (vap
->va_fileid
!= VNOVAL
) ||
262 (vap
->va_blocksize
!= VNOVAL
) || (vap
->va_rdev
!= VNOVAL
) ||
263 ((int)vap
->va_bytes
!= VNOVAL
) || (vap
->va_gen
!= VNOVAL
)) {
267 fstrans_start(vp
->v_mount
, FSTRANS_SHARED
);
269 if (vap
->va_flags
!= VNOVAL
) {
270 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
275 /* Snapshot flag cannot be set or cleared */
276 if ((vap
->va_flags
& (SF_SNAPSHOT
| SF_SNAPINVAL
)) !=
277 (ip
->i_flags
& (SF_SNAPSHOT
| SF_SNAPINVAL
))) {
282 if (ip
->i_flags
& (SF_IMMUTABLE
| SF_APPEND
)) {
283 action
|= KAUTH_VNODE_HAS_SYSFLAGS
;
286 if ((vap
->va_flags
& SF_SETTABLE
) != (ip
->i_flags
& SF_SETTABLE
)) {
287 action
|= KAUTH_VNODE_WRITE_SYSFLAGS
;
288 changing_sysflags
= true;
291 error
= kauth_authorize_vnode(cred
, action
, vp
, NULL
,
292 genfs_can_chflags(cred
, vp
->v_type
, ip
->i_uid
,
297 if (changing_sysflags
) {
298 ip
->i_flags
= vap
->va_flags
;
299 DIP_ASSIGN(ip
, flags
, ip
->i_flags
);
301 ip
->i_flags
&= SF_SETTABLE
;
302 ip
->i_flags
|= (vap
->va_flags
& UF_SETTABLE
);
303 DIP_ASSIGN(ip
, flags
, ip
->i_flags
);
305 ip
->i_flag
|= IN_CHANGE
;
306 if (vap
->va_flags
& (IMMUTABLE
| APPEND
)) {
311 if (ip
->i_flags
& (IMMUTABLE
| APPEND
)) {
316 * Go through the fields and update iff not VNOVAL.
318 if (vap
->va_uid
!= (uid_t
)VNOVAL
|| vap
->va_gid
!= (gid_t
)VNOVAL
) {
319 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
323 error
= ulfs_chown(vp
, vap
->va_uid
, vap
->va_gid
, cred
, l
);
327 if (vap
->va_size
!= VNOVAL
) {
329 * Disallow write attempts on read-only file systems;
330 * unless the file is a socket, fifo, or a block or
331 * character device resident on the file system.
333 switch (vp
->v_type
) {
342 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
346 if ((ip
->i_flags
& SF_SNAPSHOT
) != 0) {
350 error
= lfs_truncate(vp
, vap
->va_size
, 0, cred
);
360 if (vap
->va_atime
.tv_sec
!= VNOVAL
|| vap
->va_mtime
.tv_sec
!= VNOVAL
||
361 vap
->va_birthtime
.tv_sec
!= VNOVAL
) {
362 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
366 if ((ip
->i_flags
& SF_SNAPSHOT
) != 0) {
370 error
= kauth_authorize_vnode(cred
, KAUTH_VNODE_WRITE_TIMES
, vp
,
371 NULL
, genfs_can_chtimes(vp
, vap
->va_vaflags
, ip
->i_uid
, cred
));
374 if (vap
->va_atime
.tv_sec
!= VNOVAL
)
375 if (!(vp
->v_mount
->mnt_flag
& MNT_NOATIME
))
376 ip
->i_flag
|= IN_ACCESS
;
377 if (vap
->va_mtime
.tv_sec
!= VNOVAL
) {
378 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
379 if (vp
->v_mount
->mnt_flag
& MNT_RELATIME
)
380 ip
->i_flag
|= IN_ACCESS
;
382 if (vap
->va_birthtime
.tv_sec
!= VNOVAL
) {
383 lfs_dino_setbirthtime(fs
, ip
->i_din
,
386 error
= lfs_update(vp
, &vap
->va_atime
, &vap
->va_mtime
, 0);
391 if (vap
->va_mode
!= (mode_t
)VNOVAL
) {
392 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
396 if ((ip
->i_flags
& SF_SNAPSHOT
) != 0 &&
397 (vap
->va_mode
& (S_IXUSR
| S_IWUSR
| S_IXGRP
| S_IWGRP
|
398 S_IXOTH
| S_IWOTH
))) {
402 error
= ulfs_chmod(vp
, (int)vap
->va_mode
, cred
, l
);
404 VN_KNOTE(vp
, NOTE_ATTRIB
);
406 fstrans_done(vp
->v_mount
);
411 * Change the mode on a file.
412 * Inode must be locked before calling.
415 ulfs_chmod(struct vnode
*vp
, int mode
, kauth_cred_t cred
, struct lwp
*l
)
422 error
= kauth_authorize_vnode(cred
, KAUTH_VNODE_WRITE_SECURITY
, vp
,
423 NULL
, genfs_can_chmod(vp
->v_type
, cred
, ip
->i_uid
, ip
->i_gid
, mode
));
427 fstrans_start(vp
->v_mount
, FSTRANS_SHARED
);
428 ip
->i_mode
&= ~ALLPERMS
;
429 ip
->i_mode
|= (mode
& ALLPERMS
);
430 ip
->i_flag
|= IN_CHANGE
;
431 DIP_ASSIGN(ip
, mode
, ip
->i_mode
);
432 fstrans_done(vp
->v_mount
);
437 * Perform chown operation on inode ip;
438 * inode must be locked prior to call.
441 ulfs_chown(struct vnode
*vp
, uid_t uid
, gid_t gid
, kauth_cred_t cred
,
446 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
454 if (uid
== (uid_t
)VNOVAL
)
456 if (gid
== (gid_t
)VNOVAL
)
459 error
= kauth_authorize_vnode(cred
, KAUTH_VNODE_CHANGE_OWNERSHIP
, vp
,
460 NULL
, genfs_can_chown(cred
, ip
->i_uid
, ip
->i_gid
, uid
, gid
));
464 fstrans_start(vp
->v_mount
, FSTRANS_SHARED
);
465 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
468 change
= DIP(ip
, blocks
);
469 (void) lfs_chkdq(ip
, -change
, cred
, 0);
470 (void) lfs_chkiq(ip
, -1, cred
, 0);
473 DIP_ASSIGN(ip
, gid
, gid
);
475 DIP_ASSIGN(ip
, uid
, uid
);
476 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
477 if ((error
= lfs_chkdq(ip
, change
, cred
, 0)) == 0) {
478 if ((error
= lfs_chkiq(ip
, 1, cred
, 0)) == 0)
481 (void) lfs_chkdq(ip
, -change
, cred
, FORCE
);
484 DIP_ASSIGN(ip
, gid
, ogid
);
486 DIP_ASSIGN(ip
, uid
, ouid
);
487 (void) lfs_chkdq(ip
, change
, cred
, FORCE
);
488 (void) lfs_chkiq(ip
, 1, cred
, FORCE
);
489 fstrans_done(vp
->v_mount
);
492 #endif /* LFS_QUOTA || LFS_QUOTA2 */
493 ip
->i_flag
|= IN_CHANGE
;
494 fstrans_done(vp
->v_mount
);
501 struct vop_remove_args
/* {
504 struct componentname *a_cnp;
506 struct vnode
*vp
, *dvp
;
510 struct ulfs_lookup_results
*ulr
;
516 KASSERT(mp
== vp
->v_mount
); /* XXX Not stable without lock. */
518 /* XXX should handle this material another way */
519 ulr
= &VTOI(dvp
)->i_crap
;
520 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp
));
522 fstrans_start(mp
, FSTRANS_SHARED
);
523 if (vp
->v_type
== VDIR
|| (ip
->i_flags
& (IMMUTABLE
| APPEND
)) ||
524 (VTOI(dvp
)->i_flags
& APPEND
))
527 error
= ulfs_dirremove(dvp
, ulr
,
528 ip
, ap
->a_cnp
->cn_flags
, 0);
530 VN_KNOTE(vp
, NOTE_DELETE
);
531 VN_KNOTE(dvp
, NOTE_WRITE
);
542 * ulfs_link: create hard link.
547 struct vop_link_v2_args
/* {
550 struct componentname *a_cnp;
552 struct vnode
*dvp
= ap
->a_dvp
;
553 struct vnode
*vp
= ap
->a_vp
;
554 struct componentname
*cnp
= ap
->a_cnp
;
555 struct mount
*mp
= dvp
->v_mount
;
558 struct ulfs_lookup_results
*ulr
;
561 KASSERT(vp
->v_type
!= VDIR
);
562 KASSERT(mp
== vp
->v_mount
); /* XXX Not stable without lock. */
564 /* XXX should handle this material another way */
565 ulr
= &VTOI(dvp
)->i_crap
;
566 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp
));
568 fstrans_start(mp
, FSTRANS_SHARED
);
569 error
= vn_lock(vp
, LK_EXCLUSIVE
);
571 VOP_ABORTOP(dvp
, cnp
);
575 if ((nlink_t
)ip
->i_nlink
>= LINK_MAX
) {
576 VOP_ABORTOP(dvp
, cnp
);
580 if (ip
->i_flags
& (IMMUTABLE
| APPEND
)) {
581 VOP_ABORTOP(dvp
, cnp
);
586 DIP_ASSIGN(ip
, nlink
, ip
->i_nlink
);
587 ip
->i_flag
|= IN_CHANGE
;
588 error
= lfs_update(vp
, NULL
, NULL
, UPDATE_DIROP
);
590 error
= ulfs_direnter(dvp
, ulr
, vp
,
591 cnp
, ip
->i_number
, LFS_IFTODT(ip
->i_mode
), NULL
);
595 DIP_ASSIGN(ip
, nlink
, ip
->i_nlink
);
596 ip
->i_flag
|= IN_CHANGE
;
601 VN_KNOTE(vp
, NOTE_LINK
);
602 VN_KNOTE(dvp
, NOTE_WRITE
);
608 * whiteout vnode call
611 ulfs_whiteout(void *v
)
613 struct vop_whiteout_args
/* {
615 struct componentname *a_cnp;
618 struct vnode
*dvp
= ap
->a_dvp
;
619 struct componentname
*cnp
= ap
->a_cnp
;
621 struct ulfsmount
*ump
= VFSTOULFS(dvp
->v_mount
);
622 struct lfs
*fs
= ump
->um_lfs
;
623 struct ulfs_lookup_results
*ulr
;
625 /* XXX should handle this material another way */
626 ulr
= &VTOI(dvp
)->i_crap
;
627 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp
));
630 switch (ap
->a_flags
) {
632 /* 4.4 format directories support whiteout operations */
633 if (fs
->um_maxsymlinklen
> 0)
638 /* create a new directory whiteout */
639 fstrans_start(dvp
->v_mount
, FSTRANS_SHARED
);
641 if (fs
->um_maxsymlinklen
<= 0)
642 panic("ulfs_whiteout: old format filesystem");
645 error
= ulfs_direnter(dvp
, ulr
, NULL
,
646 cnp
, ULFS_WINO
, LFS_DT_WHT
, NULL
);
650 /* remove an existing directory whiteout */
651 fstrans_start(dvp
->v_mount
, FSTRANS_SHARED
);
653 if (fs
->um_maxsymlinklen
<= 0)
654 panic("ulfs_whiteout: old format filesystem");
657 cnp
->cn_flags
&= ~DOWHITEOUT
;
658 error
= ulfs_dirremove(dvp
, ulr
, NULL
, cnp
->cn_flags
, 0);
661 panic("ulfs_whiteout: unknown op");
664 fstrans_done(dvp
->v_mount
);
671 struct vop_rmdir_args
/* {
674 struct componentname *a_cnp;
676 struct vnode
*vp
, *dvp
;
677 struct componentname
*cnp
;
678 struct inode
*ip
, *dp
;
680 struct ulfs_lookup_results
*ulr
;
688 /* XXX should handle this material another way */
690 ULFS_CHECK_CRAPCOUNTER(dp
);
693 * No rmdir "." or of mounted directories please.
695 if (dp
== ip
|| vp
->v_mountedhere
!= NULL
) {
704 fstrans_start(dvp
->v_mount
, FSTRANS_SHARED
);
707 * Do not remove a directory that is in the process of being renamed.
708 * Verify that the directory is empty (and valid). (Rmdir ".." won't
709 * be valid since ".." will contain a reference to the current
710 * directory and thus be non-empty.)
713 if (ip
->i_nlink
!= 2 ||
714 !ulfs_dirempty(ip
, dp
->i_number
, cnp
->cn_cred
)) {
718 if ((dp
->i_flags
& APPEND
) ||
719 (ip
->i_flags
& (IMMUTABLE
| APPEND
))) {
724 * Delete reference to directory before purging
725 * inode. If we crash in between, the directory
726 * will be reattached to lost+found,
728 error
= ulfs_dirremove(dvp
, ulr
, ip
, cnp
->cn_flags
, 1);
732 VN_KNOTE(dvp
, NOTE_WRITE
| NOTE_LINK
);
735 * Truncate inode. The only stuff left in the directory is "." and
736 * "..". The "." reference is inconsequential since we're quashing
740 DIP_ASSIGN(dp
, nlink
, dp
->i_nlink
);
741 dp
->i_flag
|= IN_CHANGE
;
743 DIP_ASSIGN(ip
, nlink
, ip
->i_nlink
);
744 ip
->i_flag
|= IN_CHANGE
;
745 error
= lfs_truncate(vp
, (off_t
)0, IO_SYNC
, cnp
->cn_cred
);
748 if (ip
->i_dirhash
!= NULL
)
749 ulfsdirhash_free(ip
);
752 VN_KNOTE(vp
, NOTE_DELETE
);
754 fstrans_done(dvp
->v_mount
);
760 * Vnode op for reading directories.
762 * This routine handles converting from the on-disk directory format
763 * "struct lfs_direct" to the in-memory format "struct dirent" as well as
764 * byte swapping the entries if necessary.
767 ulfs_readdir(void *v
)
769 struct vop_readdir_args
/* {
777 struct vnode
*vp
= ap
->a_vp
;
778 LFS_DIRHEADER
*cdp
, *ecdp
;
780 char *cdbuf
, *ndbuf
, *endp
;
781 struct uio auio
, *uio
;
784 size_t count
, ccount
, rcount
, cdbufsz
, ndbufsz
;
788 struct ulfsmount
*ump
= VFSTOULFS(vp
->v_mount
);
789 struct lfs
*fs
= ump
->um_lfs
;
791 count
= uio
->uio_resid
;
792 rcount
= count
- ((uio
->uio_offset
+ count
) & (fs
->um_dirblksiz
- 1));
794 if (rcount
< LFS_DIRECTSIZ(fs
, 0) || count
< _DIRENT_MINSIZE(ndp
))
797 startoff
= uio
->uio_offset
& ~(fs
->um_dirblksiz
- 1);
798 skipbytes
= uio
->uio_offset
- startoff
;
801 auio
.uio_iov
= &aiov
;
803 auio
.uio_offset
= startoff
;
804 auio
.uio_resid
= rcount
;
805 UIO_SETUP_SYSSPACE(&auio
);
806 auio
.uio_rw
= UIO_READ
;
808 cdbuf
= kmem_alloc(cdbufsz
, KM_SLEEP
);
809 aiov
.iov_base
= cdbuf
;
810 aiov
.iov_len
= rcount
;
811 error
= VOP_READ(vp
, &auio
, 0, ap
->a_cred
);
813 kmem_free(cdbuf
, cdbufsz
);
817 rcount
-= auio
.uio_resid
;
819 cdp
= (LFS_DIRHEADER
*)(void *)cdbuf
;
820 ecdp
= (LFS_DIRHEADER
*)(void *)&cdbuf
[rcount
];
823 ndbuf
= kmem_alloc(ndbufsz
, KM_SLEEP
);
824 ndp
= (struct dirent
*)(void *)ndbuf
;
825 endp
= &ndbuf
[count
];
827 off
= uio
->uio_offset
;
829 ccount
= rcount
/ _DIRENT_RECLEN(ndp
, 1);
830 ccp
= *(ap
->a_cookies
) = malloc(ccount
* sizeof(*ccp
),
840 if (lfs_dir_getreclen(fs
, cdp
) <= skipbytes
) {
841 skipbytes
-= lfs_dir_getreclen(fs
, cdp
);
842 cdp
= LFS_NEXTDIR(fs
, cdp
);
851 if (lfs_dir_getreclen(fs
, cdp
) == 0) {
852 struct dirent
*ondp
= ndp
;
853 ndp
->d_reclen
= _DIRENT_MINSIZE(ndp
);
854 ndp
= _DIRENT_NEXT(ndp
);
859 ndp
->d_type
= lfs_dir_gettype(fs
, cdp
);
860 ndp
->d_namlen
= lfs_dir_getnamlen(fs
, cdp
);
861 ndp
->d_reclen
= _DIRENT_RECLEN(ndp
, ndp
->d_namlen
);
862 if ((char *)(void *)ndp
+ ndp
->d_reclen
+
863 _DIRENT_MINSIZE(ndp
) > endp
)
865 ndp
->d_fileno
= lfs_dir_getino(fs
, cdp
);
866 (void)memcpy(ndp
->d_name
, lfs_dir_nameptr(fs
, cdp
),
868 memset(&ndp
->d_name
[ndp
->d_namlen
], 0,
869 ndp
->d_reclen
- _DIRENT_NAMEOFF(ndp
) - ndp
->d_namlen
);
870 off
+= lfs_dir_getreclen(fs
, cdp
);
872 KASSERT(ccp
- *(ap
->a_cookies
) < ccount
);
875 ndp
= _DIRENT_NEXT(ndp
);
876 cdp
= LFS_NEXTDIR(fs
, cdp
);
879 count
= ((char *)(void *)ndp
- ndbuf
);
880 error
= uiomove(ndbuf
, count
, uio
);
884 free(*(ap
->a_cookies
), M_TEMP
);
885 *(ap
->a_cookies
) = NULL
;
886 *(ap
->a_ncookies
) = 0;
888 *ap
->a_ncookies
= ccp
- *(ap
->a_cookies
);
891 uio
->uio_offset
= off
;
892 kmem_free(ndbuf
, ndbufsz
);
893 kmem_free(cdbuf
, cdbufsz
);
894 *ap
->a_eofflag
= VTOI(vp
)->i_size
<= uio
->uio_offset
;
899 * Return target name of a symbolic link
902 ulfs_readlink(void *v
)
904 struct vop_readlink_args
/* {
909 struct vnode
*vp
= ap
->a_vp
;
910 struct inode
*ip
= VTOI(vp
);
911 struct ulfsmount
*ump
= VFSTOULFS(vp
->v_mount
);
912 struct lfs
*fs
= ump
->um_lfs
;
916 if (isize
< fs
->um_maxsymlinklen
||
917 (fs
->um_maxsymlinklen
== 0 && DIP(ip
, blocks
) == 0)) {
918 uiomove((char *)SHORTLINK(ip
), isize
, ap
->a_uio
);
921 return (lfs_bufrd(vp
, ap
->a_uio
, 0, ap
->a_cred
));
925 * Print out the contents of an inode.
930 struct vop_print_args
/* {
938 printf("tag VT_ULFS, ino %llu, on dev %llu, %llu",
939 (unsigned long long)ip
->i_number
,
940 (unsigned long long)major(ip
->i_dev
),
941 (unsigned long long)minor(ip
->i_dev
));
942 printf(" flags 0x%x, nlink %d\n",
943 ip
->i_flag
, ip
->i_nlink
);
944 printf("\tmode 0%o, owner %d, group %d, size %qd",
945 ip
->i_mode
, ip
->i_uid
, ip
->i_gid
,
946 (long long)ip
->i_size
);
947 if (vp
->v_type
== VFIFO
)
948 VOCALL(fifo_vnodeop_p
, VOFFSET(vop_print
), v
);
954 * Read wrapper for special devices.
957 ulfsspec_read(void *v
)
959 struct vop_read_args
/* {
969 if ((ap
->a_vp
->v_mount
->mnt_flag
& MNT_NODEVMTIME
) == 0)
970 VTOI(ap
->a_vp
)->i_flag
|= IN_ACCESS
;
971 return (VOCALL (spec_vnodeop_p
, VOFFSET(vop_read
), ap
));
975 * Write wrapper for special devices.
978 ulfsspec_write(void *v
)
980 struct vop_write_args
/* {
988 * Set update and change flags.
990 if ((ap
->a_vp
->v_mount
->mnt_flag
& MNT_NODEVMTIME
) == 0)
991 VTOI(ap
->a_vp
)->i_flag
|= IN_MODIFY
;
992 return (VOCALL (spec_vnodeop_p
, VOFFSET(vop_write
), ap
));
996 * Read wrapper for fifo's
999 ulfsfifo_read(void *v
)
1001 struct vop_read_args
/* {
1005 kauth_cred_t a_cred;
1011 VTOI(ap
->a_vp
)->i_flag
|= IN_ACCESS
;
1012 return (VOCALL (fifo_vnodeop_p
, VOFFSET(vop_read
), ap
));
1016 * Write wrapper for fifo's.
1019 ulfsfifo_write(void *v
)
1021 struct vop_write_args
/* {
1025 kauth_cred_t a_cred;
1029 * Set update and change flags.
1031 VTOI(ap
->a_vp
)->i_flag
|= IN_MODIFY
;
1032 return (VOCALL (fifo_vnodeop_p
, VOFFSET(vop_write
), ap
));
1036 * Return POSIX pathconf information applicable to ulfs filesystems.
1039 ulfs_pathconf(void *v
)
1041 struct vop_pathconf_args
/* {
1044 register_t *a_retval;
1047 switch (ap
->a_name
) {
1049 *ap
->a_retval
= LINK_MAX
;
1052 *ap
->a_retval
= LFS_MAXNAMLEN
;
1055 *ap
->a_retval
= PATH_MAX
;
1058 *ap
->a_retval
= PIPE_BUF
;
1060 case _PC_CHOWN_RESTRICTED
:
1069 case _PC_FILESIZEBITS
:
1072 case _PC_SYMLINK_MAX
:
1073 *ap
->a_retval
= MAXPATHLEN
;
1075 case _PC_2_SYMLINKS
:
1085 * Advisory record locking support
1088 ulfs_advlock(void *v
)
1090 struct vop_advlock_args
/* {
1099 ip
= VTOI(ap
->a_vp
);
1100 return lf_advlock(ap
, &ip
->i_lockf
, ip
->i_size
);
1104 * Initialize the vnode associated with a new inode, handle aliased
1108 ulfs_vinit(struct mount
*mntp
, int (**specops
)(void *), int (**fifoops
)(void *),
1115 struct ulfsmount
*ump
;
1119 switch(vp
->v_type
= IFTOVT(ip
->i_mode
)) {
1124 // XXX clean this up
1125 if (ump
->um_fstype
== ULFS1
)
1126 rdev
= (dev_t
)ulfs_rw32(ip
->i_din
->u_32
.di_rdev
,
1127 ULFS_MPNEEDSWAP(ump
->um_lfs
));
1129 rdev
= (dev_t
)ulfs_rw64(ip
->i_din
->u_64
.di_rdev
,
1130 ULFS_MPNEEDSWAP(ump
->um_lfs
));
1131 spec_node_init(vp
, rdev
);
1144 if (ip
->i_number
== ULFS_ROOTINO
)
1145 vp
->v_vflag
|= VV_ROOT
;
1147 * Initialize modrev times
1149 getmicrouptime(&tv
);
1150 ip
->i_modrev
= (uint64_t)(uint
)tv
.tv_sec
<< 32
1151 | tv
.tv_usec
* 4294u;
1156 * Allocate a new inode.
1159 ulfs_makeinode(struct vattr
*vap
, struct vnode
*dvp
,
1160 const struct ulfs_lookup_results
*ulr
,
1161 struct vnode
**vpp
, struct componentname
*cnp
)
1167 error
= vcache_new(dvp
->v_mount
, dvp
, vap
, cnp
->cn_cred
, &tvp
);
1170 error
= vn_lock(tvp
, LK_EXCLUSIVE
);
1175 lfs_mark_vnode(tvp
);
1178 ip
->i_flag
|= IN_ACCESS
| IN_CHANGE
| IN_UPDATE
;
1180 DIP_ASSIGN(ip
, nlink
, 1);
1182 /* Authorize setting SGID if needed. */
1183 if (ip
->i_mode
& ISGID
) {
1184 error
= kauth_authorize_vnode(cnp
->cn_cred
, KAUTH_VNODE_WRITE_SECURITY
,
1185 tvp
, NULL
, genfs_can_chmod(tvp
->v_type
, cnp
->cn_cred
, ip
->i_uid
,
1186 ip
->i_gid
, MAKEIMODE(vap
->va_type
, vap
->va_mode
)));
1188 ip
->i_mode
&= ~ISGID
;
1189 DIP_ASSIGN(ip
, mode
, ip
->i_mode
);
1193 if (cnp
->cn_flags
& ISWHITEOUT
) {
1194 ip
->i_flags
|= UF_OPAQUE
;
1195 DIP_ASSIGN(ip
, flags
, ip
->i_flags
);
1199 * Make sure inode goes to disk before directory entry.
1201 if ((error
= lfs_update(tvp
, NULL
, NULL
, UPDATE_DIROP
)) != 0)
1203 error
= ulfs_direnter(dvp
, ulr
, tvp
,
1204 cnp
, ip
->i_number
, LFS_IFTODT(ip
->i_mode
), NULL
);
1212 * Write error occurred trying to update the inode
1213 * or the directory so must deallocate the inode.
1216 DIP_ASSIGN(ip
, nlink
, 0);
1217 ip
->i_flag
|= IN_CHANGE
;
1218 /* If IN_ADIROP, account for it */
1219 lfs_unmark_vnode(tvp
);
1225 * Allocate len bytes at offset off.
1228 ulfs_gop_alloc(struct vnode
*vp
, off_t off
, off_t len
, int flags
,
1231 struct inode
*ip
= VTOI(vp
);
1232 int error
, delta
, bshift
, bsize
;
1233 UVMHIST_FUNC("ulfs_gop_alloc"); UVMHIST_CALLED(ubchist
);
1236 bshift
= vp
->v_mount
->mnt_fs_bshift
;
1237 bsize
= 1 << bshift
;
1239 delta
= off
& (bsize
- 1);
1244 bsize
= MIN(bsize
, len
);
1246 error
= lfs_balloc(vp
, off
, bsize
, cred
, flags
, NULL
);
1252 * increase file size now, lfs_balloc() requires that
1253 * EOF be up-to-date before each call.
1256 if (ip
->i_size
< off
+ bsize
) {
1257 UVMHIST_LOG(ubchist
, "vp %p old 0x%x new 0x%x",
1258 vp
, ip
->i_size
, off
+ bsize
, 0);
1259 ip
->i_size
= off
+ bsize
;
1260 DIP_ASSIGN(ip
, size
, ip
->i_size
);
1272 ulfs_gop_markupdate(struct vnode
*vp
, int flags
)
1276 if ((flags
& GOP_UPDATE_ACCESSED
) != 0) {
1279 if ((flags
& GOP_UPDATE_MODIFIED
) != 0) {
1280 if (vp
->v_type
== VREG
) {
1281 mask
|= IN_CHANGE
| IN_UPDATE
;
1287 struct inode
*ip
= VTOI(vp
);
1294 ulfs_bufio(enum uio_rw rw
, struct vnode
*vp
, void *buf
, size_t len
, off_t off
,
1295 int ioflg
, kauth_cred_t cred
, size_t *aresid
, struct lwp
*l
)
1301 KASSERT(ISSET(ioflg
, IO_NODELOCKED
));
1302 KASSERT(VOP_ISLOCKED(vp
));
1303 KASSERT(rw
!= UIO_WRITE
|| VOP_ISLOCKED(vp
) == LK_EXCLUSIVE
);
1309 uio
.uio_resid
= len
;
1310 uio
.uio_offset
= off
;
1312 UIO_SETUP_SYSSPACE(&uio
);
1316 error
= lfs_bufrd(vp
, &uio
, ioflg
, cred
);
1319 error
= lfs_bufwr(vp
, &uio
, ioflg
, cred
);
1322 panic("invalid uio rw: %d", (int)rw
);
1326 *aresid
= uio
.uio_resid
;
1327 else if (uio
.uio_resid
&& error
== 0)
1330 KASSERT(VOP_ISLOCKED(vp
));
1331 KASSERT(rw
!= UIO_WRITE
|| VOP_ISLOCKED(vp
) == LK_EXCLUSIVE
);