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 * 2/10/2000 Clark Warner Added copyfile
31 * 5/24/1999 Don Brady Fixed security hole in get_fsvnode.
32 * 11/18/1998 Don Brady Special case 2 to mean the root of a file system.
33 * 9/28/1998 Umesh Vaishampayan Use the default vnode ops. Cleanup
35 * 11/12/1998 Scott Roberts validfsnode only checks to see if the volfs mount flag is set
36 * 8/5/1998 Don Brady fix validfsnode logic to handle a "bad" VFS_GET
37 * 7/5/1998 Don Brady In volfs_reclaim set vp->v_data to NULL after private data is free (VFS expects a NULL).
38 * 4/5/1998 Don Brady Changed lockstatus calls to VOP_ISLOCKED (radar #2231108);
39 * 3/25/1998 Pat Dirks Added include for sys/attr.h, which is no longer included indirectly.
42 #include <mach/mach_types.h>
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/resourcevar.h>
47 #include <sys/kernel.h>
49 #include <sys/filedesc.h>
54 #include <sys/mount.h>
55 #include <sys/vnode.h>
56 #include <sys/malloc.h>
57 #include <sys/dirent.h>
58 #include <sys/namei.h>
60 #include <sys/kdebug.h>
61 #include <sys/queue.h>
64 #include <sys/errno.h>
65 #include <vfs/vfs_support.h>
70 * volfs acts as a bridge between the requirements of the MacOS API and the Unix API.
71 * MacOS applications describe files by a <Volume ID><Directory ID><File Name> triple.
72 * The Unix API describes files by pathname. Volfs is a virtual file system that sits over
73 * the HFS VFS interface and allows files to be described by a <Volume ID>/<Directory ID>/<File Name>
76 * The root of the volfs filesystem consists of directories named the volume ID's of all the
77 * currently mounted filesystems which support the VFS vget() routine. Each of those directories
78 * supports the lookup by file ID of all files and directories within the filesystem. When a
79 * file or directory is resolved its vnode from that filesystem rather than a volfs vnode is returned
80 * allowing immediate access to the target file or directory.
82 * Readdir on the root of the volfs filesystem returns the list of available file systems. Readdir
83 * on a filesystem node, however, returns only . and .. since it is not practical to list all
84 * of the file ID's in a timely fashion and furthermore VFS does not provide a mechanism for
85 * enumerating all of the file id's.
87 * Volume ID's are taken from the low 32 bits of the f_fsid field, formatted as a base 10 ASCII
88 * string with no leading zeros (volume ID 1 is represented as "1").
90 * File ID's are created in same manner, with their 32 bits formatted as a base 10 ASCII
91 * string with no leading zeros.
93 * Volfs does create a security hole since it is possible to bypass directory permissions higher
94 * in the namespace tree. This security hole is about the same as the one created by NFS which uses
95 * a similar mechanism.
98 #define VOPFUNC int (*)(void *)
100 /* Global vfs data structures for volfs. */
101 int (**volfs_vnodeop_p
) (void *);
102 struct vnodeopv_entry_desc volfs_vnodeop_entries
[] = {
103 {&vop_default_desc
, (VOPFUNC
)vn_default_error
},
104 {&vop_strategy_desc
, (VOPFUNC
)err_strategy
}, /* strategy */
105 {&vop_bwrite_desc
, (VOPFUNC
)err_bwrite
}, /* bwrite */
106 {&vop_lookup_desc
, (VOPFUNC
)volfs_lookup
}, /* lookup */
107 {&vop_create_desc
, (VOPFUNC
)err_create
}, /* create */
108 {&vop_whiteout_desc
, (VOPFUNC
)err_whiteout
}, /* whiteout */
109 {&vop_mknod_desc
, (VOPFUNC
)err_mknod
}, /* mknod */
110 {&vop_mkcomplex_desc
, (VOPFUNC
)err_mkcomplex
}, /* mkcomplex */
111 {&vop_open_desc
, (VOPFUNC
)nop_open
}, /* open */
112 {&vop_close_desc
, (VOPFUNC
)nop_close
}, /* close */
113 {&vop_access_desc
, (VOPFUNC
)volfs_access
}, /* access */
114 {&vop_getattr_desc
, (VOPFUNC
)volfs_getattr
}, /* getattr */
115 {&vop_setattr_desc
, (VOPFUNC
)err_setattr
}, /* setattr */
116 {&vop_getattrlist_desc
, (VOPFUNC
)err_getattrlist
}, /* getattrlist */
117 {&vop_setattrlist_desc
, (VOPFUNC
)err_setattrlist
}, /* setattrlist */
118 {&vop_read_desc
, (VOPFUNC
)err_read
}, /* read */
119 {&vop_write_desc
, (VOPFUNC
)err_write
}, /* write */
120 {&vop_lease_desc
, (VOPFUNC
)err_lease
}, /* lease */
121 {&vop_ioctl_desc
, (VOPFUNC
)err_ioctl
}, /* ioctl */
122 {&vop_select_desc
, (VOPFUNC
)volfs_select
}, /* select */
123 {&vop_exchange_desc
, (VOPFUNC
)err_exchange
}, /* exchange */
124 {&vop_revoke_desc
, (VOPFUNC
)nop_revoke
}, /* revoke */
125 {&vop_mmap_desc
, (VOPFUNC
)err_mmap
}, /* mmap */
126 {&vop_fsync_desc
, (VOPFUNC
)err_fsync
}, /* fsync */
127 {&vop_seek_desc
, (VOPFUNC
)nop_seek
}, /* seek */
128 {&vop_remove_desc
, (VOPFUNC
)err_remove
}, /* remove */
129 {&vop_link_desc
, (VOPFUNC
)err_link
}, /* link */
130 {&vop_rename_desc
, (VOPFUNC
)err_rename
}, /* rename */
131 {&vop_mkdir_desc
, (VOPFUNC
)err_mkdir
}, /* mkdir */
132 {&vop_rmdir_desc
, (VOPFUNC
)volfs_rmdir
}, /* rmdir */
133 {&vop_symlink_desc
, (VOPFUNC
)err_symlink
}, /* symlink */
134 {&vop_readdir_desc
, (VOPFUNC
)volfs_readdir
}, /* readdir */
135 {&vop_readdirattr_desc
, (VOPFUNC
)err_readdirattr
}, /* readdirattr */
136 {&vop_readlink_desc
, (VOPFUNC
)err_readlink
}, /* readlink */
137 {&vop_abortop_desc
, (VOPFUNC
)err_abortop
}, /* abortop */
138 {&vop_inactive_desc
, (VOPFUNC
)err_inactive
}, /* inactive */
139 {&vop_reclaim_desc
, (VOPFUNC
)volfs_reclaim
}, /* reclaim */
140 {&vop_lock_desc
, (VOPFUNC
)volfs_lock
}, /* lock */
141 {&vop_unlock_desc
, (VOPFUNC
)volfs_unlock
}, /* unlock */
142 {&vop_bmap_desc
, (VOPFUNC
)err_bmap
}, /* bmap */
143 {&vop_print_desc
, (VOPFUNC
)err_print
}, /* print */
144 {&vop_islocked_desc
, (VOPFUNC
)volfs_islocked
}, /* islocked */
145 {&vop_pathconf_desc
, (VOPFUNC
)volfs_pathconf
}, /* pathconf */
146 {&vop_advlock_desc
, (VOPFUNC
)err_advlock
}, /* advlock */
147 {&vop_blkatoff_desc
, (VOPFUNC
)err_blkatoff
}, /* blkatoff */
148 {&vop_valloc_desc
, (VOPFUNC
)err_valloc
}, /* valloc */
149 {&vop_reallocblks_desc
, (VOPFUNC
)err_reallocblks
}, /* reallocblks */
150 {&vop_vfree_desc
, (VOPFUNC
)err_vfree
}, /* vfree */
151 {&vop_truncate_desc
, (VOPFUNC
)err_truncate
}, /* truncate */
152 {&vop_allocate_desc
, (VOPFUNC
)err_allocate
}, /* allocate */
153 {&vop_update_desc
, (VOPFUNC
)err_update
}, /* update */
154 {&vop_pgrd_desc
, (VOPFUNC
)err_pgrd
}, /* pgrd */
155 {&vop_pgwr_desc
, (VOPFUNC
)err_pgwr
}, /* pgwr */
156 {&vop_pagein_desc
, (VOPFUNC
)err_pagein
}, /* pagein */
157 {&vop_pageout_desc
, (VOPFUNC
)err_pageout
}, /* pageout */
158 {&vop_devblocksize_desc
, (VOPFUNC
)err_devblocksize
}, /* devblocksize */
159 {&vop_searchfs_desc
, (VOPFUNC
)err_searchfs
}, /* searchfs */
160 {&vop_copyfile_desc
, (VOPFUNC
)err_copyfile
}, /* Copyfile */
161 {&vop_blktooff_desc
, (VOPFUNC
)err_blktooff
}, /* blktooff */
162 {&vop_offtoblk_desc
, (VOPFUNC
)err_offtoblk
}, /* offtoblk */
163 {&vop_cmap_desc
, (VOPFUNC
)err_cmap
}, /* cmap */
164 {(struct vnodeop_desc
*) NULL
, (int (*) ()) NULL
}
168 * Oh what a tangled web we weave. This structure will be used by
169 * bsd/vfs/vfs_conf.c to actually do the initialization of volfs_vnodeop_p
171 struct vnodeopv_desc volfs_vnodeop_opv_desc
=
172 {&volfs_vnodeop_p
, volfs_vnodeop_entries
};
174 static char gDot
[] = ".";
175 static char gDotDot
[] = "..";
181 struct finfoattrbuf
{
182 unsigned long length
;
186 static int validfsnode(struct mount
*fsnode
);
188 struct volfs_PLCEntry
190 LIST_ENTRY(volfs_PLCEntry
) vplc_hash_link
; /* entry's hash chain */
191 TAILQ_ENTRY(volfs_PLCEntry
) vplc_lru_link
; /* entry's LRU chain link */
198 #define VOLFSPLCHASH(fsid, inum) ((((unsigned long)fsid) + (unsigned long)(inum)) & volfs_PLCHashMask)
200 static struct slock volfs_PLChashtable_slock
;
201 static TAILQ_HEAD(volfs_PLCLRUListHead
, volfs_PLCEntry
) volfs_PLCLRUList
;
202 static TAILQ_HEAD(volfs_PLCFreeListHead
, volfs_PLCEntry
) volfs_PLCFreeList
;
203 static LIST_HEAD(, volfs_PLCEntry
) *volfs_PLCHashTable
;
204 static u_long volfs_PLCHashMask
; /* size of hash table - 1 */
205 static u_long volfs_PLCEntryCount
;
207 #if DBG_VOP_TEST_LOCKS
208 static void DbgVopTest (int max
, int error
, VopDbgStoreRec
*VopDbgStore
, char *funcname
);
209 #endif /* DBG_VOP_TEST_LOCKS */
215 __private_extern__
void
216 volfs_PLChashinit(void)
220 TAILQ_INIT(&volfs_PLCLRUList
);
221 TAILQ_INIT(&volfs_PLCFreeList
);
222 simple_lock_init(&volfs_PLChashtable_slock
);
224 volfs_PLCHashTable
= hashinit(PLCHASHSIZE
, M_TEMP
, &volfs_PLCHashMask
);
226 for (i
= 0; i
< PLCHASHSIZE
; ++i
) {
227 LIST_INIT(&volfs_PLCHashTable
[i
]);
230 volfs_PLCEntryCount
= 0;
235 __private_extern__
void
236 volfs_PLC_reclaim_entries(int entrycount
)
240 struct volfs_PLCEntry
*reclaim_target
;
242 simple_lock(&volfs_PLChashtable_slock
);
244 for (i
= entrycount
; i
> 0; --i
) {
245 if (TAILQ_EMPTY(&volfs_PLCLRUList
)) break;
247 /* Pick the next entry to be recycled and free it: */
248 reclaim_target
= TAILQ_FIRST(&volfs_PLCLRUList
);
249 TAILQ_REMOVE(&volfs_PLCLRUList
, reclaim_target
, vplc_lru_link
);
250 LIST_REMOVE(reclaim_target
, vplc_hash_link
);
251 TAILQ_INSERT_TAIL(&volfs_PLCFreeList
, reclaim_target
, vplc_lru_link
);
254 simple_unlock(&volfs_PLChashtable_slock
);
264 * Look up a PLC entry in the hash
267 volfs_PLCLookup(int32_t fsid
, u_int target_id
, uid_t uid
, pid_t pid
)
269 struct volfs_PLCEntry
*hash_entry
;
272 simple_lock(&volfs_PLChashtable_slock
);
273 LIST_FOREACH(hash_entry
, &volfs_PLCHashTable
[VOLFSPLCHASH(fsid
, target_id
)], vplc_hash_link
) {
274 if ((hash_entry
->vplc_item_id
== target_id
) &&
275 (hash_entry
->vplc_pid
== pid
) &&
276 (hash_entry
->vplc_uid
== uid
) &&
277 (hash_entry
->vplc_fsid
== fsid
)) {
280 if (hash_entry
!= TAILQ_LAST(&volfs_PLCLRUList
, volfs_PLCLRUListHead
)) {
281 TAILQ_REMOVE(&volfs_PLCLRUList
, hash_entry
, vplc_lru_link
);
282 TAILQ_INSERT_TAIL(&volfs_PLCLRUList
, hash_entry
, vplc_lru_link
);
288 simple_unlock(&volfs_PLChashtable_slock
);
294 volfs_PLCEnter(int32_t fsid
, u_int target_id
, uid_t uid
, pid_t pid
)
296 struct volfs_PLCEntry
*new_entry
;
298 simple_lock(&volfs_PLChashtable_slock
);
299 if (!TAILQ_EMPTY(&volfs_PLCFreeList
)) {
300 new_entry
= TAILQ_FIRST(&volfs_PLCFreeList
);
301 TAILQ_REMOVE(&volfs_PLCFreeList
, new_entry
, vplc_lru_link
);
304 * Allocate up to the predetermined maximum number of new entries:
305 * [must be done now to avoid blocking in MALLOC() with volfs_PLChashtable_slock held locked]
307 if (volfs_PLCEntryCount
< MAXPLCENTRIES
) {
308 simple_unlock(&volfs_PLChashtable_slock
);
309 new_entry
= MALLOC(new_entry
, struct volfs_PLCEntry
*, sizeof(struct volfs_PLCEntry
), M_TEMP
, M_WAITOK
);
310 simple_lock(&volfs_PLChashtable_slock
);
311 ++volfs_PLCEntryCount
;
313 new_entry
= TAILQ_FIRST(&volfs_PLCLRUList
);
314 TAILQ_REMOVE(&volfs_PLCLRUList
, new_entry
, vplc_lru_link
);
315 LIST_REMOVE(new_entry
, vplc_hash_link
);
319 new_entry
->vplc_fsid
= fsid
;
320 new_entry
->vplc_item_id
= target_id
;
321 new_entry
->vplc_uid
= uid
;
322 new_entry
->vplc_pid
= pid
;
324 /* Link the new entry on the hash list for the fsid/target_id as well as the tail of the LRU list: */
325 LIST_INSERT_HEAD(&volfs_PLCHashTable
[VOLFSPLCHASH(fsid
, target_id
)], new_entry
, vplc_hash_link
);
326 TAILQ_INSERT_TAIL(&volfs_PLCLRUList
, new_entry
, vplc_lru_link
);
327 simple_unlock(&volfs_PLChashtable_slock
);
333 * volfs_reclaim - Reclaim a vnode so that it can be used for other purposes.
335 * Locking policy: ignored
339 struct vop_reclaim_args
/* { struct vnode *a_vp; struct proc *a_p; } */ *ap
;
341 struct vnode
*vp
= ap
->a_vp
;
342 void *data
= vp
->v_data
;
344 DBG_FUNC_NAME("volfs_reclaim");
345 DBG_VOP_LOCKS_DECL(1);
346 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
348 DBG_VOP_LOCKS_INIT(0, vp
, VOPDBG_UNLOCKED
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_ZERO
);
351 FREE(data
, M_VOLFSNODE
);
353 DBG_VOP_LOCKS_TEST(0);
358 * volfs_access - same access policy for all vnodes and all users (file/directory vnodes
359 * for the actual file systems are handled by actual file system)
361 * Locking policy: a_vp locked on input and output
365 struct vop_access_args
/* { struct vnode *a_vp; int a_mode; struct
366 ucred *a_cred; struct proc *a_p; } */ *ap
;
369 DBG_FUNC_NAME("volfs_access");
370 DBG_VOP_LOCKS_DECL(1);
371 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
373 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
376 * We don't need to check credentials! FS is read-only for everyone
378 if ((ap
->a_mode
& ~(VREAD
| VEXEC
)) == 0)
383 DBG_VOP_LOCKS_TEST(ret_err
);
388 * volfs_getattr - fill in the attributes for this vnode
390 * Locking policy: don't change anything
394 struct vop_getattr_args
/* { struct vnode *a_vp; struct vattr *a_vap;
395 struct ucred *a_cred; struct proc *a_p; } */ *ap
;
397 struct volfs_vndata
*priv_data
;
401 DBG_FUNC_NAME("volfs_getattr");
402 DBG_VOP_LOCKS_DECL(1);
403 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
405 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_SAME
, VOPDBG_SAME
, VOPDBG_SAME
, VOPDBG_POS
);
410 priv_data
= a_vp
->v_data
;
412 a_vap
->va_type
= VDIR
;
413 a_vap
->va_mode
= 0444; /* Yup, hard - coded to read - only */
415 a_vap
->va_uid
= 0; /* Always owned by root */
416 a_vap
->va_gid
= 0; /* Always part of group 0 */
417 a_vap
->va_fsid
= (int) a_vp
->v_mount
->mnt_stat
.f_fsid
.val
[0];
418 a_vap
->va_fileid
= priv_data
->nodeID
;
421 * If it's the root vnode calculate its size based on the number of eligible
424 if (priv_data
->vnode_type
== VOLFS_ROOT
)
426 register struct mount
*mp
, *nmp
;
428 simple_lock(&mountlist_slock
);
429 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
430 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, ap
->a_p
)) {
431 nmp
= mp
->mnt_list
.cqe_next
;
435 if (mp
!= a_vp
->v_mount
&& validfsnode(mp
))
438 simple_lock(&mountlist_slock
);
439 nmp
= mp
->mnt_list
.cqe_next
;
440 vfs_unbusy(mp
, ap
->a_p
);
442 simple_unlock(&mountlist_slock
);
444 DBG_VOP(("found %d file systems that volfs can support\n", numMounts
));
445 a_vap
->va_size
= (numMounts
+ 2) * VLFSDIRENTLEN
;
449 a_vap
->va_size
= 2 * VLFSDIRENTLEN
;
451 DBG_VOP(("va_size = %d, VLFSDIRENTLEN = %ld\n", (int) a_vap
->va_size
, VLFSDIRENTLEN
));
452 a_vap
->va_blocksize
= 512;
454 a_vap
->va_atime
.tv_sec
= boottime
.tv_sec
;
455 a_vap
->va_atime
.tv_nsec
= 0;
457 a_vap
->va_mtime
.tv_sec
= boottime
.tv_sec
;
458 a_vap
->va_mtime
.tv_nsec
= 0;
460 a_vap
->va_ctime
.tv_sec
= boottime
.tv_sec
;
461 a_vap
->va_ctime
.tv_nsec
= 0;
466 a_vap
->va_bytes
= a_vap
->va_size
;
467 a_vap
->va_filerev
= 0;
468 a_vap
->va_vaflags
= 0;
470 DBG_VOP_LOCKS_TEST(0);
475 * volfs_select - just say OK. Only possible op is readdir
477 * Locking policy: ignore
481 struct vop_select_args
/* { struct vnode *a_vp; int a_which; int
482 * a_fflags; struct ucred *a_cred; void * a_wql; struct
485 DBG_VOP(("volfs_select called\n"));
491 * vofls_rmdir - not possible to remove directories in volfs
493 * Locking policy: a_dvp & a_vp - locked on entry, unlocked on exit
497 struct vop_rmdir_args
/* { struct vnode *a_dvp; struct vnode *a_vp;
498 struct componentname *a_cnp; } */ *ap
;
500 DBG_VOP(("volfs_rmdir called\n"));
501 if (ap
->a_dvp
== ap
->a_vp
) {
502 (void) nop_rmdir(ap
);
505 return (err_rmdir(ap
));
509 * volfs_readdir - Get directory entries
511 * Directory listings are only produced for the root volfs node. Filesystems
513 * Filesystems contained within the volfs root are named by the decimal
514 * equivalent of the f_fsid.val[0] from their mount structure (typically
515 * the device id of the volume). The maximum length for a name, then is
518 * Locking policy: a_vp locked on entry and exit
522 struct vop_readdir_args
/* { struct vnode *a_vp; struct uio *a_uio;
523 * struct ucred *a_cred; int *a_eofflag; int
524 *ncookies; u_long **a_cookies; } */ *ap
;
526 struct volfs_vndata
*priv_data
;
527 register struct uio
*uio
= ap
->a_uio
;
531 struct dirent local_dir
;
535 DBG_FUNC_NAME("volfs_readdir");
536 DBG_VOP_LOCKS_DECL(1);
538 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
539 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
541 DBG_VOP(("\tuio_offset = %d, uio_resid = %d\n", (int) uio
->uio_offset
, uio
->uio_resid
));
542 /* We assume it's all one big buffer... */
543 if (uio
->uio_iovcnt
> 1)
544 DBG_VOP(("\tuio->uio_iovcnt = %d?\n", uio
->uio_iovcnt
));
546 off
= uio
->uio_offset
;
547 priv_data
= ap
->a_vp
->v_data
;
548 starting_resid
= uio
->uio_resid
;
549 count
= uio
->uio_resid
;
551 /* Make sure we don't return partial entries. */
552 count
-= (uio
->uio_offset
+ count
) & (VLFSDIRENTLEN
- 1);
555 DBG_VOP(("volfs_readdir: Not enough buffer to read in entries\n"));
556 DBG_VOP_LOCKS_TEST(EINVAL
);
560 * Make sure we're starting on a directory boundary
562 if (off
& (VLFSDIRENTLEN
- 1))
564 DBG_VOP_LOCKS_TEST(EINVAL
);
567 rec_offset
= off
/ VLFSDIRENTLEN
;
568 lost
= uio
->uio_resid
- count
;
569 uio
->uio_resid
= count
;
570 uio
->uio_iov
->iov_len
= count
;
572 local_dir
.d_reclen
= VLFSDIRENTLEN
;
574 * We must synthesize . and ..
576 DBG_VOP(("\tstarting ... uio_offset = %d, uio_resid = %d\n",
577 (int) uio
->uio_offset
, uio
->uio_resid
));
580 DBG_VOP(("\tAdding .\n"));
584 local_dir
.d_fileno
= priv_data
->nodeID
;
585 local_dir
.d_type
= DT_DIR
;
586 local_dir
.d_namlen
= 1;
587 local_dir
.d_name
[0] = '.';
588 for (i
= 1; i
< MAXVLFSNAMLEN
; i
++)
589 local_dir
.d_name
[i
] = 0;
590 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
591 DBG_VOP(("\t after adding ., uio_offset = %d, uio_resid = %d\n",
592 (int) uio
->uio_offset
, uio
->uio_resid
));
597 DBG_VOP(("\tAdding ..\n"));
600 * We only have two levels in the volfs hierarchy. Root's
601 * .. points to itself and the second level points to root,
602 * hence we've hardcoded d_fileno for .. here
604 local_dir
.d_fileno
= ROOT_DIRID
;
605 local_dir
.d_type
= DT_DIR
;
606 local_dir
.d_namlen
= 2;
607 local_dir
.d_name
[0] = '.';
608 local_dir
.d_name
[1] = '.';
609 for (i
= 2; i
< MAXVLFSNAMLEN
; i
++)
610 local_dir
.d_name
[i
] = 0;
611 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
613 DBG_VOP(("\t after adding .., uio_offset = %d, uio_resid = %d\n",
614 (int) uio
->uio_offset
, uio
->uio_resid
));
618 * OK, we've given them the . & .. entries. If this is a
619 * filesystem node then we've gone as far as we're going
622 if (priv_data
->vnode_type
== VOLFS_FSNODE
)
624 *ap
->a_eofflag
= 1; /* we got all the way to the end */
625 DBG_VOP_LOCKS_TEST(error
);
629 if (rec_offset
> 1) {
630 register struct mount
*mp
, *nmp
;
632 struct proc
*p
= uio
->uio_procp
;
634 validnodeindex
= 1; /* we always have "." and ".." */
636 simple_lock(&mountlist_slock
);
637 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
638 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
639 nmp
= mp
->mnt_list
.cqe_next
;
643 if (mp
!= ap
->a_vp
->v_mount
&& validfsnode(mp
))
646 if (rec_offset
== validnodeindex
)
648 local_dir
.d_fileno
= mp
->mnt_stat
.f_fsid
.val
[0];
649 local_dir
.d_type
= DT_DIR
;
650 local_dir
.d_reclen
= VLFSDIRENTLEN
;
651 DBG_VOP(("\tAdding dir entry %d for offset %d\n", mp
->mnt_stat
.f_fsid
.val
[0], rec_offset
));
652 local_dir
.d_namlen
= sprintf(&local_dir
.d_name
[0], "%d", mp
->mnt_stat
.f_fsid
.val
[0]);
653 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
654 DBG_VOP(("\t after adding entry '%s', uio_offset = %d, uio_resid = %d\n",
655 &local_dir
.d_name
[0], (int) uio
->uio_offset
, uio
->uio_resid
));
659 simple_lock(&mountlist_slock
);
660 nmp
= mp
->mnt_list
.cqe_next
;
663 simple_unlock(&mountlist_slock
);
665 if (mp
== (void *) &mountlist
)
666 *ap
->a_eofflag
= 1; /* we got all the way to the end */
669 uio
->uio_resid
+= lost
;
670 if (starting_resid
== uio
->uio_resid
)
673 DBG_VOP(("\tExiting, uio_offset = %d, uio_resid = %d, ap->a_eofflag = %d\n",
674 (int) uio
->uio_offset
, uio
->uio_resid
, *ap
->a_eofflag
));
676 DBG_VOP_LOCKS_TEST(error
);
682 * validfsnode - test to see if a file system supports VGET
684 * This can cause context switching, so caller should be lock safe
687 validfsnode(struct mount
*fsnode
)
691 * Just check to see if the the mount flag is set, if it is we assume the
692 * file system supports all of volfs symantecs
695 if ((! (fsnode
->mnt_kern_flag
& MNTK_UNMOUNT
)) && (fsnode
->mnt_flag
& MNT_DOVOLFS
))
702 * volfs_lock - Lock an inode.
703 * If its already locked, set the WANT bit and sleep.
705 * Locking policy: handled by lockmgr
709 struct vop_lock_args
/* { struct vnode *a_vp; int a_flags; struct
713 struct volfs_vndata
*priv_data
;
714 DBG_FUNC_NAME("volfs_lock");
715 DBG_VOP_LOCKS_DECL(1);
717 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 0)) | DBG_FUNC_START
,
718 (unsigned int)ap
->a_vp
, (unsigned int)ap
->a_flags
, (unsigned int)ap
->a_p
, 0, 0);
720 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
722 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_UNLOCKED
, VOPDBG_LOCKED
, VOPDBG_UNLOCKED
, VOPDBG_ZERO
);
724 priv_data
= (struct volfs_vndata
*) ap
->a_vp
->v_data
;
725 retval
= lockmgr(&priv_data
->lock
, ap
->a_flags
, &ap
->a_vp
->v_interlock
, ap
->a_p
);
726 DBG_VOP_LOCKS_TEST(retval
);
728 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 0)) | DBG_FUNC_END
,
729 (unsigned int)ap
->a_vp
, (unsigned int)ap
->a_flags
, (unsigned int)ap
->a_p
, retval
, 0);
735 * volfs_unlock - Unlock an inode.
737 * Locking policy: handled by lockmgr
741 struct vop_unlock_args
/* { struct vnode *a_vp; int a_flags; struct
745 struct volfs_vndata
*priv_data
;
746 DBG_FUNC_NAME("volfs_unlock");
747 DBG_VOP_LOCKS_DECL(1);
749 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 4)) | DBG_FUNC_START
,
750 (unsigned int)ap
->a_vp
, (unsigned int)ap
->a_flags
, (unsigned int)ap
->a_p
, 0, 0);
752 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
754 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_UNLOCKED
, VOPDBG_LOCKED
, VOPDBG_ZERO
);
756 priv_data
= (struct volfs_vndata
*) ap
->a_vp
->v_data
;
757 retval
= lockmgr(&priv_data
->lock
, ap
->a_flags
| LK_RELEASE
,
758 &ap
->a_vp
->v_interlock
, ap
->a_p
);
760 DBG_VOP_LOCKS_TEST(retval
);
762 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 4)) | DBG_FUNC_END
,
763 (unsigned int)ap
->a_vp
, (unsigned int)ap
->a_flags
, (unsigned int)ap
->a_p
, retval
, 0);
769 * volfs_islocked - Check for a locked inode.
771 * Locking policy: ignore
775 struct vop_islocked_args
/* { struct vnode *a_vp; } */ *ap
;
778 struct volfs_vndata
*priv_data
;
780 DBG_FUNC_NAME("volfs_islocked");
781 DBG_VOP_LOCKS_DECL(1);
782 //DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
784 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_ZERO
);
785 priv_data
= (struct volfs_vndata
*) ap
->a_vp
->v_data
;
786 retval
= lockstatus(&priv_data
->lock
);
788 DBG_VOP_LOCKS_TEST(retval
);
793 * volfs_pathconf - Return POSIX pathconf information applicable to ufs filesystems.
795 * Locking policy: a_vp locked on input and output
799 struct vop_pathconf_args
/* { struct vnode *a_vp; int a_name; int
802 DBG_VOP(("volfs_pathconf called\n"));
807 *ap
->a_retval
= LINK_MAX
;
810 *ap
->a_retval
= NAME_MAX
;
813 *ap
->a_retval
= PATH_MAX
;
816 *ap
->a_retval
= PIPE_BUF
;
818 case _PC_CHOWN_RESTRICTED
:
832 * Call VOP_GETATTRLIST on a given vnode
835 vp_getattrlist(struct vnode
*vp
, struct attrlist alist
, void *attrbufptr
, size_t bufsize
, unsigned long options
, struct proc
*p
) {
839 iov
.iov_base
= (char *)attrbufptr
;
840 iov
.iov_len
= bufsize
;
842 bufuio
.uio_iov
= &iov
;
843 bufuio
.uio_iovcnt
= 1;
844 bufuio
.uio_offset
= 0;
845 bufuio
.uio_resid
= iov
.iov_len
;
846 bufuio
.uio_segflg
= UIO_SYSSPACE
;
847 bufuio
.uio_rw
= UIO_READ
;
848 bufuio
.uio_procp
= p
;
850 return VOP_GETATTRLIST(vp
, &alist
, &bufuio
, p
->p_ucred
, p
);
854 * get_parentvp() - internal routine that tries to lookup the parent of vpp.
855 * On success, *vpp is the parent vp and is returned locked and the original child
856 * is left unlocked. On failure, the original child will be locked upon return.
859 get_parentvp(struct vnode
**vpp
, struct mount
*mp
, struct proc
*p
)
862 struct attrlist alist
;
863 struct finfoattrbuf finfobuf
;
864 struct vnode
*child_vp
= *vpp
;
866 alist
.bitmapcount
= 5;
868 alist
.commonattr
= ATTR_CMN_PAROBJID
;
873 result
= vp_getattrlist(child_vp
, alist
, &finfobuf
, sizeof(finfobuf
), 0, p
);
877 /* Release the child vnode before trying to acquire its parent
878 to avoid vnode deadlock problems with parsing code
879 coming top-down through the directory hierarchy: */
880 VOP_UNLOCK(child_vp
, 0, p
);
882 /* Shift attention to the parent directory vnode: */
883 result
= VFS_VGET(mp
, &finfobuf
.fi
.parID
.fid_objno
, vpp
);
885 /* Make sure child_vp is still locked on exit: */
886 vn_lock(child_vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
894 * Look up the parent directory of a given vnode.
897 lookup_parent(u_int id
, struct vnode
*child_vp
, struct vnode
**parent_vp
, struct proc
*p
)
900 struct componentname
*cnp
= &nd
.ni_cnd
;
901 struct filedesc
*fdp
= p
->p_fd
;
907 * Special case lookups for root's parent directory,
908 * recognized by its special id of "1":
912 nd
.ni_startdir
= child_vp
;
913 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_SYSSPACE
, (caddr_t
)&gDotDot
, p
);
915 struct vnode
*root_vp
;
917 error
= VFS_ROOT(child_vp
->v_mount
, &root_vp
);
918 if (error
) return error
;
919 VOP_UNLOCK(root_vp
, 0, p
); /* Hold on to the reference */
920 nd
.ni_startdir
= root_vp
;
921 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_SYSSPACE
, (caddr_t
)&gDot
, p
);
923 nd
.ni_cnd
.cn_cred
= nd
.ni_cnd
.cn_proc
->p_ucred
;
925 /* Since we can't hit any symlinks, use the source path string directly: */
926 cnp
->cn_pnbuf
= nd
.ni_dirp
;
927 nd
.ni_pathlen
= strlen(cnp
->cn_pnbuf
);
928 cnp
->cn_pnlen
= nd
.ni_pathlen
+ 1;
929 cnp
->cn_flags
|= (HASBUF
| SAVENAME
);
933 if ((nd
.ni_rootdir
= fdp
->fd_rdir
) == NULL
) nd
.ni_rootdir
= rootvnode
;
934 cnp
->cn_nameptr
= cnp
->cn_pnbuf
;
935 if (error
= lookup(&nd
)) {
936 cnp
->cn_pnbuf
= NULL
;
940 * Check for symbolic link
942 if (cnp
->cn_flags
& ISSYMLINK
) return ENOENT
;
943 if (nd
.ni_vp
== child_vp
) return ELOOP
;
945 *parent_vp
= nd
.ni_vp
;
952 * verify_fullpathaccess(ret_vnode);
956 verify_fullpathaccess(u_int id
, struct vnode
*targetvp
, struct proc
*p
) {
957 struct vnode
*vp
, *parent_vp
;
958 struct mount
*mp
= targetvp
->v_mount
;
959 struct attrlist alist
;
960 struct finfoattrbuf finfobuf
;
962 struct filedesc
*fdp
= p
->p_fd
; /* pointer to file descriptor state */
967 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 12)) | DBG_FUNC_START
,
968 (unsigned int)targetvp
, (unsigned int)mp
, (unsigned int)p
, 0, 0);
973 if (vp
->v_type
!= VDIR
) {
975 /* The target is a file: get the parent directory. */
976 result
= get_parentvp(&vp
, mp
, p
);
977 if (result
) goto err_exit
;
979 /* At this point, targetvp is unlocked (but still referenced), and
980 vp is the parent directory vnode, held locked */
985 if (volfs_PLCLookup(mp
->mnt_stat
.f_fsid
.val
[0], id
, p
->p_ucred
->cr_uid
, p
->p_pid
)) goto lookup_success
;
987 /* Keep going up until either the process's root or the process's working directory is hit,
988 either one of which are potential valid starting points for a full pathname: */
990 while (vp
!= NULL
&& (!((vp
->v_flag
& VROOT
) || /* Hit "/" */
991 (vp
== fdp
->fd_cdir
) || /* Hit process's working directory */
992 (vp
== fdp
->fd_rdir
)))) { /* Hit process chroot()-ed root */
994 /* At this point, vp is some directory node and it's always locked */
995 /* Unlock the starting directory for namei(), retaining a reference... */
996 VOP_UNLOCK(vp
, 0, p
);
998 if (result
= lookup_parent(target_id
, vp
, &parent_vp
, p
)) {
1000 * If the lookup fails with EACCES and the targetvp is a directory,
1001 * we should try again using get_parentvp(). Without this check,
1002 * directories that you can navigate to but not traverse will
1003 * disappear when clicked in the Finder.
1005 if (result
== EACCES
&& vp
== targetvp
&& vp
->v_type
== VDIR
&& (vp
->v_flag
& VROOT
) == 0) {
1006 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1008 if (get_parentvp(&parent_vp
, mp
, p
)) {
1009 /* on error, vp is still locked... unlock for lookup_err_exit path */
1010 VOP_UNLOCK(vp
, 0, p
);
1012 /* on success, vp is returned unlocked, parent_vp is returned locked */
1016 if (result
) goto lookup_err_exit
;
1019 if (vp
!= targetvp
) {
1020 vrele(vp
); /* Completely done with that vp now... */
1024 target_id
= 0; /* It's unknown at this point */
1026 if (((result
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
)) != 0) &&
1027 ((result
= VOP_ACCESS(vp
, VREAD
, p
->p_ucred
, p
)) != 0)) {
1028 VOP_UNLOCK(vp
, 0, p
);
1029 goto lookup_err_exit
;
1034 volfs_PLCEnter(mp
->mnt_stat
.f_fsid
.val
[0], id
, p
->p_ucred
->cr_uid
, p
->p_pid
);
1038 /* Success: the caller has complete access to the initial vnode: */
1041 if (vp
&& vp
!= targetvp
) VOP_UNLOCK(vp
, 0, p
);
1044 if (vp
&& vp
!= targetvp
) {
1046 vn_lock(targetvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1047 if (vp_id
!= targetvp
->v_id
|| targetvp
->v_type
== VBAD
) {
1048 result
= EAGAIN
; /* vnode was recycled */
1054 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 12)) | DBG_FUNC_END
,
1055 (unsigned int)targetvp
, (unsigned int)mp
, (unsigned int)p
, result
, 0);
1062 * get_fsvnode - internal routine to create a vnode for a file system. Called with mount pointer,
1063 * id of filesystem to lookup and pointer to vnode pointer to fill in
1066 get_fsvnode(our_mount
, id
, ret_vnode
)
1067 struct mount
*our_mount
;
1069 struct vnode
**ret_vnode
;
1071 register struct mount
*mp
;
1072 struct mount
*cur_mount
;
1073 struct vnode
*cur_vnode
;
1074 struct volfs_vndata
*cur_privdata
;
1077 //DBG_VOP(("volfs: get_fsvnode called\n"));
1080 * OK, first look up the matching mount on the list of mounted file systems
1083 simple_lock(&mountlist_slock
);
1084 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= mp
->mnt_list
.cqe_next
)
1086 if (validfsnode(mp
) && mp
->mnt_stat
.f_fsid
.val
[0] == id
)
1092 simple_unlock(&mountlist_slock
);
1094 if (cur_mount
== NULL
) {
1096 * No mounted file system by the specified ID currently exists in the system.
1098 * XXX We could deal with a vnode that is still hanging about for an FS that
1099 * does not exists or has been unmounted now, or count on the update below
1100 * to happen later...
1107 * Now search the list attached to the mount structure to
1108 * see if this vnode is already floating around
1111 cur_vnode
= our_mount
->mnt_vnodelist
.lh_first
;
1112 while (cur_vnode
!= NULL
)
1114 cur_privdata
= (struct volfs_vndata
*) cur_vnode
->v_data
;
1115 if (cur_privdata
->nodeID
== id
)
1117 if (cur_privdata
->fs_mount
!= cur_mount
) {
1118 DBG_VOP(("volfs get_fsvnode: Updating fs_mount for vnode 0x%08lX (id = %d) from 0x%08lX to 0x%08lX...\n",
1119 (unsigned long)cur_vnode
,
1120 cur_privdata
->nodeID
,
1121 (unsigned long)cur_privdata
->fs_mount
,
1122 (unsigned long)cur_mount
));
1123 cur_privdata
->fs_mount
= cur_mount
;
1127 cur_vnode
= cur_vnode
->v_mntvnodes
.le_next
;
1130 //DBG_VOP(("\tfinal cur_mount: 0x%x\n",cur_mount));
1132 /* If vget returns an error, cur_vnode will not be what we think it is, try again */
1133 if (vget(cur_vnode
, LK_EXCLUSIVE
, current_proc()) != 0) {
1134 goto search_vnodelist
;
1139 MALLOC(cur_privdata
, struct volfs_vndata
*,
1140 sizeof(struct volfs_vndata
), M_VOLFSNODE
, M_WAITOK
);
1141 retval
= getnewvnode(VT_VOLFS
, our_mount
, volfs_vnodeop_p
, &cur_vnode
);
1143 FREE(cur_privdata
, M_VOLFSNODE
);
1147 cur_privdata
->vnode_type
= VOLFS_FSNODE
;
1148 cur_privdata
->nodeID
= id
;
1150 cur_privdata
->fs_mount
= cur_mount
;
1151 lockinit(&cur_privdata
->lock
, PINOD
, "volfsnode", 0, 0);
1152 lockmgr(&cur_privdata
->lock
, LK_EXCLUSIVE
, (struct slock
*)0, current_proc());
1153 cur_vnode
->v_data
= cur_privdata
;
1154 cur_vnode
->v_type
= VDIR
;
1155 DBG_VOP(("get_fsvnode returned with new node of "));
1156 DBG_VOP_PRINT_VNODE_INFO(cur_vnode
);DBG_VOP(("\n"));
1159 *ret_vnode
= cur_vnode
;
1167 * get_filevnode - returns the vnode for the given id within a filesystem. The parent vnode
1168 * is a filesystem, id is the 32-bit id of the file/directory and ret_vnode is a pointer
1169 * to a vnode pointer
1172 get_filevnode(parent_fs
, id
, ret_vnode
, p
)
1173 struct mount
*parent_fs
;
1175 struct vnode
**ret_vnode
;
1182 * Special case 2 to mean the root of a file system
1185 retval
= VFS_ROOT(parent_fs
, ret_vnode
);
1187 retval
= VFS_VGET(parent_fs
, &id
, ret_vnode
);
1188 if (retval
) goto error
;
1190 retval
= verify_fullpathaccess(id
, *ret_vnode
, p
);
1192 /* An error was encountered verifying that the caller has,
1193 in fact, got access all the way from "/" or their working
1194 directory to the specified item...
1198 /* vnode was recycled during access verification. */
1199 if (retval
== EAGAIN
) {
1211 struct vop_lookup_args
/* { struct vnode *a_dvp; struct vnode
1212 **a_vpp; struct componentname *a_cnp; } */ *ap
;
1214 struct volfs_vndata
*priv_data
;
1217 struct mount
*parent_fs
;
1218 int unlocked_parent
= 0, isdot_or_dotdot
= 0;
1219 int ret_err
= ENOENT
;
1220 DBG_FUNC_NAME("volfs_lookup");
1221 DBG_VOP_LOCKS_DECL(2);
1224 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 8)) | DBG_FUNC_START
,
1225 (unsigned int)ap
->a_dvp
, (unsigned int)ap
->a_cnp
, (unsigned int)p
, 0, 0);
1228 DBG_VOP(("volfs_lookup called, name = %s, namelen = %ld\n", ap
->a_cnp
->cn_nameptr
, ap
->a_cnp
->cn_namelen
));
1230 DBG_VOP_LOCKS_INIT(0,ap
->a_dvp
, VOPDBG_LOCKED
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_POS
);
1231 DBG_VOP_LOCKS_INIT(1,*ap
->a_vpp
, VOPDBG_IGNORE
, VOPDBG_LOCKED
, VOPDBG_IGNORE
, VOPDBG_POS
);
1232 DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
1233 DBG_VOP(("\t"));DBG_VOP_PRINT_CPN_INFO(ap
->a_cnp
);DBG_VOP(("\n"));
1234 if (ap
->a_cnp
->cn_flags
& LOCKPARENT
)
1235 DBG_VOP(("\tLOCKPARENT is set\n"));
1236 if (ap
->a_cnp
->cn_flags
& ISLASTCN
)
1238 DBG_VOP(("\tISLASTCN is set\n"));
1239 if (ap
->a_cnp
->cn_nameiop
== DELETE
|| ap
->a_cnp
->cn_nameiop
== RENAME
) /* XXX PPD Shouldn't we check for CREATE, too? */
1245 priv_data
= ap
->a_dvp
->v_data
;
1246 cnp
= ap
->a_cnp
->cn_nameptr
;
1247 namelen
= ap
->a_cnp
->cn_namelen
;
1250 switch (priv_data
->vnode_type
) {
1252 DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_ROOT.\n", (unsigned long)ap
->a_dvp
));
1256 DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_FSNODE, nodeID = %d, fs_mount = 0x%08lX.\n",
1257 (unsigned long)ap
->a_dvp
,
1259 (unsigned long)priv_data
->fs_mount
));
1262 DBG_VOP(("\tparent directory (vnode 0x%08lX) has unknown vnode_type (%d), nodeID = %d.\n",
1263 (unsigned long)ap
->a_dvp
,
1264 priv_data
->vnode_type
,
1265 priv_data
->nodeID
));
1267 #endif /* VOLFS_DEBUG */
1269 /* first check for "." and ".." */
1275 isdot_or_dotdot
= 1;
1276 *ap
->a_vpp
= ap
->a_dvp
;
1278 DBG_VOP_LOCKS_TEST(0);
1281 else if (cnp
[1] == '.' && namelen
== 2)
1283 /* ".." requested */
1284 isdot_or_dotdot
= 1;
1285 ret_err
= volfs_root(ap
->a_dvp
->v_mount
, ap
->a_vpp
);
1289 /* then look for special file system root symbol ('@') */
1290 else if (cnp
[0] == '@')
1292 if ((namelen
== 1) && (priv_data
->vnode_type
!= VOLFS_ROOT
)) {
1293 parent_fs
= priv_data
->fs_mount
;
1294 if (!(ap
->a_cnp
->cn_flags
& LOCKPARENT
) || !(ap
->a_cnp
->cn_flags
& ISLASTCN
)) {
1295 VOP_UNLOCK(ap
->a_dvp
, 0, ap
->a_cnp
->cn_proc
);
1296 unlocked_parent
= 1;
1298 ret_err
= VFS_ROOT(parent_fs
, ap
->a_vpp
);
1300 DBG_VOP(("volfs_lookup: pathname = '@' but namelen = %ld and parent vnode_type = %d.\n", namelen
, priv_data
->vnode_type
));
1306 /* finally, just look for numeric ids... */
1307 else if (namelen
<= 10 && cnp
[0] > '0' && cnp
[0] <= '9') /* 10 digits max lead digit must be 1 - 9 */
1312 id
= strtoul(cnp
, &check_ptr
, 10);
1315 * strtol will leave us at the first non-numeric character.
1316 * we've checked to make sure the component name does
1317 * begin with a numeric so check_ptr must wind up on
1318 * the terminating null or there was other junk following the
1321 if ((check_ptr
- cnp
) == namelen
)
1323 if (priv_data
->vnode_type
== VOLFS_ROOT
)
1324 ret_err
= get_fsvnode(ap
->a_dvp
->v_mount
, id
, ap
->a_vpp
);
1326 parent_fs
= priv_data
->fs_mount
;
1327 if (!(ap
->a_cnp
->cn_flags
& LOCKPARENT
) || !(ap
->a_cnp
->cn_flags
& ISLASTCN
)) {
1328 VOP_UNLOCK(ap
->a_dvp
, 0, ap
->a_cnp
->cn_proc
);
1329 unlocked_parent
= 1;
1331 ret_err
= get_filevnode(parent_fs
, id
, ap
->a_vpp
, ap
->a_cnp
->cn_proc
);
1336 if (!isdot_or_dotdot
&& *ap
->a_vpp
&& VPARENT(*ap
->a_vpp
) == NULL
&& ap
->a_dvp
!= *ap
->a_vpp
) {
1337 if (VPARENT(ap
->a_dvp
) == *ap
->a_vpp
) {
1338 panic("volfs: ap->a_dvp 0x%x has parent == a_vpp 0x%x\n",
1339 ap
->a_dvp
, *ap
->a_vpp
);
1341 vget(ap
->a_dvp
, 0, ap
->a_cnp
->cn_proc
);
1342 VPARENT(*ap
->a_vpp
) = ap
->a_dvp
;
1345 if (!unlocked_parent
&& (!(ap
->a_cnp
->cn_flags
& LOCKPARENT
) || !(ap
->a_cnp
->cn_flags
& ISLASTCN
))) {
1346 VOP_UNLOCK(ap
->a_dvp
, 0, ap
->a_cnp
->cn_proc
);
1349 /* XXX PPD Should we do something special in case LOCKLEAF isn't set? */
1353 DBG_VOP_UPDATE_VP(1, *ap
->a_vpp
);
1354 DBG_VOP_LOCKS_TEST(ret_err
);
1357 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 8)) | DBG_FUNC_START
,
1358 (unsigned int)ap
->a_dvp
, (unsigned int)ap
->a_cnp
, (unsigned int)p
, ret_err
, 0);
1363 #if DBG_VOP_TEST_LOCKS
1366 static void DbgLookupTest( char *funcname
, struct componentname
*cnp
, struct vnode
*dvp
, struct vnode
*vp
)
1368 int flags
= cnp
->cn_flags
;
1369 int nameiop
= cnp
->cn_nameiop
;
1371 DBG_VOP (("%s: Action:", funcname
));
1387 PRINTIT ("!!!UNKNOWN!!!!");
1390 PRINTIT(" flags: 0x%x ",flags
);
1391 if (flags
& LOCKPARENT
)
1392 PRINTIT (" Lock Parent");
1393 if (flags
& ISLASTCN
)
1394 PRINTIT (" Last Action");
1399 PRINTIT ("%s: Parent vnode exited ", funcname
);
1400 if (VOP_ISLOCKED(dvp
))
1401 PRINTIT("LOCKED\n");
1403 PRINTIT("UNLOCKED\n");
1407 PRINTIT ("%s: Found and Parent are the same\n", funcname
);
1411 PRINTIT ("%s: Found vnode exited ", funcname
);
1412 if (VOP_ISLOCKED(vp
))
1413 PRINTIT("LOCKED\n");
1415 PRINTIT("UNLOCKED\n");
1418 PRINTIT ("%s: Found vnode exited NULL\n", funcname
);
1424 static void DbgVopTest( int maxSlots
,
1426 VopDbgStoreRec
*VopDbgStore
,
1431 for (index
= 0; index
< maxSlots
; index
++)
1433 if (VopDbgStore
[index
].id
!= index
) {
1434 PRINTIT("%s: DBG_VOP_LOCK: invalid id field (%d) in target entry (#%d).\n", funcname
, VopDbgStore
[index
].id
, index
);
1438 if ((VopDbgStore
[index
].vp
!= NULL
) &&
1439 ((VopDbgStore
[index
].vp
->v_data
==NULL
)))
1442 switch (VopDbgStore
[index
].inState
)
1446 /* Do Nothing !!! */
1449 case VOPDBG_UNLOCKED
:
1450 case VOPDBG_LOCKNOTNIL
:
1452 if (VopDbgStore
[index
].vp
== NULL
&& (VopDbgStore
[index
].inState
!= VOPDBG_LOCKNOTNIL
)) {
1453 PRINTIT ("%s: InState check: Null vnode ptr in entry #%d\n", funcname
, index
);
1454 } else if (VopDbgStore
[index
].vp
!= NULL
) {
1455 switch (VopDbgStore
[index
].inState
)
1458 case VOPDBG_LOCKNOTNIL
:
1459 if (VopDbgStore
[index
].inValue
== 0)
1461 PRINTIT ("%s: %d Entry: not LOCKED:", funcname
, index
); DBG_VOP(("\n"));
1464 case VOPDBG_UNLOCKED
:
1465 if (VopDbgStore
[index
].inValue
!= 0)
1467 PRINTIT ("%s: %d Entry: not UNLOCKED:", funcname
, index
); DBG_VOP(("\n"));
1475 PRINTIT ("%s: DBG_VOP_LOCK on entry: bad lock test value: %d\n", funcname
, VopDbgStore
[index
].errState
);
1481 switch (VopDbgStore
[index
].errState
)
1484 /* Do Nothing !!! */
1487 case VOPDBG_UNLOCKED
:
1490 if (VopDbgStore
[index
].vp
== NULL
) {
1491 PRINTIT ("%s: ErrState check: Null vnode ptr in entry #%d\n", funcname
, index
);
1493 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1494 switch (VopDbgStore
[index
].errState
)
1497 if (VopDbgStore
[index
].outValue
== 0)
1499 PRINTIT ("%s: %d Error: not LOCKED:", funcname
, index
); DBG_VOP(("\n"));
1502 case VOPDBG_UNLOCKED
:
1503 if (VopDbgStore
[index
].outValue
!= 0)
1505 PRINTIT ("%s: %d Error: not UNLOCKED:", funcname
, index
); DBG_VOP(("\n"));
1509 if (VopDbgStore
[index
].outValue
!= VopDbgStore
[index
].inValue
)
1510 PRINTIT ("%s: Error: In/Out locks are DIFFERENT: 0x%x, inis %d and out is %d\n", funcname
, (u_int
)VopDbgStore
[index
].vp
, VopDbgStore
[index
].inValue
, VopDbgStore
[index
].outValue
);
1516 case VOPDBG_LOCKNOTNIL
:
1517 if (VopDbgStore
[index
].vp
!= NULL
) {
1518 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1519 if (VopDbgStore
[index
].outValue
== 0)
1520 PRINTIT ("%s: Error: %d Not LOCKED: 0x%x\n", funcname
, index
, (u_int
)VopDbgStore
[index
].vp
);
1524 PRINTIT ("%s: Error: bad lock test value: %d\n", funcname
, VopDbgStore
[index
].errState
);
1529 switch (VopDbgStore
[index
].outState
)
1532 /* Do Nothing !!! */
1535 case VOPDBG_UNLOCKED
:
1537 if (VopDbgStore
[index
].vp
== NULL
) {
1538 PRINTIT ("%s: OutState: Null vnode ptr in entry #%d\n", funcname
, index
);
1540 if (VopDbgStore
[index
].vp
!= NULL
)
1542 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1543 switch (VopDbgStore
[index
].outState
)
1546 if (VopDbgStore
[index
].outValue
== 0)
1548 PRINTIT ("%s: %d Out: not LOCKED:", funcname
, index
); DBG_VOP(("\n"));
1551 case VOPDBG_UNLOCKED
:
1552 if (VopDbgStore
[index
].outValue
!= 0)
1554 PRINTIT ("%s: %d Out: not UNLOCKED:", funcname
, index
); DBG_VOP(("\n"));
1558 if (VopDbgStore
[index
].outValue
!= VopDbgStore
[index
].inValue
)
1559 PRINTIT ("%s: Out: In/Out locks are DIFFERENT: 0x%x, inis %d and out is %d\n", funcname
, (u_int
)VopDbgStore
[index
].vp
, VopDbgStore
[index
].inValue
, VopDbgStore
[index
].outValue
);
1564 case VOPDBG_LOCKNOTNIL
:
1565 if (VopDbgStore
[index
].vp
!= NULL
) {
1566 if (&((struct volfs_vndata
*)(VopDbgStore
[index
].vp
->v_data
))->lock
== NULL
)
1567 PRINTIT ("%s: DBG_VOP_LOCK on out: Null lock on vnode 0x%x\n", funcname
, (u_int
)VopDbgStore
[index
].vp
);
1569 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1570 if (VopDbgStore
[index
].outValue
== 0)
1572 PRINTIT ("%s: DBG_VOP_LOCK on out: Should be LOCKED:", funcname
); DBG_VOP(("\n"));
1578 PRINTIT ("%s: DBG_VOP_LOCK on out: bad lock test value: %d\n", funcname
, VopDbgStore
[index
].outState
);
1582 VopDbgStore
[index
].id
= -1; /* Invalidate the entry to allow panic-free re-use */
1586 #endif /* DBG_VOP_TEST_LOCKS */