2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1998-1999 Apple Computer, Inc. All Rights Reserved.
28 * Modification History:
30 * 02-Feb-2000 Clark Warner Added copyfile to table
31 * 17-Aug-1999 Pat Dirks New today.
34 #include <mach/mach_types.h>
35 #include <mach/machine/boolean.h>
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
44 #include <sys/mount.h>
45 #include <sys/vnode.h>
46 #include <sys/malloc.h>
47 #include <sys/dirent.h>
48 #include <sys/namei.h>
52 #include <sys/errno.h>
53 #include <vfs/vfs_support.h>
60 #error NOT PORTED FOR UBC
61 /* when porting to UBC, do not just replace
62 * vnode_uncache by ubc_uncache - there's more
68 /* external routines defined in vfs_cache.c */
69 extern void cache_purge (struct vnode
*vp
);
70 extern int cache_lookup (struct vnode
*dvp
, struct vnode
**vpp
, struct componentname
*cnp
);
71 extern void cache_enter (struct vnode
*dvp
, struct vnode
*vpp
, struct componentname
*cnp
);
73 //extern void vnode_uncache(struct vnode *);
75 extern int groupmember(gid_t gid
, struct ucred
* cred
);
77 #define VOPFUNC int (*)(void *)
79 /* Global vfs data structures for synthfs. */
80 int (**synthfs_vnodeop_p
) (void *);
81 struct vnodeopv_entry_desc synthfs_vnodeop_entries
[] = {
82 {&vop_default_desc
, (VOPFUNC
)vn_default_error
},
83 {&vop_strategy_desc
, (VOPFUNC
)err_strategy
}, /* strategy - not supported */
84 {&vop_bwrite_desc
, (VOPFUNC
)err_bwrite
}, /* bwrite - not supported */
85 {&vop_lookup_desc
, (VOPFUNC
)synthfs_cached_lookup
}, /* cached lookup */
86 {&vop_create_desc
, (VOPFUNC
)synthfs_create
}, /* create - DEBUGGER */
87 {&vop_whiteout_desc
, (VOPFUNC
)err_whiteout
}, /* whiteout - not supported */
88 {&vop_mknod_desc
, (VOPFUNC
)err_mknod
}, /* mknod - not supported */
89 {&vop_mkcomplex_desc
, (VOPFUNC
)err_mkcomplex
}, /* mkcomplex - not supported */
90 {&vop_open_desc
, (VOPFUNC
)synthfs_open
}, /* open - DEBUGGER */
91 {&vop_close_desc
, (VOPFUNC
)nop_close
}, /* close - NOP */
92 {&vop_access_desc
, (VOPFUNC
)synthfs_access
}, /* access */
93 {&vop_getattr_desc
, (VOPFUNC
)synthfs_getattr
}, /* getattr */
94 {&vop_setattr_desc
, (VOPFUNC
)synthfs_setattr
}, /* setattr */
95 {&vop_getattrlist_desc
, (VOPFUNC
)err_getattrlist
}, /* getattrlist - not supported */
96 {&vop_setattrlist_desc
, (VOPFUNC
)err_setattrlist
}, /* setattrlist - not supported */
97 {&vop_read_desc
, (VOPFUNC
)err_read
}, /* read - not supported */
98 {&vop_write_desc
, (VOPFUNC
)err_write
}, /* write - not supported */
99 {&vop_lease_desc
, (VOPFUNC
)err_lease
}, /* lease - not supported */
100 {&vop_ioctl_desc
, (VOPFUNC
)err_ioctl
}, /* ioctl - not supported */
101 {&vop_select_desc
, (VOPFUNC
)synthfs_select
}, /* select */
102 {&vop_exchange_desc
, (VOPFUNC
)err_exchange
}, /* exchange - not supported */
103 {&vop_revoke_desc
, (VOPFUNC
)nop_revoke
}, /* revoke - NOP */
104 {&vop_mmap_desc
, (VOPFUNC
)synthfs_mmap
}, /* mmap - DEBUGGER */
105 {&vop_fsync_desc
, (VOPFUNC
)nop_fsync
}, /* fsync - NOP */
106 {&vop_seek_desc
, (VOPFUNC
)nop_seek
}, /* seek - NOP */
107 {&vop_remove_desc
, (VOPFUNC
)synthfs_remove
}, /* remove */
108 {&vop_link_desc
, (VOPFUNC
)err_link
}, /* link - not supported */
109 {&vop_rename_desc
, (VOPFUNC
)synthfs_rename
}, /* rename */
110 {&vop_mkdir_desc
, (VOPFUNC
)synthfs_mkdir
}, /* mkdir */
111 {&vop_rmdir_desc
, (VOPFUNC
)synthfs_rmdir
}, /* rmdir */
112 {&vop_symlink_desc
, (VOPFUNC
)synthfs_symlink
}, /* symlink */
113 {&vop_readdir_desc
, (VOPFUNC
)synthfs_readdir
}, /* readdir */
114 {&vop_readdirattr_desc
, (VOPFUNC
)err_readdirattr
}, /* readdirattr - not supported */
115 {&vop_readlink_desc
, (VOPFUNC
)synthfs_readlink
}, /* readlink */
116 {&vop_abortop_desc
, (VOPFUNC
)nop_abortop
}, /* abortop - NOP */
117 {&vop_inactive_desc
, (VOPFUNC
)synthfs_inactive
}, /* inactive */
118 {&vop_reclaim_desc
, (VOPFUNC
)synthfs_reclaim
}, /* reclaim */
119 {&vop_lock_desc
, (VOPFUNC
)synthfs_lock
}, /* lock */
120 {&vop_unlock_desc
, (VOPFUNC
)synthfs_unlock
}, /* unlock */
121 {&vop_bmap_desc
, (VOPFUNC
)err_bmap
}, /* bmap - not supported */
122 {&vop_print_desc
, (VOPFUNC
)err_print
}, /* print - not supported */
123 {&vop_islocked_desc
, (VOPFUNC
)synthfs_islocked
}, /* islocked */
124 {&vop_pathconf_desc
, (VOPFUNC
)synthfs_pathconf
}, /* pathconf */
125 {&vop_advlock_desc
, (VOPFUNC
)err_advlock
}, /* advlock - not supported */
126 {&vop_blkatoff_desc
, (VOPFUNC
)err_blkatoff
}, /* blkatoff - not supported */
127 {&vop_valloc_desc
, (VOPFUNC
)err_valloc
}, /* valloc - not supported */
128 {&vop_reallocblks_desc
, (VOPFUNC
)err_reallocblks
}, /* reallocblks - not supported */
129 {&vop_vfree_desc
, (VOPFUNC
)err_vfree
}, /* vfree - not supported */
130 {&vop_truncate_desc
, (VOPFUNC
)err_truncate
}, /* truncate - not supported */
131 {&vop_allocate_desc
, (VOPFUNC
)err_allocate
}, /* allocate - not supported */
132 {&vop_update_desc
, (VOPFUNC
)synthfs_update
}, /* update */
133 {&vop_pgrd_desc
, (VOPFUNC
)err_pgrd
}, /* pgrd - not supported */
134 {&vop_pgwr_desc
, (VOPFUNC
)err_pgwr
}, /* pgwr - not supported */
135 {&vop_pagein_desc
, (VOPFUNC
)err_pagein
}, /* pagein - not supported */
136 {&vop_pageout_desc
, (VOPFUNC
)err_pageout
}, /* pageout - not supported */
137 {&vop_devblocksize_desc
, (VOPFUNC
)err_devblocksize
}, /* devblocksize - not supported */
138 {&vop_searchfs_desc
, (VOPFUNC
)err_searchfs
}, /* searchfs - not supported */
139 {&vop_copyfile_desc
, (VOPFUNC
)err_copyfile
}, /* copyfile - not supported */
140 { &vop_blktooff_desc
, (VOPFUNC
)err_blktooff
}, /* blktooff not supported */
141 { &vop_offtoblk_desc
, (VOPFUNC
)err_offtoblk
}, /* offtoblk not supported */
142 { &vop_cmap_desc
, (VOPFUNC
)err_cmap
}, /* cmap not supported */
143 {(struct vnodeop_desc
*) NULL
, (int (*) ()) NULL
}
147 * Oh what a tangled web we weave. This structure will be used by
148 * bsd/vfs/vfs_conf.c to actually do the initialization of synthfs_vnodeop_p
150 struct vnodeopv_desc synthfs_vnodeop_opv_desc
=
151 {&synthfs_vnodeop_p
, synthfs_vnodeop_entries
};
156 * Create a regular file
161 IN WILLRELE struct vnode *dvp;
162 OUT struct vnode **vpp;
163 IN struct componentname *cnp;
164 IN struct vattr *vap;
166 We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is
173 struct vop_create_args
/* {
175 struct vnode **a_vpp;
176 struct componentname *a_cnp;
181 struct vnode
*dvp
= ap
->a_dvp
;
184 sprintf(debugmsg
, "synthfs_create: attempt to create '%s' in '%s' ?!", ap
->a_cnp
->cn_nameptr
, VTOS(dvp
)->s_name
);
200 IN struct ucred *cred;
206 struct vop_open_args
/* {
209 struct ucred *a_cred;
213 struct vnode
*vp
= ap
->a_vp
;
215 if (vp
->v_type
== VDIR
) {
219 struct synthfsnode
*sp
= VTOS(vp
);
222 sprintf(debugmsg
, "synthfs_open: attempt to open '/%s' ?!", sp
->s_name
);
235 * NB Currently unsupported.
241 IN struct ucred *cred;
250 struct vop_mmap_args
/* {
253 struct ucred *a_cred;
258 struct vnode
*vp
= ap
->a_vp
;
261 sprintf(debugmsg
, "synthfs_mmap: attempt to map '/%s' ?!", VTOS(vp
)->s_name
);
276 IN struct ucred *cred;
283 struct vop_access_args
/* {
286 struct ucred *a_cred;
290 struct vnode
*vp
= ap
->a_vp
;
291 mode_t mode
= ap
->a_mode
;
292 struct ucred
*cred
= ap
->a_cred
;
293 struct synthfsnode
*sp
= VTOS(vp
);
300 * Disallow write attempts on read-only file systems;
301 * unless the file is a socket, fifo, or a block or
302 * character device resident on the file system.
305 switch (vp
->v_type
) {
309 if (VTOVFS(vp
)->mnt_flag
& MNT_RDONLY
)
317 /* If immutable bit set, nobody gets to write it. */
318 if ((mode
& VWRITE
) && (sp
->s_flags
& IMMUTABLE
))
321 /* Otherwise, user id 0 always gets access. */
322 if (ap
->a_cred
->cr_uid
== 0) {
329 /* Otherwise, check the owner. */
330 if (cred
->cr_uid
== sp
->s_uid
) {
337 retval
= ((sp
->s_mode
& mask
) == mask
? 0 : EACCES
);
341 /* Otherwise, check the groups. */
342 for (i
= 0, gp
= cred
->cr_groups
; i
< cred
->cr_ngroups
; i
++, gp
++)
343 if (sp
->s_gid
== *gp
) {
350 retval
= ((sp
->s_mode
& mask
) == mask
? 0 : EACCES
);
354 /* Otherwise, check everyone else. */
361 retval
= ((sp
->s_mode
& mask
) == mask
? 0 : EACCES
);
372 IN struct vattr *vap;
373 IN struct ucred *cred;
379 struct vop_getattr_args
/* {
382 struct ucred *a_cred;
386 struct vnode
*vp
= ap
->a_vp
;
387 struct vattr
*vap
= ap
->a_vap
;
388 struct synthfsnode
*sp
= VTOS(vp
);
389 struct synthfs_mntdata
*smp
= VTOSFS(vp
);
391 vap
->va_type
= vp
->v_type
;
392 vap
->va_mode
= sp
->s_mode
;
393 vap
->va_nlink
= sp
->s_linkcount
;
394 vap
->va_uid
= sp
->s_uid
;
395 vap
->va_gid
= sp
->s_gid
;
396 vap
->va_fsid
= VTOVFS(vp
)->mnt_stat
.f_fsid
.val
[0];
397 vap
->va_fileid
= sp
->s_nodeid
;
398 switch (vp
->v_type
) {
400 vap
->va_size
= (sp
->s_u
.d
.d_entrycount
+ 2) * sizeof(struct dirent
);
404 vap
->va_size
= sp
->s_u
.f
.f_size
;
408 vap
->va_size
= sp
->s_u
.s
.s_length
;
414 vap
->va_blocksize
= 512;
415 vap
->va_atime
.tv_sec
= sp
->s_accesstime
.tv_sec
;
416 vap
->va_atime
.tv_nsec
= sp
->s_accesstime
.tv_usec
* 1000;
417 vap
->va_mtime
.tv_sec
= sp
->s_modificationtime
.tv_sec
;
418 vap
->va_mtime
.tv_nsec
= sp
->s_modificationtime
.tv_usec
* 1000;
419 vap
->va_ctime
.tv_sec
= sp
->s_changetime
.tv_sec
;
420 vap
->va_ctime
.tv_nsec
= sp
->s_changetime
.tv_usec
* 1000;
421 vap
->va_gen
= sp
->s_generation
;
422 vap
->va_flags
= sp
->s_flags
;
423 vap
->va_rdev
= sp
->s_rdev
;
424 vap
->va_bytes
= vap
->va_blocksize
* ((vap
->va_size
+ vap
->va_blocksize
- 1) / vap
->va_blocksize
);
434 * Change the mode on a file or directory.
435 * vnode vp must be locked on entry.
437 int synthfs_chmod(struct vnode
*vp
, int mode
, struct ucred
*cred
, struct proc
*p
)
439 struct synthfsnode
*sp
= VTOS(vp
);
442 if ((cred
->cr_uid
!= sp
->s_uid
) &&
443 (result
= suser(cred
, &p
->p_acflag
)))
446 if (vp
->v_type
!= VDIR
&& (mode
& S_ISTXT
))
448 if (!groupmember(sp
->s_gid
, cred
) && (mode
& S_ISGID
))
451 sp
->s_mode
&= ~ALLPERMS
;
452 sp
->s_mode
|= (mode
& ALLPERMS
);
453 sp
->s_nodeflags
|= IN_CHANGE
;
455 if ((vp
->v_flag
& VTEXT
) && (sp
->s_mode
& S_ISTXT
) == 0) (void) vnode_uncache(vp
);
464 * Change the flags on a file or directory.
465 * vnode vp must be locked on entry.
467 int synthfs_chflags(struct vnode
*vp
, u_long flags
, struct ucred
*cred
, struct proc
*p
)
469 struct synthfsnode
*sp
= VTOS(vp
);
472 if (cred
->cr_uid
!= sp
->s_uid
&&
473 (result
= suser(cred
, &p
->p_acflag
)))
476 if (cred
->cr_uid
== 0) {
477 if ((sp
->s_flags
& (SF_IMMUTABLE
| SF_APPEND
)) &&
483 if (sp
->s_flags
& (SF_IMMUTABLE
| SF_APPEND
) ||
484 (flags
& UF_SETTABLE
) != flags
) {
487 sp
->s_flags
&= SF_SETTABLE
;
488 sp
->s_flags
|= (flags
& UF_SETTABLE
);
490 sp
->s_nodeflags
|= IN_CHANGE
;
498 * Perform chown operation on vnode vp;
499 * vnode vp must be locked on entry.
501 int synthfs_chown(struct vnode
*vp
, uid_t uid
, gid_t gid
, struct ucred
*cred
, struct proc
*p
)
503 struct synthfsnode
*sp
= VTOS(vp
);
508 if (uid
== (uid_t
)VNOVAL
) uid
= sp
->s_uid
;
509 if (gid
== (gid_t
)VNOVAL
) gid
= sp
->s_gid
;
512 * If we don't own the file, are trying to change the owner
513 * of the file, or are not a member of the target group,
514 * the caller must be superuser or the call fails.
516 if ((cred
->cr_uid
!= sp
->s_uid
|| uid
!= sp
->s_uid
||
517 (gid
!= sp
->s_gid
&& !groupmember((gid_t
)gid
, cred
))) &&
518 (result
= suser(cred
, &p
->p_acflag
)))
527 if (ouid
!= uid
|| ogid
!= gid
) sp
->s_nodeflags
|= IN_CHANGE
;
528 if (ouid
!= uid
&& cred
->cr_uid
!= 0) sp
->s_mode
&= ~S_ISUID
;
529 if (ogid
!= gid
&& cred
->cr_uid
!= 0) sp
->s_mode
&= ~S_ISGID
;
537 * Set attribute vnode op. called from several syscalls
542 IN struct vattr *vap;
543 IN struct ucred *cred;
550 struct vop_setattr_args
/* {
553 struct ucred *a_cred;
557 struct vnode
*vp
= ap
->a_vp
;
558 struct synthfsnode
*sp
= VTOS(vp
);
559 struct vattr
*vap
= ap
->a_vap
;
560 struct ucred
*cred
= ap
->a_cred
;
561 struct proc
*p
= ap
->a_p
;
562 struct timeval atimeval
, mtimeval
;
566 * Check for unsettable attributes.
568 if (((vap
->va_type
!= VNON
) && (vap
->va_type
!= vp
->v_type
)) ||
569 (vap
->va_nlink
!= VNOVAL
) ||
570 (vap
->va_fsid
!= VNOVAL
) || (vap
->va_fileid
!= VNOVAL
) ||
571 (vap
->va_blocksize
!= VNOVAL
) || (vap
->va_rdev
!= VNOVAL
) ||
572 ((int)vap
->va_bytes
!= VNOVAL
) || (vap
->va_gen
!= VNOVAL
)) {
577 if (vap
->va_flags
!= VNOVAL
) {
578 if (VTOVFS(vp
)->mnt_flag
& MNT_RDONLY
) {
582 if ((result
= synthfs_chflags(vp
, vap
->va_flags
, cred
, p
))) {
585 if (vap
->va_flags
& (IMMUTABLE
| APPEND
)) {
591 if (sp
->s_flags
& (IMMUTABLE
| APPEND
)) {
597 * Go through the fields and update iff not VNOVAL.
599 if (vap
->va_uid
!= (uid_t
)VNOVAL
|| vap
->va_gid
!= (gid_t
)VNOVAL
) {
600 if (VTOVFS(vp
)->mnt_flag
& MNT_RDONLY
) {
604 if ((result
= synthfs_chown(vp
, vap
->va_uid
, vap
->va_gid
, cred
, p
))) {
608 if (vap
->va_size
!= VNOVAL
) {
610 * Disallow write attempts on read-only file systems;
611 * unless the file is a socket, fifo, or a block or
612 * character device resident on the file system.
614 switch (vp
->v_type
) {
620 if (VTOVFS(vp
)->mnt_flag
& MNT_RDONLY
) {
629 if ((result
= VOP_TRUNCATE(vp
, vap
->va_size
, 0, cred
, p
))) {
639 if (vap
->va_atime
.tv_sec
!= VNOVAL
|| vap
->va_mtime
.tv_sec
!= VNOVAL
) {
640 if (VTOVFS(vp
)->mnt_flag
& MNT_RDONLY
) {
644 if (cred
->cr_uid
!= sp
->s_uid
&&
645 (result
= suser(cred
, &p
->p_acflag
)) &&
646 ((vap
->va_vaflags
& VA_UTIMES_NULL
) == 0 ||
647 (result
= VOP_ACCESS(vp
, VWRITE
, cred
, p
)))) {
650 if (vap
->va_atime
.tv_sec
!= VNOVAL
)
651 sp
->s_nodeflags
|= IN_ACCESS
;
652 if (vap
->va_mtime
.tv_sec
!= VNOVAL
)
653 sp
->s_nodeflags
|= IN_CHANGE
| IN_UPDATE
;
654 atimeval
.tv_sec
= vap
->va_atime
.tv_sec
;
655 atimeval
.tv_usec
= vap
->va_atime
.tv_nsec
/ 1000;
656 mtimeval
.tv_sec
= vap
->va_mtime
.tv_sec
;
657 mtimeval
.tv_usec
= vap
->va_mtime
.tv_nsec
/ 1000;
658 if ((result
= VOP_UPDATE(vp
, &atimeval
, &mtimeval
, 1))) {
664 if (vap
->va_mode
!= (mode_t
)VNOVAL
) {
665 if (VTOVFS(vp
)->mnt_flag
& MNT_RDONLY
) {
669 result
= synthfs_chmod(vp
, (int)vap
->va_mode
, cred
, p
);
674 DBG_VOP(("synthfs_setattr: returning %d...\n", result
));
683 #% rename sourcePar_vp U U U
684 #% rename source_vp U U U
685 #% rename targetPar_vp L U U
686 #% rename target_vp X U U
689 IN WILLRELE struct vnode *sourcePar_vp;
690 IN WILLRELE struct vnode *source_vp;
691 IN struct componentname *source_cnp;
692 IN WILLRELE struct vnode *targetPar_vp;
693 IN WILLRELE struct vnode *target_vp;
694 IN struct componentname *target_cnp;
701 * source's parent directory is unlocked
702 * source file or directory is unlocked
703 * destination's parent directory is locked
704 * destination file or directory is locked if it exists
707 * all denodes should be released
713 struct vop_rename_args
/* {
714 struct vnode *a_fdvp;
716 struct componentname *a_fcnp;
717 struct vnode *a_tdvp;
719 struct componentname *a_tcnp;
722 struct vnode
*target_vp
= ap
->a_tvp
;
723 struct vnode
*targetPar_vp
= ap
->a_tdvp
;
724 struct vnode
*source_vp
= ap
->a_fvp
;
725 struct vnode
*sourcePar_vp
= ap
->a_fdvp
;
726 struct componentname
*target_cnp
= ap
->a_tcnp
;
727 struct componentname
*source_cnp
= ap
->a_fcnp
;
728 struct proc
*p
= source_cnp
->cn_proc
;
729 struct synthfsnode
*target_sp
, *targetPar_sp
, *source_sp
, *sourcePar_sp
;
730 u_short doingdirectory
= 0, oldparent
= 0, newparent
= 0;
734 #if SYNTHFS_DIAGNOSTIC
735 if ((target_cnp
->cn_flags
& HASBUF
) == 0 ||
736 (source_cnp
->cn_flags
& HASBUF
) == 0)
737 panic("synthfs_rename: no name");
740 DBG_ASSERT((ap
->a_fdvp
->v_type
== VDIR
) && (ap
->a_tdvp
->v_type
== VDIR
));
741 target_sp
= targetPar_sp
= source_sp
= sourcePar_sp
= NULL
;
744 * Check for cross-device rename.
746 if ((source_vp
->v_mount
!= targetPar_vp
->v_mount
) ||
747 (target_vp
&& (source_vp
->v_mount
!= target_vp
->v_mount
))) {
753 * Check for access permissions
755 if (target_vp
&& ((VTOS(target_vp
)->s_pflags
& (IMMUTABLE
| APPEND
)) ||
756 (VTOS(targetPar_vp
)->s_pflags
& APPEND
))) {
761 if ((retval
= vn_lock(source_vp
, LK_EXCLUSIVE
, p
)))
764 sourcePar_sp
= VTOS(sourcePar_vp
);
765 source_sp
= VTOS(source_vp
);
766 oldparent
= sourcePar_sp
->s_nodeid
;
767 if ((source_sp
->s_pflags
& (IMMUTABLE
| APPEND
)) || (sourcePar_sp
->s_pflags
& APPEND
)) {
768 VOP_UNLOCK(source_vp
, 0, p
);
774 * Be sure we are not renaming ".", "..", or an alias of ".". This
775 * leads to a crippled directory tree. It's pretty tough to do a
776 * "ls" or "pwd" with the "." directory entry missing, and "cd .."
777 * doesn't work if the ".." entry is missing.
779 if (source_sp
->s_type
== SYNTHFS_DIRECTORY
) {
780 if ((source_cnp
->cn_namelen
== 1 && source_cnp
->cn_nameptr
[0] == '.')
781 || sourcePar_sp
== source_sp
782 || (source_cnp
->cn_flags
& ISDOTDOT
)
783 || (source_sp
->s_nodeflags
& IN_RENAME
)) {
784 VOP_UNLOCK(source_vp
, 0, p
);
788 source_sp
->s_nodeflags
|= IN_RENAME
;
789 doingdirectory
= TRUE
;
792 /* Transit between abort and bad */
794 targetPar_sp
= VTOS(targetPar_vp
);
795 target_sp
= target_vp
? VTOS(target_vp
) : NULL
;
796 newparent
= targetPar_sp
->s_nodeid
;
798 retval
= VOP_ACCESS(source_vp
, VWRITE
, target_cnp
->cn_cred
, target_cnp
->cn_proc
);
799 if (doingdirectory
&& (newparent
!= oldparent
)) {
800 if (retval
) /* write access check above */
805 * If the destination exists, then be sure its type (file or dir)
806 * matches that of the source. And, if it is a directory make sure
807 * it is empty. Then delete the destination.
811 * If the parent directory is "sticky", then the user must
812 * own the parent directory, or the destination of the rename,
813 * otherwise the destination may not be changed (except by
814 * root). This implements append-only directories.
816 if ((targetPar_sp
->s_mode
& S_ISTXT
) && target_cnp
->cn_cred
->cr_uid
!= 0 &&
817 target_cnp
->cn_cred
->cr_uid
!= targetPar_sp
->s_uid
&&
818 target_sp
->s_uid
!= target_cnp
->cn_cred
->cr_uid
) {
824 * VOP_REMOVE will vput targetPar_vp so we better bump
825 * its ref count and relockit, always set target_vp to
826 * NULL afterwards to indicate that were done with it.
830 if (target_vp
->v_type
== VREG
) {
831 (void) vnode_uncache(target_vp
);
834 cache_purge(target_vp
);
836 target_cnp
->cn_flags
&= ~SAVENAME
;
837 retval
= VOP_REMOVE(targetPar_vp
, target_vp
, target_cnp
);
838 (void) vn_lock(targetPar_vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
843 if (retval
) goto bad
;
847 if (newparent
!= oldparent
)
848 vn_lock(sourcePar_vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
850 /* remove the existing entry from the namei cache: */
851 if (source_vp
->v_type
== VREG
) cache_purge(source_vp
);
853 retval
= synthfs_move_rename_entry( source_vp
, targetPar_vp
, target_cnp
->cn_nameptr
);
855 if (newparent
!= oldparent
)
856 VOP_UNLOCK(sourcePar_vp
, 0, p
);
858 if (retval
) goto bad
;
860 source_sp
->s_nodeflags
&= ~IN_RENAME
;
863 * Timestamp both parent directories.
864 * Note that if this is a rename within the same directory,
865 * (where targetPar_hp == sourcePar_hp)
866 * the code below is still safe and correct.
868 targetPar_sp
->s_nodeflags
|= IN_UPDATE
;
869 sourcePar_sp
->s_nodeflags
|= IN_UPDATE
;
871 SYNTHFSTIMES(targetPar_sp
, &tv
, &tv
);
872 SYNTHFSTIMES(sourcePar_sp
, &tv
, &tv
);
881 if (retval
&& doingdirectory
)
882 source_sp
->s_nodeflags
&= ~IN_RENAME
;
884 if (targetPar_vp
== target_vp
)
894 if (VOP_ISLOCKED(source_vp
))
903 VOP_ABORTOP(targetPar_vp
, target_cnp
); /* XXX, why not in NFS? */
905 if (targetPar_vp
== target_vp
)
913 VOP_ABORTOP(sourcePar_vp
, source_cnp
); /* XXX, why not in NFS? */
930 IN WILLRELE struct vnode *dvp;
931 OUT struct vnode **vpp;
932 IN struct componentname *cnp;
933 IN struct vattr *vap;
935 We are responsible for freeing the namei buffer, it is done in synthfs_makenode(), unless there is
942 struct vop_mkdir_args
/* {
944 struct vnode **a_vpp;
945 struct componentname *a_cnp;
950 struct vnode
*dvp
= ap
->a_dvp
;
951 struct componentname
*cnp
= ap
->a_cnp
;
952 int mode
= MAKEIMODE(ap
->a_vap
->va_type
, ap
->a_vap
->va_mode
);
953 struct vnode
*vp
= NULL
;
957 retval
= synthfs_new_directory(VTOVFS(dvp
), dvp
, cnp
->cn_nameptr
, VTOSFS(dvp
)->synthfs_nextid
++, mode
, ap
->a_cnp
->cn_proc
, &vp
);
958 if (retval
) goto Error_Exit
;
960 retval
= VOP_SETATTR(vp
, ap
->a_vap
, cnp
->cn_cred
, cnp
->cn_proc
);
961 if (retval
!= 0) goto Error_Exit
;
967 if (vp
) synthfs_remove_directory(vp
);
968 VOP_ABORTOP(dvp
, cnp
);
983 IN WILLRELE struct vnode *dvp;
984 IN WILLRELE struct vnode *vp;
985 IN struct componentname *cnp;
991 struct vop_remove_args
/* {
994 struct componentname *a_cnp;
997 struct vnode
*vp
= ap
->a_vp
;
998 struct vnode
*dvp
= ap
->a_dvp
;
999 struct synthfsnode
*sp
= VTOS(vp
);
1003 if ((sp
->s_flags
& (IMMUTABLE
| APPEND
)) ||
1004 (VTOS(dvp
)->s_flags
& APPEND
)) {
1009 /* This is sort of silly right now but someday it may make sense... */
1010 if (sp
->s_nodeflags
& IN_MODIFIED
) {
1012 VOP_UPDATE(vp
, &tv
, &tv
, 0);
1015 /* remove the entry from the namei cache: */
1018 /* remove entry from tree and reclaim any resources consumed: */
1019 switch (sp
->s_type
) {
1020 case SYNTHFS_DIRECTORY
:
1021 synthfs_remove_directory(vp
);
1025 case SYNTHFS_SYMLINK
:
1026 synthfs_remove_symlink(vp
);
1030 /* Fall through to default case */
1033 synthfs_remove_entry(vp
);
1039 VTOS(dvp
)->s_nodeflags
|= IN_CHANGE
| IN_UPDATE
;
1058 IN WILLRELE struct vnode *dvp;
1059 IN WILLRELE struct vnode *vp;
1060 IN struct componentname *cnp;
1066 struct vop_rmdir_args
/* {
1067 struct vnode *a_dvp;
1069 struct componentname *a_cnp;
1072 DBG_VOP(("synthfs_rmdir called\n"));
1073 return synthfs_remove((struct vop_remove_args
*)ap
);
1079 * synthfs_select - just say OK. Only possible op is readdir
1081 * Locking policy: ignore
1085 struct vop_select_args
/* {
1089 struct ucred *a_cred;
1094 DBG_VOP(("synthfs_select called\n"));
1101 #% symlink dvp L U U
1102 #% symlink vpp - U -
1104 # XXX - note that the return vnode has already been vrele'ed
1105 # by the filesystem layer. To use it you must use vget,
1106 # possibly with a further namei.
1109 IN WILLRELE struct vnode *dvp;
1110 OUT WILLRELE struct vnode **vpp;
1111 IN struct componentname *cnp;
1112 IN struct vattr *vap;
1115 We are responsible for freeing the namei buffer, it is done in synthfs_makenode(), unless there is
1123 struct vop_symlink_args
/* {
1124 struct vnode *a_dvp;
1125 struct vnode **a_vpp;
1126 struct componentname *a_cnp;
1127 struct vattr *a_vap;
1131 struct vnode
*dvp
= ap
->a_dvp
;
1132 struct vnode
**vpp
= ap
->a_vpp
;
1133 struct componentname
*cnp
= ap
->a_cnp
;
1138 retval
= synthfs_new_symlink(VTOVFS(dvp
), dvp
, cnp
->cn_nameptr
, VTOSFS(dvp
)->synthfs_nextid
++, ap
->a_target
, ap
->a_cnp
->cn_proc
, vpp
);
1139 if (retval
) goto Error_Exit
;
1141 VOP_UNLOCK(*vpp
, 0, cnp
->cn_proc
);
1146 VOP_ABORTOP(dvp
, cnp
);
1157 #% readlink vp L L L
1160 IN struct vnode *vp;
1161 INOUT struct uio *uio;
1162 IN struct ucred *cred;
1166 synthfs_readlink(ap
)
1167 struct vop_readlink_args
/* {
1170 struct ucred *a_cred;
1173 struct vnode
*vp
= ap
->a_vp
;
1174 struct synthfsnode
*sp
= VTOS(vp
);
1175 struct uio
*uio
= ap
->a_uio
;
1177 unsigned long count
;
1179 if (ap
->a_uio
->uio_offset
> sp
->s_u
.s
.s_length
) {
1183 if (uio
->uio_offset
+ uio
->uio_resid
<= sp
->s_u
.s
.s_length
) {
1184 count
= uio
->uio_resid
;
1186 count
= sp
->s_u
.s
.s_length
- uio
->uio_offset
;
1188 retval
= uiomove((void *)((unsigned char *)sp
->s_u
.s
.s_symlinktarget
+ uio
->uio_offset
), count
, uio
);
1202 IN struct vnode *vp;
1203 INOUT struct uio *uio;
1204 IN struct ucred *cred;
1207 INOUT u_long **cookies;
1213 struct vop_readdir_args
/* {
1222 struct synthfsnode
*sp
= VTOS(ap
->a_vp
);
1223 register struct uio
*uio
= ap
->a_uio
;
1224 off_t diroffset
; /* Offset into simulated directory file */
1225 struct synthfsnode
*entry
;
1227 DBG_VOP(("\tuio_offset = %d, uio_resid = %d\n", (int) uio
->uio_offset
, uio
->uio_resid
));
1229 /* We assume it's all one big buffer... */
1230 if (uio
->uio_iovcnt
> 1) {
1231 DBG_VOP(("\tuio->uio_iovcnt = %d?\n", uio
->uio_iovcnt
));
1236 NFS cookies are not supported:
1238 if ((ap
->a_cookies
!= NULL
) || (ap
->a_ncookies
!= NULL
)) {
1245 * We must synthesize . and ..
1247 DBG_VOP(("\tstarting ... uio_offset = %d, uio_resid = %d\n", (int) uio
->uio_offset
, uio
->uio_resid
));
1248 if (uio
->uio_offset
== diroffset
)
1250 DBG_VOP(("\tAdding .\n"));
1251 diroffset
+= synthfs_adddirentry(sp
->s_nodeid
, DT_DIR
, ".", uio
);
1252 DBG_VOP(("\t after adding ., uio_offset = %d, uio_resid = %d\n", (int) uio
->uio_offset
, uio
->uio_resid
));
1254 if ((uio
->uio_resid
> 0) && (diroffset
> uio
->uio_offset
)) {
1255 /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */
1259 if (uio
->uio_offset
== diroffset
)
1261 DBG_VOP(("\tAdding ..\n"));
1262 if (sp
->s_parent
!= NULL
) {
1263 diroffset
+= synthfs_adddirentry(sp
->s_parent
->s_nodeid
, DT_DIR
, "..", uio
);
1265 diroffset
+= synthfs_adddirentry(sp
->s_nodeid
, DT_DIR
, "..", uio
);
1267 DBG_VOP(("\t after adding .., uio_offset = %d, uio_resid = %d\n", (int) uio
->uio_offset
, uio
->uio_resid
));
1269 if ((uio
->uio_resid
> 0) && (diroffset
> uio
->uio_offset
)) {
1270 /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */
1274 /* OK, so much for the fakes. Now for the "real thing": */
1275 TAILQ_FOREACH(entry
, &sp
->s_u
.d
.d_subnodes
, s_sibling
) {
1276 if (diroffset
== uio
->uio_offset
) {
1277 /* Return this entry */
1278 diroffset
+= synthfs_adddirentry(entry
->s_nodeid
, VTTOIF(STOV(entry
)->v_type
), entry
->s_name
, uio
);
1280 if ((uio
->uio_resid
> 0) && (diroffset
> uio
->uio_offset
)) {
1281 /* Oops - we skipped over a partial entry: at best, diroffset should've just matched uio->uio_offset */
1287 *ap
->a_eofflag
= (entry
== NULL
); /* If we ran all the way through the list, there is no more */
1302 synthfs_cached_lookup(ap
)
1303 struct vop_cachedlookup_args
/* {
1304 struct vnode *a_dvp;
1305 struct vnode **a_vpp;
1306 struct componentname *a_cnp;
1309 struct vnode
*dp
= ap
->a_dvp
;
1310 struct componentname
*cnp
= ap
->a_cnp
;
1311 u_long nameiop
= cnp
->cn_nameiop
;
1312 u_long flags
= cnp
->cn_flags
;
1313 boolean_t lockparent
= (flags
& LOCKPARENT
);
1314 struct proc
*p
= cnp
->cn_proc
;
1315 struct ucred
*cred
= cnp
->cn_cred
;
1316 struct vnode
*target_vp
= NULL
;
1317 u_int32_t target_vnode_id
; /* Capability ID of the target vnode for .. unlock/relock handling check */
1318 struct vnode
**vpp
= ap
->a_vpp
;
1321 DBG_VOP(("synthfs_cached_lookup called, name = %s, namelen = %ld\n", ap
->a_cnp
->cn_nameptr
, ap
->a_cnp
->cn_namelen
));
1322 if (flags
& LOCKPARENT
) DBG_VOP(("\tLOCKPARENT is set\n"));
1323 if (flags
& ISLASTCN
) DBG_VOP(("\tISLASTCN is set\n"));
1327 if (dp
->v_type
!= VDIR
) {
1332 if ((flags
& ISLASTCN
) &&
1333 (VTOVFS(dp
)->mnt_flag
& MNT_RDONLY
) &&
1334 ((nameiop
== DELETE
) || (nameiop
== RENAME
))) {
1339 result
= VOP_ACCESS(dp
, VEXEC
, cred
, cnp
->cn_proc
);
1340 if (result
!= 0) goto Err_Exit
;
1343 * Look up an entry in the namei cache
1346 result
= cache_lookup(dp
, vpp
, cnp
);
1348 /* There was no entry in the cache for this parent vnode/name pair:
1349 do the full-blown pathname lookup
1351 return synthfs_lookup(ap
);
1353 if (result
== ENOENT
) return result
;
1355 /* An entry matching the parent vnode/name was found in the cache: */
1359 target_vnode_id
= target_vp
->v_id
;
1360 if (target_vp
== dp
) {
1364 } else if (flags
& ISDOTDOT
) {
1366 * Carefully now: trying to step from child to parent;
1367 * must release lock on child before trying to lock parent
1370 VOP_UNLOCK(dp
, 0, p
);
1371 result
= vget(target_vp
, LK_EXCLUSIVE
, p
);
1372 if ((result
== 0) && lockparent
&& (flags
& ISLASTCN
)) {
1373 result
= vn_lock(dp
, LK_EXCLUSIVE
, p
);
1376 result
= vget(target_vp
, LK_EXCLUSIVE
, p
);
1377 if (!lockparent
|| (result
!= 0) || !(flags
& ISLASTCN
)) {
1378 VOP_UNLOCK(dp
, 0, p
);
1383 Check to make sure the target vnode ID didn't change while we
1387 if (target_vnode_id
== target_vp
->v_id
) {
1388 return 0; /* THIS IS THE NORMAL EXIT PATH */
1391 /* The vnode ID didn't match anymore: we've got another vnode! */
1393 /* Unlock the parent vnode in the cases where it should've been left locked: */
1394 if (lockparent
&& (dp
!= target_vp
) && (flags
& ISLASTCN
)) {
1395 VOP_UNLOCK(dp
, 0, p
);
1399 /* One last try for a successful lookup through the complete lookup path: */
1400 result
= vn_lock(dp
, LK_EXCLUSIVE
, p
);
1402 return synthfs_lookup(ap
);
1413 struct vop_cachedlookup_args
/* {
1414 struct vnode *a_dvp;
1415 struct vnode **a_vpp;
1416 struct componentname *a_cnp;
1419 struct vnode
*dp
= ap
->a_dvp
;
1420 struct synthfsnode
*dsp
= VTOS(dp
);
1421 struct componentname
*cnp
= ap
->a_cnp
;
1422 u_long nameiop
= cnp
->cn_nameiop
;
1423 // char *nameptr = cnp->cn_nameptr;
1424 u_long flags
= cnp
->cn_flags
;
1425 long namelen
= cnp
->cn_namelen
;
1426 struct proc
*p
= cnp
->cn_proc
;
1427 struct ucred
*cred
= cnp
->cn_cred
;
1428 struct synthfsnode
*entry
;
1429 struct vnode
*target_vp
= NULL
;
1431 boolean_t found
= FALSE
;
1432 boolean_t isDot
= FALSE
;
1433 boolean_t isDotDot
= FALSE
;
1434 struct vnode
*starting_parent
= dp
;
1436 DBG_VOP(("synthfs_lookup called, name = %s, namelen = %ld\n", ap
->a_cnp
->cn_nameptr
, ap
->a_cnp
->cn_namelen
));
1437 if (flags
& LOCKPARENT
) DBG_VOP(("\tLOCKPARENT is set\n"));
1438 if (flags
& ISLASTCN
) DBG_VOP(("\tISLASTCN is set\n"));
1442 if (dp
->v_type
!= VDIR
) {
1447 if ((flags
& ISLASTCN
) &&
1448 (VTOVFS(dp
)->mnt_flag
& MNT_RDONLY
) &&
1449 ((nameiop
== DELETE
) || (nameiop
== RENAME
))) {
1454 result
= VOP_ACCESS(dp
, VEXEC
, cred
, cnp
->cn_proc
);
1455 if (result
!= 0) goto Err_Exit
;
1457 /* first check for "." and ".." */
1458 if (cnp
->cn_nameptr
[0] == '.') {
1472 } else if ((namelen
== 2) && (cnp
->cn_nameptr
[1] == '.')) {
1479 if ((dsp
->s_parent
!= NULL
) && (dsp
->s_parent
!= VTOS(dp
))) {
1480 target_vp
= STOV(dsp
->s_parent
);
1482 * Special case for ".." to prevent deadlock:
1483 * always release the parent vnode BEFORE trying to acquire
1484 * ITS parent. This avoids deadlocking with another lookup
1485 * starting from the target_vp trying to vget() this directory.
1487 VOP_UNLOCK(dp
, 0, p
);
1488 result
= vget(target_vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1490 vn_lock(dp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1493 if ((flags
& LOCKPARENT
) && (flags
& ISLASTCN
)) {
1494 result
= vn_lock(dp
, LK_EXCLUSIVE
, p
);
1495 // vput(target_vp); /* XXX WHY WAS THIS HERE? */
1499 /* dp is alread locked and ref'ed */
1507 /* finally, just look for entries by name (making sure the entry's length
1508 matches the cnp's namelen... */
1509 TAILQ_FOREACH(entry
, &dsp
->s_u
.d
.d_subnodes
, s_sibling
) {
1510 if ((bcmp(cnp
->cn_nameptr
, entry
->s_name
, (unsigned)namelen
) == 0) &&
1511 (*(entry
->s_name
+ namelen
) == (char)0)) {
1513 target_vp
= STOV(entry
);
1514 result
= vget(target_vp
, LK_EXCLUSIVE
| LK_RETRY
, p
); /* vget is not really needed because refcount is always > 0... */
1520 /* The specified entry was found and successfully acquired: */
1529 if ((nameiop
== DELETE
) && (flags
& ISLASTCN
)) {
1531 * Deleting entries requires write access:
1533 result
= VOP_ACCESS(dp
, VWRITE
, cred
, p
);
1534 if (result
!= 0) goto Err_Exit
;
1537 * If the parent directory is "sticky" then the user must own
1538 * the directory, or the file in it, in order to be allowed to
1539 * delete it (unless the user is root). This implements
1540 * append-only directories
1542 if ((dsp
->s_mode
& S_ISVTX
) &&
1543 (cred
->cr_uid
!= 0) &&
1544 (cred
->cr_uid
!= dsp
->s_uid
) &&
1545 (target_vp
!= NULL
) &&
1546 (target_vp
->v_type
!= VLNK
) &&
1547 (VTOS(target_vp
)->s_uid
!= cred
->cr_uid
)) {
1554 if ((nameiop
== RENAME
) && (flags
& WANTPARENT
) && (flags
* ISLASTCN
)) {
1555 result
= VOP_ACCESS(dp
, VWRITE
, cred
, p
);
1556 if (result
!= 0) goto Err_Exit
;
1565 /* The specified entry wasn't found: */
1568 if ((flags
& ISLASTCN
) &&
1569 ((nameiop
== CREATE
) ||
1570 (nameiop
== RENAME
) ||
1571 ((nameiop
== DELETE
) && (flags
& DOWHITEOUT
) && (flags
& ISWHITEOUT
)))) {
1572 /* Write access is required to create entries in the directory: */
1573 result
= VOP_ACCESS(dp
, VWRITE
, cred
, p
);
1574 if (result
!= 0) goto Err_Exit
;
1576 cnp
->cn_flags
|= SAVENAME
;
1578 result
= EJUSTRETURN
;
1582 /* XXX PPD Should we do something special in case LOCKLEAF isn't set? */
1583 if (found
&& !isDot
&& !isDotDot
&& (!(flags
& LOCKPARENT
) || !(flags
& ISLASTCN
))) {
1584 VOP_UNLOCK(dp
, 0, p
);
1587 *ap
->a_vpp
= target_vp
;
1590 DBG_VOP(("synthfs_lookup: result = %d.\n", result
));
1593 if (VOP_ISLOCKED(target_vp
)) {
1594 DBG_VOP(("synthfs_lookup: target_vp = 0x%08X (locked).\n", (u_long
)target_vp
));
1596 DBG_VOP(("synthfs_lookup: target_vp = 0x%08X (NOT locked?).\n", (u_long
)target_vp
));
1599 DBG_VOP(("synthfs_lookup: found = true but target_vp = NULL?\n"));
1602 DBG_VOP(("synthf_lookup: target not found.\n"));
1604 if (VOP_ISLOCKED(starting_parent
)) {
1605 DBG_VOP(("synthfs_lookup: dp = %08X; starting_parent = 0x%08X (LOCKED).\n", (u_long
)dp
, (u_long
)starting_parent
));
1607 DBG_VOP(("synthfs_lookup: dp = %08X; starting_parent = 0x%08X (UNLOCKED).\n", (u_long
)dp
, (u_long
)starting_parent
));
1617 #% pathconf vp L L L
1620 IN struct vnode *vp;
1622 OUT register_t *retval;
1625 synthfs_pathconf(ap
)
1626 struct vop_pathconf_args
/* {
1632 DBG_VOP(("synthfs_pathconf called\n"));
1637 *ap
->a_retval
= LINK_MAX
;
1640 *ap
->a_retval
= NAME_MAX
;
1643 *ap
->a_retval
= PATH_MAX
;
1646 *ap
->a_retval
= PIPE_BUF
;
1648 case _PC_CHOWN_RESTRICTED
:
1662 * Update the access, modified, and node change times as specified by the
1663 * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is
1664 * used to specify that the node needs to be updated but that the times have
1665 * already been set. The access and modified times are taken from the second
1666 * and third parameters; the node change time is always taken from the current
1667 * time. If waitfor is set, then wait for the disk write of the node to
1672 IN struct vnode *vp;
1673 IN struct timeval *access;
1674 IN struct timeval *modify;
1680 struct vop_update_args
/* {
1682 struct timeval *a_access;
1683 struct timeval *a_modify;
1687 struct vnode
*vp
= ap
->a_vp
;
1688 struct synthfsnode
*sp
= VTOS(vp
);
1690 DBG_ASSERT(sp
!= NULL
);
1691 DBG_ASSERT(*((int*)&vp
->v_interlock
) == 0);
1693 if (((sp
->s_nodeflags
& (IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
)) != 0) &&
1694 !(VTOVFS(ap
->a_vp
)->mnt_flag
& MNT_RDONLY
)) {
1695 if (sp
->s_nodeflags
& IN_ACCESS
) sp
->s_accesstime
= *ap
->a_access
;
1696 if (sp
->s_nodeflags
& IN_UPDATE
) sp
->s_modificationtime
= *ap
->a_modify
;
1697 if (sp
->s_nodeflags
& IN_CHANGE
) sp
->s_changetime
= time
;
1700 /* After the updates are finished, clear the flags */
1701 sp
->s_nodeflags
&= ~(IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
);
1703 // DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0);
1709 /*******************************************************************************************
1711 Utility/housekeeping vnode operations:
1713 ******************************************************************************************/
1720 IN struct vnode *vp;
1727 struct vop_lock_args
/* {
1733 return lockmgr(&VTOS(ap
->a_vp
)->s_lock
, ap
->a_flags
, &ap
->a_vp
->v_interlock
, ap
->a_p
);
1737 * Unlock an synthfsnode.
1741 IN struct vnode *vp;
1748 struct vop_unlock_args
/* {
1754 return lockmgr(&VTOS(ap
->a_vp
)->s_lock
, ap
->a_flags
| LK_RELEASE
, &ap
->a_vp
->v_interlock
, ap
->a_p
);
1758 * Check for a locked synthfsnode.
1759 #% islocked vp = = =
1762 IN struct vnode *vp;
1766 synthfs_islocked(ap
)
1767 struct vop_islocked_args
/* {
1771 return lockstatus(&VTOS(ap
->a_vp
)->s_lock
);
1778 #% inactive vp L U U
1781 IN struct vnode *vp;
1787 synthfs_inactive(ap
)
1788 struct vop_inactive_args
/* {
1793 struct vnode
*vp
= ap
->a_vp
;
1794 struct proc
*p
= ap
->a_p
;
1795 struct synthfsnode
*sp
= VTOS(vp
);
1798 if (vp
->v_usecount
!= 0)
1799 DBG_VOP(("synthfs_inactive: bad usecount = %d\n", vp
->v_usecount
));
1802 * Ignore nodes related to stale file handles.
1804 if (vp
->v_type
== VNON
)
1807 /* This is sort of silly but might make sense in the future: */
1808 if (sp
->s_nodeflags
& (IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
)) {
1810 VOP_UPDATE(vp
, &tv
, &tv
, 0);
1814 VOP_UNLOCK(vp
, 0, p
);
1816 * If we are done with the inode, reclaim it
1817 * so that it can be reused immediately.
1819 if (vp
->v_type
== VNON
) {
1820 vrecycle(vp
, (struct slock
*)0, p
);
1829 * synthfs_reclaim - Reclaim a vnode so that it can be used for other purposes.
1831 * Locking policy: ignored
1835 struct vop_reclaim_args
/* { struct vnode *a_vp; struct proc *a_p; } */ *ap
;
1837 struct vnode
*vp
= ap
->a_vp
;
1838 struct synthfsnode
*sp
= VTOS(vp
);
1839 void *name
= sp
->s_name
;
1845 FREE((void *)sp
, M_SYNTHFS
);