1 /* $NetBSD: v7fs_vnops.c,v 1.21 2015/04/20 23:03:08 riastradh Exp $ */
4 * Copyright (c) 2004, 2011 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: v7fs_vnops.c,v 1.21 2015/04/20 23:03:08 riastradh Exp $");
34 #if defined _KERNEL_OPT
38 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/resource.h>
41 #include <sys/vnode.h>
42 #include <sys/namei.h>
43 #include <sys/dirent.h>
45 #include <sys/lockf.h>
46 #include <sys/unistd.h>
47 #include <sys/fcntl.h>
48 #include <sys/kauth.h>
50 #include <sys/stat.h> /*APPEND */
51 #include <miscfs/genfs/genfs.h>
53 #include <fs/v7fs/v7fs.h>
54 #include <fs/v7fs/v7fs_impl.h>
55 #include <fs/v7fs/v7fs_inode.h>
56 #include <fs/v7fs/v7fs_dirent.h>
57 #include <fs/v7fs/v7fs_file.h>
58 #include <fs/v7fs/v7fs_datablock.h>
59 #include <fs/v7fs/v7fs_extern.h>
61 #ifdef V7FS_VNOPS_DEBUG
62 #define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
64 #define DPRINTF(arg...) ((void)0)
67 static v7fs_mode_t
vtype_to_v7fs_mode(enum vtype
);
68 static uint8_t v7fs_mode_to_d_type(v7fs_mode_t
);
71 vtype_to_v7fs_mode(enum vtype type
)
73 /* Convert Vnode types to V7FS types (sys/vnode.h)*/
74 v7fs_mode_t table
[] = { 0, V7FS_IFREG
, V7FS_IFDIR
, V7FS_IFBLK
,
75 V7FS_IFCHR
, V7FSBSD_IFLNK
, V7FSBSD_IFSOCK
,
81 v7fs_mode_to_d_type(v7fs_mode_t mode
)
83 /* Convert V7FS types to dirent d_type (sys/dirent.h)*/
85 return (mode
& V7FS_IFMT
) >> 12;
91 struct vop_lookup_v2_args
/* {
94 struct componentname *a_cnp;
96 struct vnode
*dvp
= a
->a_dvp
;
97 struct v7fs_node
*parent_node
= dvp
->v_data
;
98 struct v7fs_inode
*parent
= &parent_node
->inode
;
99 struct v7fs_self
*fs
= parent_node
->v7fsmount
->core
;/* my filesystem */
101 struct componentname
*cnp
= a
->a_cnp
;
102 int nameiop
= cnp
->cn_nameiop
;
103 const char *name
= cnp
->cn_nameptr
;
104 int namelen
= cnp
->cn_namelen
;
105 int flags
= cnp
->cn_flags
;
106 bool isdotdot
= flags
& ISDOTDOT
;
107 bool islastcn
= flags
& ISLASTCN
;
110 #ifdef V7FS_VNOPS_DEBUG
111 const char *opname
[] = { "LOOKUP", "CREATE", "DELETE", "RENAME" };
113 DPRINTF("'%s' op=%s flags=%d parent=%d %o %dbyte\n", name
,
114 opname
[nameiop
], cnp
->cn_flags
, parent
->inode_number
, parent
->mode
,
119 /* Check directory permission for search */
120 if ((error
= VOP_ACCESS(dvp
, VEXEC
, cnp
->cn_cred
))) {
121 DPRINTF("***perm.\n");
125 /* Deny last component write operation on a read-only mount */
126 if (islastcn
&& (dvp
->v_mount
->mnt_flag
& MNT_RDONLY
) &&
127 (nameiop
== DELETE
|| nameiop
== RENAME
)) {
128 DPRINTF("***ROFS.\n");
132 /* No lookup on removed directory */
133 if (v7fs_inode_nlink(parent
) == 0)
137 if (namelen
== 1 && name
[0] == '.') {
138 if ((nameiop
== RENAME
) && islastcn
) {
139 return EISDIR
; /* t_vnops rename_dir(3) */
141 vref(dvp
); /* v_usecount++ */
143 DPRINTF("done.(.)\n");
147 /* ".." and reguler file. */
148 if ((error
= v7fs_file_lookup_by_name(fs
, parent
, name
, &ino
))) {
149 /* Not found. Tell this entry be able to allocate. */
150 if (((nameiop
== CREATE
) || (nameiop
== RENAME
)) && islastcn
) {
151 /* Check directory permission to allocate. */
152 if ((error
= VOP_ACCESS(dvp
, VWRITE
, cnp
->cn_cred
))) {
153 DPRINTF("access denied. (%s)\n", name
);
156 DPRINTF("EJUSTRETURN op=%d (%s)\n", nameiop
, name
);
159 DPRINTF("lastcn=%d\n", flags
& ISLASTCN
);
163 if ((nameiop
== DELETE
) && islastcn
) {
164 if ((error
= VOP_ACCESS(dvp
, VWRITE
, cnp
->cn_cred
))) {
165 DPRINTF("access denied. (%s)\n", name
);
170 /* Entry found. Allocate v-node */
171 // Check permissions?
174 VOP_UNLOCK(dvp
); /* preserve reference count. (not vput) */
176 DPRINTF("enter vget\n");
177 if ((error
= v7fs_vget(dvp
->v_mount
, ino
, &vpp
))) {
178 DPRINTF("***can't get vnode.\n");
181 DPRINTF("exit vget\n");
183 vn_lock(dvp
, LK_EXCLUSIVE
| LK_RETRY
);
188 DPRINTF("done.(%s)\n", name
);
196 struct vop_create_v3_args
/* {
198 struct vnode **a_vpp;
199 struct componentname *a_cnp;
202 struct v7fs_node
*parent_node
= a
->a_dvp
->v_data
;
203 struct v7fs_mount
*v7fsmount
= parent_node
->v7fsmount
;
204 struct v7fs_self
*fs
= v7fsmount
->core
;
205 struct mount
*mp
= v7fsmount
->mountp
;
206 struct v7fs_fileattr attr
;
207 struct vattr
*va
= a
->a_vap
;
208 kauth_cred_t cr
= a
->a_cnp
->cn_cred
;
212 DPRINTF("%s parent#%d\n", a
->a_cnp
->cn_nameptr
,
213 parent_node
->inode
.inode_number
);
214 KDASSERT((va
->va_type
== VREG
) || (va
->va_type
== VSOCK
));
216 memset(&attr
, 0, sizeof(attr
));
217 attr
.uid
= kauth_cred_geteuid(cr
);
218 attr
.gid
= kauth_cred_getegid(cr
);
219 attr
.mode
= va
->va_mode
| vtype_to_v7fs_mode (va
->va_type
);
222 /* Allocate disk entry. and register its entry to parent directory. */
223 if ((error
= v7fs_file_allocate(fs
, &parent_node
->inode
,
224 a
->a_cnp
->cn_nameptr
, &attr
, &ino
))) {
225 DPRINTF("v7fs_file_allocate failed.\n");
228 /* Sync dirent size change. */
229 uvm_vnp_setsize(a
->a_dvp
, v7fs_inode_filesize(&parent_node
->inode
));
231 /* Get myself vnode. */
233 if ((error
= v7fs_vget(mp
, ino
, a
->a_vpp
))) {
234 DPRINTF("v7fs_vget failed.\n");
238 /* Scheduling update time. real update by v7fs_update */
239 struct v7fs_node
*newnode
= (*a
->a_vpp
)->v_data
;
240 newnode
->update_ctime
= true;
241 newnode
->update_mtime
= true;
242 newnode
->update_atime
= true;
243 DPRINTF("allocated %s->#%d\n", a
->a_cnp
->cn_nameptr
, ino
);
246 VOP_UNLOCK(*a
->a_vpp
);
254 struct vop_mknod_v3_args
/* {
256 struct vnode **a_vpp;
257 struct componentname *a_cnp;
260 struct componentname
*cnp
= a
->a_cnp
;
261 kauth_cred_t cr
= cnp
->cn_cred
;
262 struct vnode
*dvp
= a
->a_dvp
;
263 struct vattr
*va
= a
->a_vap
;
264 struct v7fs_node
*parent_node
= dvp
->v_data
;
265 struct v7fs_mount
*v7fsmount
= parent_node
->v7fsmount
;
266 struct v7fs_self
*fs
= v7fsmount
->core
;
267 struct mount
*mp
= v7fsmount
->mountp
;
268 struct v7fs_fileattr attr
;
273 DPRINTF("%s %06o %lx %d\n", cnp
->cn_nameptr
, va
->va_mode
,
274 (long)va
->va_rdev
, va
->va_type
);
275 memset(&attr
, 0, sizeof(attr
));
276 attr
.uid
= kauth_cred_geteuid(cr
);
277 attr
.gid
= kauth_cred_getegid(cr
);
278 attr
.mode
= va
->va_mode
| vtype_to_v7fs_mode(va
->va_type
);
279 attr
.device
= va
->va_rdev
;
281 if ((error
= v7fs_file_allocate(fs
, &parent_node
->inode
,
282 cnp
->cn_nameptr
, &attr
, &ino
)))
284 /* Sync dirent size change. */
285 uvm_vnp_setsize(dvp
, v7fs_inode_filesize(&parent_node
->inode
));
287 if ((error
= v7fs_vget(mp
, ino
, a
->a_vpp
))) {
288 DPRINTF("can't get vnode.\n");
291 struct v7fs_node
*newnode
= (*a
->a_vpp
)->v_data
;
292 newnode
->update_ctime
= true;
293 newnode
->update_mtime
= true;
294 newnode
->update_atime
= true;
297 VOP_UNLOCK(*a
->a_vpp
);
305 struct vop_open_args
/* {
311 struct vnode
*vp
= a
->a_vp
;
312 struct v7fs_node
*v7node
= vp
->v_data
;
313 struct v7fs_inode
*inode
= &v7node
->inode
;
315 DPRINTF("inode %d\n", inode
->inode_number
);
316 /* Append mode file pointer is managed by kernel. */
317 if (inode
->append_mode
&&
318 ((a
->a_mode
& (FWRITE
| O_APPEND
)) == FWRITE
)) {
319 DPRINTF("file is already opened by append mode.\n");
329 struct vop_close_args
/* {
330 struct vnodeop_desc *a_desc;
335 struct vnode
*vp
= a
->a_vp
;
336 #ifdef V7FS_VNOPS_DEBUG
337 struct v7fs_node
*v7node
= vp
->v_data
;
338 struct v7fs_inode
*inode
= &v7node
->inode
;
340 DPRINTF("#%d (i)%dbyte (v)%zubyte\n", inode
->inode_number
,
341 v7fs_inode_filesize(inode
), vp
->v_size
);
343 /* Update timestamp */
344 v7fs_update(vp
, 0, 0, UPDATE_WAIT
);
350 v7fs_check_possible(struct vnode
*vp
, struct v7fs_node
*v7node
,
354 if (!(mode
& VWRITE
))
357 switch (vp
->v_type
) {
359 /* special file is always writable. */
367 return vp
->v_mount
->mnt_flag
& MNT_RDONLY
? EROFS
: 0;
371 v7fs_check_permitted(struct vnode
*vp
, struct v7fs_node
*v7node
,
372 mode_t mode
, kauth_cred_t cred
)
375 struct v7fs_inode
*inode
= &v7node
->inode
;
377 return kauth_authorize_vnode(cred
, KAUTH_ACCESS_ACTION(mode
,
378 vp
->v_type
, inode
->mode
), vp
, NULL
, genfs_can_access(vp
->v_type
,
379 inode
->mode
, inode
->uid
, inode
->gid
, mode
, cred
));
385 struct vop_access_args
/* {
390 struct vnode
*vp
= ap
->a_vp
;
391 struct v7fs_node
*v7node
= vp
->v_data
;
394 error
= v7fs_check_possible(vp
, v7node
, ap
->a_mode
);
398 error
= v7fs_check_permitted(vp
, v7node
, ap
->a_mode
, ap
->a_cred
);
404 v7fs_getattr(void *v
)
406 struct vop_getattr_args
/* {
411 struct vnode
*vp
= ap
->a_vp
;
412 struct v7fs_node
*v7node
= vp
->v_data
;
413 struct v7fs_inode
*inode
= &v7node
->inode
;
414 struct v7fs_mount
*v7fsmount
= v7node
->v7fsmount
;
415 struct vattr
*vap
= ap
->a_vap
;
418 vap
->va_type
= vp
->v_type
;
419 vap
->va_mode
= inode
->mode
;
420 vap
->va_nlink
= inode
->nlink
;
421 vap
->va_uid
= inode
->uid
;
422 vap
->va_gid
= inode
->gid
;
423 vap
->va_fsid
= v7fsmount
->devvp
->v_rdev
;
424 vap
->va_fileid
= inode
->inode_number
;
425 vap
->va_size
= vp
->v_size
;
426 if (vp
->v_type
== VLNK
) {
427 /* Ajust for trailing NUL. */
428 KASSERT(vap
->va_size
> 0);
431 vap
->va_atime
.tv_sec
= inode
->atime
;
432 vap
->va_mtime
.tv_sec
= inode
->mtime
;
433 vap
->va_ctime
.tv_sec
= inode
->ctime
;
434 vap
->va_birthtime
.tv_sec
= 0;
436 vap
->va_flags
= inode
->append_mode
? SF_APPEND
: 0;
437 vap
->va_rdev
= inode
->device
;
438 vap
->va_bytes
= vap
->va_size
; /* No sparse support. */
441 /* PAGE_SIZE is larger than sizeof(struct dirent). OK.
442 getcwd_scandir()@vfs_getcwd.c */
443 vap
->va_blocksize
= PAGE_SIZE
;
449 v7fs_setattr(void *v
)
451 struct vop_setattr_args
/* {
457 struct vnode
*vp
= ap
->a_vp
;
458 struct vattr
*vap
= ap
->a_vap
;
459 struct v7fs_node
*v7node
= vp
->v_data
;
460 struct v7fs_self
*fs
= v7node
->v7fsmount
->core
;
461 struct v7fs_inode
*inode
= &v7node
->inode
;
462 kauth_cred_t cred
= ap
->a_cred
;
463 struct timespec
*acc
, *mod
;
469 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
470 switch (vp
->v_type
) {
472 /* special file is always writable. */
477 DPRINTF("read-only mount\n");
482 if ((vap
->va_type
!= VNON
) || (vap
->va_nlink
!= VNOVAL
) ||
483 (vap
->va_fsid
!= VNOVAL
) || (vap
->va_fileid
!= VNOVAL
) ||
484 (vap
->va_blocksize
!= VNOVAL
) || (vap
->va_rdev
!= VNOVAL
) ||
485 ((int)vap
->va_bytes
!= VNOVAL
) || (vap
->va_gen
!= VNOVAL
)) {
486 DPRINTF("invalid request\n");
489 /* File pointer mode. */
490 if (vap
->va_flags
!= VNOVAL
) {
491 error
= kauth_authorize_vnode(cred
, KAUTH_VNODE_WRITE_FLAGS
,
492 vp
, NULL
, genfs_can_chflags(cred
, vp
->v_type
, inode
->uid
,
496 inode
->append_mode
= vap
->va_flags
& SF_APPEND
;
499 /* File size change. */
500 if ((vap
->va_size
!= VNOVAL
) && (vp
->v_type
== VREG
)) {
501 error
= v7fs_datablock_size_change(fs
, vap
->va_size
, inode
);
503 uvm_vnp_setsize(vp
, vap
->va_size
);
505 uid_t uid
= inode
->uid
;
506 gid_t gid
= inode
->gid
;
508 if (vap
->va_uid
!= (uid_t
)VNOVAL
) {
510 error
= kauth_authorize_vnode(cred
,
511 KAUTH_VNODE_CHANGE_OWNERSHIP
, vp
, NULL
,
512 genfs_can_chown(cred
, inode
->uid
, inode
->gid
, uid
,
518 if (vap
->va_gid
!= (uid_t
)VNOVAL
) {
520 error
= kauth_authorize_vnode(cred
,
521 KAUTH_VNODE_CHANGE_OWNERSHIP
, vp
, NULL
,
522 genfs_can_chown(cred
, inode
->uid
, inode
->gid
, uid
,
528 if (vap
->va_mode
!= (mode_t
)VNOVAL
) {
529 mode_t mode
= vap
->va_mode
;
530 error
= kauth_authorize_vnode(cred
, KAUTH_VNODE_WRITE_SECURITY
,
531 vp
, NULL
, genfs_can_chmod(vp
->v_type
, cred
, inode
->uid
, inode
->gid
,
536 v7fs_inode_chmod(inode
, mode
);
538 if ((vap
->va_atime
.tv_sec
!= VNOVAL
) ||
539 (vap
->va_mtime
.tv_sec
!= VNOVAL
) ||
540 (vap
->va_ctime
.tv_sec
!= VNOVAL
)) {
541 error
= kauth_authorize_vnode(cred
, KAUTH_VNODE_WRITE_TIMES
, vp
,
542 NULL
, genfs_can_chtimes(vp
, vap
->va_vaflags
, inode
->uid
,
547 if (vap
->va_atime
.tv_sec
!= VNOVAL
) {
548 acc
= &vap
->va_atime
;
550 if (vap
->va_mtime
.tv_sec
!= VNOVAL
) {
551 mod
= &vap
->va_mtime
;
552 v7node
->update_mtime
= true;
554 if (vap
->va_ctime
.tv_sec
!= VNOVAL
) {
555 v7node
->update_ctime
= true;
559 v7node
->update_atime
= true;
560 v7fs_update(vp
, acc
, mod
, 0);
568 struct vop_read_args
/* {
574 struct vnode
*vp
= a
->a_vp
;
575 struct uio
*uio
= a
->a_uio
;
576 struct v7fs_node
*v7node
= vp
->v_data
;
577 struct v7fs_inode
*inode
= &v7node
->inode
;
578 vsize_t sz
, filesz
= v7fs_inode_filesize(inode
);
579 const int advice
= IO_ADV_DECODE(a
->a_ioflag
);
582 DPRINTF("type=%d inode=%d\n", vp
->v_type
, v7node
->inode
.inode_number
);
584 while (uio
->uio_resid
> 0) {
585 if ((sz
= MIN(filesz
- uio
->uio_offset
, uio
->uio_resid
)) == 0)
588 error
= ubc_uiomove(&vp
->v_uobj
, uio
, sz
, advice
, UBC_READ
|
589 UBC_PARTIALOK
| UBC_UNMAP_FLAG(v
));
593 DPRINTF("read %zubyte\n", sz
);
595 v7node
->update_atime
= true;
603 struct vop_write_args
/* {
609 struct vnode
*vp
= a
->a_vp
;
610 struct uio
*uio
= a
->a_uio
;
611 int advice
= IO_ADV_DECODE(a
->a_ioflag
);
612 struct v7fs_node
*v7node
= vp
->v_data
;
613 struct v7fs_inode
*inode
= &v7node
->inode
;
614 struct v7fs_self
*fs
= v7node
->v7fsmount
->core
;
618 if (uio
->uio_resid
== 0)
621 sz
= v7fs_inode_filesize(inode
);
622 DPRINTF("(i)%ld (v)%zu ofs=%zu + res=%zu = %zu\n", sz
, vp
->v_size
,
623 uio
->uio_offset
, uio
->uio_resid
, uio
->uio_offset
+ uio
->uio_resid
);
625 /* Append mode file offset is managed by kernel. */
626 if (a
->a_ioflag
& IO_APPEND
)
627 uio
->uio_offset
= sz
;
629 /* If write region is over filesize, expand. */
630 size_t newsize
= uio
->uio_offset
+ uio
->uio_resid
;
631 ssize_t expand
= newsize
- sz
;
633 if ((error
= v7fs_datablock_expand(fs
, inode
, expand
)))
635 uvm_vnp_setsize(vp
, newsize
);
638 while (uio
->uio_resid
> 0) {
640 if ((error
= ubc_uiomove(&vp
->v_uobj
, uio
, sz
, advice
,
641 UBC_WRITE
| UBC_UNMAP_FLAG(v
))))
643 DPRINTF("write %zubyte\n", sz
);
645 v7node
->update_mtime
= true;
653 struct vop_fsync_args
/* {
660 struct vnode
*vp
= a
->a_vp
;
663 DPRINTF("%p\n", a
->a_vp
);
664 if (a
->a_flags
& FSYNC_CACHE
) {
668 wait
= (a
->a_flags
& FSYNC_WAIT
);
669 error
= vflushbuf(vp
, a
->a_flags
);
671 if (error
== 0 && (a
->a_flags
& FSYNC_DATAONLY
) == 0)
672 error
= v7fs_update(vp
, NULL
, NULL
, wait
? UPDATE_WAIT
: 0);
680 struct vop_remove_args
/* {
681 struct vnodeop_desc *a_desc;
682 struct vnode * a_dvp;
684 struct componentname * a_cnp;
686 struct v7fs_node
*parent_node
= a
->a_dvp
->v_data
;
687 struct v7fs_mount
*v7fsmount
= parent_node
->v7fsmount
;
688 struct vnode
*vp
= a
->a_vp
;
689 struct vnode
*dvp
= a
->a_dvp
;
690 struct v7fs_inode
*inode
= &((struct v7fs_node
*)vp
->v_data
)->inode
;
691 struct v7fs_self
*fs
= v7fsmount
->core
;
694 DPRINTF("delete %s\n", a
->a_cnp
->cn_nameptr
);
696 if (vp
->v_type
== VDIR
) {
701 if ((error
= v7fs_file_deallocate(fs
, &parent_node
->inode
,
702 a
->a_cnp
->cn_nameptr
))) {
703 DPRINTF("v7fs_file_delete failed.\n");
706 error
= v7fs_inode_load(fs
, inode
, inode
->inode_number
);
709 /* Sync dirent size change. */
710 uvm_vnp_setsize(dvp
, v7fs_inode_filesize(&parent_node
->inode
));
714 vrele(vp
); /* v_usecount-- of unlocked vp */
716 vput(vp
); /* unlock vp and then v_usecount-- */
725 struct vop_link_v2_args
/* {
728 struct componentname *a_cnp;
730 struct vnode
*dvp
= a
->a_dvp
;
731 struct vnode
*vp
= a
->a_vp
;
732 struct v7fs_node
*parent_node
= dvp
->v_data
;
733 struct v7fs_node
*node
= vp
->v_data
;
734 struct v7fs_inode
*parent
= &parent_node
->inode
;
735 struct v7fs_inode
*p
= &node
->inode
;
736 struct v7fs_self
*fs
= node
->v7fsmount
->core
;
737 struct componentname
*cnp
= a
->a_cnp
;
741 /* Lock soruce file */
742 if ((error
= vn_lock(vp
, LK_EXCLUSIVE
))) {
743 DPRINTF("lock failed. %p\n", vp
);
744 VOP_ABORTOP(dvp
, cnp
);
747 error
= v7fs_file_link(fs
, parent
, p
, cnp
->cn_nameptr
);
748 /* Sync dirent size change. */
749 uvm_vnp_setsize(dvp
, v7fs_inode_filesize(&parent_node
->inode
));
759 struct vop_rename_args
/* {
760 struct vnode *a_fdvp; from parent-directory
761 struct vnode *a_fvp; from file
762 struct componentname *a_fcnp;
763 struct vnode *a_tdvp; to parent-directory
764 struct vnode *a_tvp; to file
765 struct componentname *a_tcnp;
767 struct vnode
*fvp
= a
->a_fvp
;
768 struct vnode
*tvp
= a
->a_tvp
;
769 struct vnode
*fdvp
= a
->a_fdvp
;
770 struct vnode
*tdvp
= a
->a_tdvp
;
771 struct v7fs_node
*parent_from
= fdvp
->v_data
;
772 struct v7fs_node
*parent_to
= tdvp
->v_data
;
773 struct v7fs_node
*v7node
= fvp
->v_data
;
774 struct v7fs_self
*fs
= v7node
->v7fsmount
->core
;
775 const char *from_name
= a
->a_fcnp
->cn_nameptr
;
776 const char *to_name
= a
->a_tcnp
->cn_nameptr
;
779 DPRINTF("%s->%s %p %p\n", from_name
, to_name
, fvp
, tvp
);
781 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
782 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
784 DPRINTF("cross-device link\n");
787 // XXXsource file lock?
788 error
= v7fs_file_rename(fs
, &parent_from
->inode
, from_name
,
789 &parent_to
->inode
, to_name
);
790 /* 'to file' inode may be changed. (hard-linked and it is cached.)
791 t_vnops rename_reg_nodir */
792 if (error
== 0 && tvp
) {
793 struct v7fs_inode
*inode
=
794 &((struct v7fs_node
*)tvp
->v_data
)->inode
;
796 error
= v7fs_inode_load(fs
, inode
, inode
->inode_number
);
797 uvm_vnp_setsize(tvp
, v7fs_inode_filesize(inode
));
799 /* Sync dirent size change. */
800 uvm_vnp_setsize(tdvp
, v7fs_inode_filesize(&parent_to
->inode
));
801 uvm_vnp_setsize(fdvp
, v7fs_inode_filesize(&parent_from
->inode
));
804 vput(tvp
); /* locked on entry */
818 struct vop_mkdir_v3_args
/* {
820 struct vnode **a_vpp;
821 struct componentname *a_cnp;
824 struct componentname
*cnp
= a
->a_cnp
;
825 kauth_cred_t cr
= cnp
->cn_cred
;
826 struct vnode
*dvp
= a
->a_dvp
;
827 struct vattr
*va
= a
->a_vap
;
828 struct v7fs_node
*parent_node
= dvp
->v_data
;
829 struct v7fs_mount
*v7fsmount
= parent_node
->v7fsmount
;
830 struct v7fs_self
*fs
= v7fsmount
->core
;
831 struct v7fs_fileattr attr
;
832 struct mount
*mp
= v7fsmount
->mountp
;
837 memset(&attr
, 0, sizeof(attr
));
838 attr
.uid
= kauth_cred_geteuid(cr
);
839 attr
.gid
= kauth_cred_getegid(cr
);
840 attr
.mode
= va
->va_mode
| vtype_to_v7fs_mode(va
->va_type
);
842 if ((error
= v7fs_file_allocate(fs
, &parent_node
->inode
,
843 cnp
->cn_nameptr
, &attr
, &ino
)))
845 /* Sync dirent size change. */
846 uvm_vnp_setsize(dvp
, v7fs_inode_filesize(&parent_node
->inode
));
848 if ((error
= v7fs_vget(mp
, ino
, a
->a_vpp
))) {
849 DPRINTF("can't get vnode.\n");
851 struct v7fs_node
*newnode
= (*a
->a_vpp
)->v_data
;
852 newnode
->update_ctime
= true;
853 newnode
->update_mtime
= true;
854 newnode
->update_atime
= true;
857 VOP_UNLOCK(*a
->a_vpp
);
865 struct vop_rmdir_args
/* {
868 struct componentname *a_cnp;
870 struct vnode
*vp
= a
->a_vp
;
871 struct vnode
*dvp
= a
->a_dvp
;
872 struct v7fs_node
*parent_node
= dvp
->v_data
;
873 struct v7fs_mount
*v7fsmount
= parent_node
->v7fsmount
;
874 struct v7fs_inode
*inode
= &((struct v7fs_node
*)vp
->v_data
)->inode
;
875 struct v7fs_self
*fs
= v7fsmount
->core
;
878 DPRINTF("delete %s\n", a
->a_cnp
->cn_nameptr
);
880 KDASSERT(vp
->v_type
== VDIR
);
882 if ((error
= v7fs_file_deallocate(fs
, &parent_node
->inode
,
883 a
->a_cnp
->cn_nameptr
))) {
884 DPRINTF("v7fs_directory_deallocate failed.\n");
887 error
= v7fs_inode_load(fs
, inode
, inode
->inode_number
);
890 uvm_vnp_setsize(vp
, v7fs_inode_filesize(inode
));
891 /* Sync dirent size change. */
892 uvm_vnp_setsize(dvp
, v7fs_inode_filesize(&parent_node
->inode
));
900 struct v7fs_readdir_arg
{
907 static int readdir_subr(struct v7fs_self
*, void *, v7fs_daddr_t
, size_t);
910 readdir_subr(struct v7fs_self
*fs
, void *ctx
, v7fs_daddr_t blk
, size_t sz
)
912 struct v7fs_readdir_arg
*p
= (struct v7fs_readdir_arg
*)ctx
;
913 struct v7fs_dirent
*dir
;
914 struct dirent
*dp
= p
->dp
;
915 struct v7fs_inode inode
;
916 char filename
[V7FS_NAME_MAX
+ 1];
921 if (!(buf
= scratch_read(fs
, blk
)))
923 dir
= (struct v7fs_dirent
*)buf
;
925 n
= sz
/ sizeof(*dir
);
927 for (i
= 0; (i
< n
) && (p
->cnt
< p
->end
); i
++, dir
++, p
->cnt
++) {
928 if (p
->cnt
< p
->start
)
931 if ((error
= v7fs_inode_load(fs
, &inode
, dir
->inode_number
)))
934 v7fs_dirent_filename(filename
, dir
->name
);
936 DPRINTF("inode=%d name=%s %s\n", dir
->inode_number
, filename
,
937 v7fs_inode_isdir(&inode
) ? "DIR" : "FILE");
938 memset(dp
, 0, sizeof(*dp
));
939 dp
->d_fileno
= dir
->inode_number
;
940 dp
->d_type
= v7fs_mode_to_d_type(inode
.mode
);
941 dp
->d_namlen
= strlen(filename
);
942 strcpy(dp
->d_name
, filename
);
943 dp
->d_reclen
= sizeof(*dp
);
944 if ((error
= uiomove(dp
, dp
->d_reclen
, p
->uio
))) {
945 DPRINTF("uiomove failed.\n");
949 scratch_free(fs
, buf
);
951 if (p
->cnt
== p
->end
)
952 return V7FS_ITERATOR_BREAK
;
958 v7fs_readdir(void *v
)
960 struct vop_readdir_args
/* {
968 struct uio
*uio
= a
->a_uio
;
969 struct vnode
*vp
= a
->a_vp
;
970 struct v7fs_node
*v7node
= vp
->v_data
;
971 struct v7fs_inode
*inode
= &v7node
->inode
;
972 struct v7fs_self
*fs
= v7node
->v7fsmount
->core
;
976 DPRINTF("offset=%zu residue=%zu\n", uio
->uio_offset
, uio
->uio_resid
);
978 KDASSERT(vp
->v_type
== VDIR
);
979 KDASSERT(uio
->uio_offset
>= 0);
980 KDASSERT(v7fs_inode_isdir(inode
));
982 struct v7fs_readdir_arg arg
;
983 arg
.start
= uio
->uio_offset
/ sizeof(*dp
);
984 arg
.end
= arg
.start
+ uio
->uio_resid
/ sizeof(*dp
);
985 if (arg
.start
== arg
.end
) {/* user buffer has not enuf space. */
986 DPRINTF("uio buffer too small\n");
989 dp
= kmem_zalloc(sizeof(*dp
), KM_SLEEP
);
994 *a
->a_eofflag
= false;
995 error
= v7fs_datablock_foreach(fs
, inode
, readdir_subr
, &arg
);
996 if (error
== V7FS_ITERATOR_END
) {
997 *a
->a_eofflag
= true;
1002 kmem_free(dp
, sizeof(*dp
));
1008 v7fs_inactive(void *v
)
1010 struct vop_inactive_args
/* {
1014 struct vnode
*vp
= a
->a_vp
;
1015 struct v7fs_node
*v7node
= vp
->v_data
;
1016 struct v7fs_inode
*inode
= &v7node
->inode
;
1018 DPRINTF("%p #%d\n", vp
, inode
->inode_number
);
1019 if (v7fs_inode_nlink(inode
) > 0) {
1020 v7fs_update(vp
, 0, 0, UPDATE_WAIT
);
1021 *a
->a_recycle
= false;
1023 *a
->a_recycle
= true;
1032 v7fs_reclaim(void *v
)
1034 /*This vnode is no longer referenced by kernel. */
1035 extern struct pool v7fs_node_pool
;
1036 struct vop_reclaim_args
/* {
1039 struct vnode
*vp
= a
->a_vp
;
1040 struct v7fs_node
*v7node
= vp
->v_data
;
1041 struct v7fs_self
*fs
= v7node
->v7fsmount
->core
;
1042 struct v7fs_inode
*inode
= &v7node
->inode
;
1044 DPRINTF("%p #%d\n", vp
, inode
->inode_number
);
1045 if (v7fs_inode_nlink(inode
) == 0) {
1046 v7fs_datablock_size_change(fs
, 0, inode
);
1047 DPRINTF("remove datablock\n");
1048 v7fs_inode_deallocate(fs
, inode
->inode_number
);
1049 DPRINTF("remove inode\n");
1051 vcache_remove(vp
->v_mount
,
1052 &inode
->inode_number
, sizeof(inode
->inode_number
));
1053 genfs_node_destroy(vp
);
1054 pool_put(&v7fs_node_pool
, v7node
);
1055 mutex_enter(vp
->v_interlock
);
1057 mutex_exit(vp
->v_interlock
);
1065 struct vop_bmap_args
/* {
1068 struct vnode **a_vpp;
1072 struct vnode
*vp
= a
->a_vp
;
1073 struct v7fs_node
*v7node
= vp
->v_data
;
1074 struct v7fs_mount
*v7fsmount
= v7node
->v7fsmount
;
1075 struct v7fs_self
*fs
= v7node
->v7fsmount
->core
;
1076 struct v7fs_inode
*inode
= &v7node
->inode
;
1079 DPRINTF("inode=%d offset=%zu %p\n", inode
->inode_number
, a
->a_bn
, vp
);
1080 DPRINTF("filesize: %d\n", inode
->filesize
);
1085 if (!(blk
= v7fs_datablock_last(fs
, inode
,
1086 (a
->a_bn
+ 1) << V7FS_BSHIFT
))) {
1087 /* +1 converts block # to file offset. */
1094 *a
->a_vpp
= v7fsmount
->devvp
;
1096 *a
->a_runp
= 0; /*XXX TODO */
1098 DPRINTF("%d %zu->%zu status=%d\n", inode
->inode_number
, a
->a_bn
,
1105 v7fs_strategy(void *v
)
1107 struct vop_strategy_args
/* {
1111 struct buf
*b
= a
->a_bp
;
1112 struct vnode
*vp
= a
->a_vp
;
1113 struct v7fs_node
*v7node
= vp
->v_data
;
1114 struct v7fs_mount
*v7fsmount
= v7node
->v7fsmount
;
1117 DPRINTF("%p\n", vp
);
1118 KDASSERT(vp
->v_type
== VREG
);
1119 if (b
->b_blkno
== b
->b_lblkno
) {
1120 error
= VOP_BMAP(vp
, b
->b_lblkno
, NULL
, &b
->b_blkno
, NULL
);
1126 if ((long)b
->b_blkno
== -1)
1129 if ((long)b
->b_blkno
== -1) {
1134 return VOP_STRATEGY(v7fsmount
->devvp
, b
);
1140 struct vop_print_args
/* {
1143 struct v7fs_node
*v7node
= a
->a_vp
->v_data
;
1145 v7fs_inode_dump(&v7node
->inode
);
1151 v7fs_advlock(void *v
)
1153 struct vop_advlock_args
/* {
1160 struct v7fs_node
*v7node
= a
->a_vp
->v_data
;
1162 DPRINTF("op=%d\n", a
->a_op
);
1164 return lf_advlock(a
, &v7node
->lockf
,
1165 v7fs_inode_filesize(&v7node
->inode
));
1169 v7fs_pathconf(void *v
)
1171 struct vop_pathconf_args
/* {
1174 register_t *a_retval;
1178 DPRINTF("%p\n", a
->a_vp
);
1180 switch (a
->a_name
) {
1182 *a
->a_retval
= V7FS_LINK_MAX
;
1185 *a
->a_retval
= V7FS_NAME_MAX
;
1188 *a
->a_retval
= V7FS_PATH_MAX
;
1190 case _PC_CHOWN_RESTRICTED
:
1199 case _PC_FILESIZEBITS
:
1200 *a
->a_retval
= 30; /* ~1G */
1202 case _PC_SYMLINK_MAX
:
1203 *a
->a_retval
= V7FSBSD_MAXSYMLINKLEN
;
1205 case _PC_2_SYMLINKS
:
1217 v7fs_update(struct vnode
*vp
, const struct timespec
*acc
,
1218 const struct timespec
*mod
, int flags
)
1220 struct v7fs_node
*v7node
= vp
->v_data
;
1221 struct v7fs_inode
*inode
= &v7node
->inode
;
1222 struct v7fs_self
*fs
= v7node
->v7fsmount
->core
;
1223 bool update
= false;
1225 DPRINTF("%p %zu %d\n", vp
, vp
->v_size
, v7fs_inode_filesize(inode
));
1226 KDASSERT(vp
->v_size
== v7fs_inode_filesize(inode
));
1228 if (v7node
->update_atime
) {
1229 inode
->atime
= acc
? acc
->tv_sec
: time_second
;
1230 v7node
->update_atime
= false;
1233 if (v7node
->update_ctime
) {
1234 inode
->ctime
= time_second
;
1235 v7node
->update_ctime
= false;
1238 if (v7node
->update_mtime
) {
1239 inode
->mtime
= mod
? mod
->tv_sec
: time_second
;
1240 v7node
->update_mtime
= false;
1245 v7fs_inode_writeback(fs
, inode
);
1251 v7fs_symlink(void *v
)
1253 struct vop_symlink_v3_args
/* {
1254 struct vnode *a_dvp;
1255 struct vnode **a_vpp;
1256 struct componentname *a_cnp;
1257 struct vattr *a_vap;
1260 struct v7fs_node
*parent_node
= a
->a_dvp
->v_data
;
1261 struct v7fs_mount
*v7fsmount
= parent_node
->v7fsmount
;
1262 struct v7fs_self
*fs
= v7fsmount
->core
;
1263 struct vattr
*va
= a
->a_vap
;
1264 kauth_cred_t cr
= a
->a_cnp
->cn_cred
;
1265 struct componentname
*cnp
= a
->a_cnp
;
1266 struct v7fs_fileattr attr
;
1268 const char *from
= a
->a_target
;
1269 const char *to
= cnp
->cn_nameptr
;
1270 size_t len
= strlen(from
) + 1;
1273 if (len
> V7FS_BSIZE
) { /* limited to 512byte pathname */
1274 DPRINTF("too long pathname.");
1275 return ENAMETOOLONG
;
1278 memset(&attr
, 0, sizeof(attr
));
1279 attr
.uid
= kauth_cred_geteuid(cr
);
1280 attr
.gid
= kauth_cred_getegid(cr
);
1281 attr
.mode
= va
->va_mode
| vtype_to_v7fs_mode(va
->va_type
);
1283 if ((error
= v7fs_file_allocate
1284 (fs
, &parent_node
->inode
, to
, &attr
, &ino
))) {
1287 /* Sync dirent size change. */
1288 uvm_vnp_setsize(a
->a_dvp
, v7fs_inode_filesize(&parent_node
->inode
));
1290 /* Get myself vnode. */
1291 if ((error
= v7fs_vget(v7fsmount
->mountp
, ino
, a
->a_vpp
))) {
1292 DPRINTF("can't get vnode.\n");
1295 struct v7fs_node
*newnode
= (*a
->a_vpp
)->v_data
;
1296 struct v7fs_inode
*p
= &newnode
->inode
;
1297 v7fs_file_symlink(fs
, p
, from
);
1298 uvm_vnp_setsize(*a
->a_vpp
, v7fs_inode_filesize(p
));
1300 newnode
->update_ctime
= true;
1301 newnode
->update_mtime
= true;
1302 newnode
->update_atime
= true;
1305 VOP_UNLOCK(*a
->a_vpp
);
1311 v7fs_readlink(void *v
)
1313 struct vop_readlink_args
/* {
1316 kauth_cred_t a_cred;
1318 struct uio
*uio
= a
->a_uio
;
1319 struct vnode
*vp
= a
->a_vp
;
1320 struct v7fs_node
*v7node
= vp
->v_data
;
1321 struct v7fs_inode
*inode
= &v7node
->inode
;
1322 struct v7fs_self
*fs
= v7node
->v7fsmount
->core
;
1325 KDASSERT(vp
->v_type
== VLNK
);
1326 KDASSERT(uio
->uio_offset
>= 0);
1327 KDASSERT(v7fs_inode_islnk(inode
));
1329 v7fs_daddr_t blk
= inode
->addr
[0];
1331 if (!(buf
= scratch_read(fs
, blk
))) {
1336 if ((error
= uiomove(buf
, strlen(buf
), uio
))) {
1337 DPRINTF("uiomove failed.\n");
1339 scratch_free(fs
, buf
);