2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1998-1999 Apple Computer, Inc. All Rights Reserved.
25 * Modification History:
27 * 2/10/2000 Clark Warner Added copyfile
28 * 5/24/1999 Don Brady Fixed security hole in get_fsvnode.
29 * 11/18/1998 Don Brady Special case 2 to mean the root of a file system.
30 * 9/28/1998 Umesh Vaishampayan Use the default vnode ops. Cleanup
32 * 11/12/1998 Scott Roberts validfsnode only checks to see if the volfs mount flag is set
33 * 8/5/1998 Don Brady fix validfsnode logic to handle a "bad" VFS_GET
34 * 7/5/1998 Don Brady In volfs_reclaim set vp->v_data to NULL after private data is free (VFS expects a NULL).
35 * 4/5/1998 Don Brady Changed lockstatus calls to VOP_ISLOCKED (radar #2231108);
36 * 3/25/1998 Pat Dirks Added include for sys/attr.h, which is no longer included indirectly.
39 #include <mach/mach_types.h>
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/resourcevar.h>
44 #include <sys/kernel.h>
46 #include <sys/filedesc.h>
51 #include <sys/mount.h>
52 #include <sys/vnode.h>
53 #include <sys/malloc.h>
54 #include <sys/dirent.h>
55 #include <sys/namei.h>
57 #include <sys/kdebug.h>
58 #include <sys/queue.h>
61 #include <sys/errno.h>
62 #include <vfs/vfs_support.h>
67 * volfs acts as a bridge between the requirements of the MacOS API and the Unix API.
68 * MacOS applications describe files by a <Volume ID><Directory ID><File Name> triple.
69 * The Unix API describes files by pathname. Volfs is a virtual file system that sits over
70 * the HFS VFS interface and allows files to be described by a <Volume ID>/<Directory ID>/<File Name>
73 * The root of the volfs filesystem consists of directories named the volume ID's of all the
74 * currently mounted filesystems which support the VFS vget() routine. Each of those directories
75 * supports the lookup by file ID of all files and directories within the filesystem. When a
76 * file or directory is resolved its vnode from that filesystem rather than a volfs vnode is returned
77 * allowing immediate access to the target file or directory.
79 * Readdir on the root of the volfs filesystem returns the list of available file systems. Readdir
80 * on a filesystem node, however, returns only . and .. since it is not practical to list all
81 * of the file ID's in a timely fashion and furthermore VFS does not provide a mechanism for
82 * enumerating all of the file id's.
84 * Volume ID's are taken from the low 32 bits of the f_fsid field, formatted as a base 10 ASCII
85 * string with no leading zeros (volume ID 1 is represented as "1").
87 * File ID's are created in same manner, with their 32 bits formatted as a base 10 ASCII
88 * string with no leading zeros.
90 * Volfs does create a security hole since it is possible to bypass directory permissions higher
91 * in the namespace tree. This security hole is about the same as the one created by NFS which uses
92 * a similar mechanism.
95 #define VOPFUNC int (*)(void *)
97 /* Global vfs data structures for volfs. */
98 int (**volfs_vnodeop_p
) (void *);
99 struct vnodeopv_entry_desc volfs_vnodeop_entries
[] = {
100 {&vop_default_desc
, (VOPFUNC
)vn_default_error
},
101 {&vop_strategy_desc
, (VOPFUNC
)err_strategy
}, /* strategy */
102 {&vop_bwrite_desc
, (VOPFUNC
)err_bwrite
}, /* bwrite */
103 {&vop_lookup_desc
, (VOPFUNC
)volfs_lookup
}, /* lookup */
104 {&vop_create_desc
, (VOPFUNC
)err_create
}, /* create */
105 {&vop_whiteout_desc
, (VOPFUNC
)err_whiteout
}, /* whiteout */
106 {&vop_mknod_desc
, (VOPFUNC
)err_mknod
}, /* mknod */
107 {&vop_mkcomplex_desc
, (VOPFUNC
)err_mkcomplex
}, /* mkcomplex */
108 {&vop_open_desc
, (VOPFUNC
)nop_open
}, /* open */
109 {&vop_close_desc
, (VOPFUNC
)nop_close
}, /* close */
110 {&vop_access_desc
, (VOPFUNC
)volfs_access
}, /* access */
111 {&vop_getattr_desc
, (VOPFUNC
)volfs_getattr
}, /* getattr */
112 {&vop_setattr_desc
, (VOPFUNC
)err_setattr
}, /* setattr */
113 {&vop_getattrlist_desc
, (VOPFUNC
)err_getattrlist
}, /* getattrlist */
114 {&vop_setattrlist_desc
, (VOPFUNC
)err_setattrlist
}, /* setattrlist */
115 {&vop_read_desc
, (VOPFUNC
)err_read
}, /* read */
116 {&vop_write_desc
, (VOPFUNC
)err_write
}, /* write */
117 {&vop_lease_desc
, (VOPFUNC
)err_lease
}, /* lease */
118 {&vop_ioctl_desc
, (VOPFUNC
)err_ioctl
}, /* ioctl */
119 {&vop_select_desc
, (VOPFUNC
)volfs_select
}, /* select */
120 {&vop_exchange_desc
, (VOPFUNC
)err_exchange
}, /* exchange */
121 {&vop_revoke_desc
, (VOPFUNC
)nop_revoke
}, /* revoke */
122 {&vop_mmap_desc
, (VOPFUNC
)err_mmap
}, /* mmap */
123 {&vop_fsync_desc
, (VOPFUNC
)err_fsync
}, /* fsync */
124 {&vop_seek_desc
, (VOPFUNC
)nop_seek
}, /* seek */
125 {&vop_remove_desc
, (VOPFUNC
)err_remove
}, /* remove */
126 {&vop_link_desc
, (VOPFUNC
)err_link
}, /* link */
127 {&vop_rename_desc
, (VOPFUNC
)err_rename
}, /* rename */
128 {&vop_mkdir_desc
, (VOPFUNC
)err_mkdir
}, /* mkdir */
129 {&vop_rmdir_desc
, (VOPFUNC
)volfs_rmdir
}, /* rmdir */
130 {&vop_symlink_desc
, (VOPFUNC
)err_symlink
}, /* symlink */
131 {&vop_readdir_desc
, (VOPFUNC
)volfs_readdir
}, /* readdir */
132 {&vop_readdirattr_desc
, (VOPFUNC
)err_readdirattr
}, /* readdirattr */
133 {&vop_readlink_desc
, (VOPFUNC
)err_readlink
}, /* readlink */
134 {&vop_abortop_desc
, (VOPFUNC
)err_abortop
}, /* abortop */
135 {&vop_inactive_desc
, (VOPFUNC
)err_inactive
}, /* inactive */
136 {&vop_reclaim_desc
, (VOPFUNC
)volfs_reclaim
}, /* reclaim */
137 {&vop_lock_desc
, (VOPFUNC
)volfs_lock
}, /* lock */
138 {&vop_unlock_desc
, (VOPFUNC
)volfs_unlock
}, /* unlock */
139 {&vop_bmap_desc
, (VOPFUNC
)err_bmap
}, /* bmap */
140 {&vop_print_desc
, (VOPFUNC
)err_print
}, /* print */
141 {&vop_islocked_desc
, (VOPFUNC
)volfs_islocked
}, /* islocked */
142 {&vop_pathconf_desc
, (VOPFUNC
)volfs_pathconf
}, /* pathconf */
143 {&vop_advlock_desc
, (VOPFUNC
)err_advlock
}, /* advlock */
144 {&vop_blkatoff_desc
, (VOPFUNC
)err_blkatoff
}, /* blkatoff */
145 {&vop_valloc_desc
, (VOPFUNC
)err_valloc
}, /* valloc */
146 {&vop_reallocblks_desc
, (VOPFUNC
)err_reallocblks
}, /* reallocblks */
147 {&vop_vfree_desc
, (VOPFUNC
)err_vfree
}, /* vfree */
148 {&vop_truncate_desc
, (VOPFUNC
)err_truncate
}, /* truncate */
149 {&vop_allocate_desc
, (VOPFUNC
)err_allocate
}, /* allocate */
150 {&vop_update_desc
, (VOPFUNC
)err_update
}, /* update */
151 {&vop_pgrd_desc
, (VOPFUNC
)err_pgrd
}, /* pgrd */
152 {&vop_pgwr_desc
, (VOPFUNC
)err_pgwr
}, /* pgwr */
153 {&vop_pagein_desc
, (VOPFUNC
)err_pagein
}, /* pagein */
154 {&vop_pageout_desc
, (VOPFUNC
)err_pageout
}, /* pageout */
155 {&vop_devblocksize_desc
, (VOPFUNC
)err_devblocksize
}, /* devblocksize */
156 {&vop_searchfs_desc
, (VOPFUNC
)err_searchfs
}, /* searchfs */
157 {&vop_copyfile_desc
, (VOPFUNC
)err_copyfile
}, /* Copyfile */
158 {&vop_blktooff_desc
, (VOPFUNC
)err_blktooff
}, /* blktooff */
159 {&vop_offtoblk_desc
, (VOPFUNC
)err_offtoblk
}, /* offtoblk */
160 {&vop_cmap_desc
, (VOPFUNC
)err_cmap
}, /* cmap */
161 {(struct vnodeop_desc
*) NULL
, (int (*) ()) NULL
}
165 * Oh what a tangled web we weave. This structure will be used by
166 * bsd/vfs/vfs_conf.c to actually do the initialization of volfs_vnodeop_p
168 struct vnodeopv_desc volfs_vnodeop_opv_desc
=
169 {&volfs_vnodeop_p
, volfs_vnodeop_entries
};
171 static char gDot
[] = ".";
172 static char gDotDot
[] = "..";
178 struct finfoattrbuf
{
179 unsigned long length
;
183 static int validfsnode(struct mount
*fsnode
);
185 struct volfs_PLCEntry
187 LIST_ENTRY(volfs_PLCEntry
) vplc_hash_link
; /* entry's hash chain */
188 TAILQ_ENTRY(volfs_PLCEntry
) vplc_lru_link
; /* entry's LRU chain link */
195 #define VOLFSPLCHASH(fsid, inum) ((((unsigned long)fsid) + (unsigned long)(inum)) & volfs_PLCHashMask)
197 static struct slock volfs_PLChashtable_slock
;
198 static TAILQ_HEAD(volfs_PLCLRUListHead
, volfs_PLCEntry
) volfs_PLCLRUList
;
199 static TAILQ_HEAD(volfs_PLCFreeListHead
, volfs_PLCEntry
) volfs_PLCFreeList
;
200 static LIST_HEAD(, volfs_PLCEntry
) *volfs_PLCHashTable
;
201 static u_long volfs_PLCHashMask
; /* size of hash table - 1 */
202 static u_long volfs_PLCEntryCount
;
204 #if DBG_VOP_TEST_LOCKS
205 static void DbgVopTest (int max
, int error
, VopDbgStoreRec
*VopDbgStore
, char *funcname
);
206 #endif /* DBG_VOP_TEST_LOCKS */
212 __private_extern__
void
213 volfs_PLChashinit(void)
217 TAILQ_INIT(&volfs_PLCLRUList
);
218 TAILQ_INIT(&volfs_PLCFreeList
);
219 simple_lock_init(&volfs_PLChashtable_slock
);
221 volfs_PLCHashTable
= hashinit(PLCHASHSIZE
, M_TEMP
, &volfs_PLCHashMask
);
223 for (i
= 0; i
< PLCHASHSIZE
; ++i
) {
224 LIST_INIT(&volfs_PLCHashTable
[i
]);
227 volfs_PLCEntryCount
= 0;
232 __private_extern__
void
233 volfs_PLC_reclaim_entries(int entrycount
)
237 struct volfs_PLCEntry
*reclaim_target
;
239 simple_lock(&volfs_PLChashtable_slock
);
241 for (i
= entrycount
; i
> 0; --i
) {
242 if (TAILQ_EMPTY(&volfs_PLCLRUList
)) break;
244 /* Pick the next entry to be recycled and free it: */
245 reclaim_target
= TAILQ_FIRST(&volfs_PLCLRUList
);
246 TAILQ_REMOVE(&volfs_PLCLRUList
, reclaim_target
, vplc_lru_link
);
247 LIST_REMOVE(reclaim_target
, vplc_hash_link
);
248 TAILQ_INSERT_TAIL(&volfs_PLCFreeList
, reclaim_target
, vplc_lru_link
);
251 simple_unlock(&volfs_PLChashtable_slock
);
261 * Look up a PLC entry in the hash
264 volfs_PLCLookup(int32_t fsid
, u_int target_id
, uid_t uid
, pid_t pid
)
266 struct volfs_PLCEntry
*hash_entry
;
269 simple_lock(&volfs_PLChashtable_slock
);
270 LIST_FOREACH(hash_entry
, &volfs_PLCHashTable
[VOLFSPLCHASH(fsid
, target_id
)], vplc_hash_link
) {
271 if ((hash_entry
->vplc_item_id
== target_id
) &&
272 (hash_entry
->vplc_pid
== pid
) &&
273 (hash_entry
->vplc_uid
== uid
) &&
274 (hash_entry
->vplc_fsid
== fsid
)) {
277 if (hash_entry
!= TAILQ_LAST(&volfs_PLCLRUList
, volfs_PLCLRUListHead
)) {
278 TAILQ_REMOVE(&volfs_PLCLRUList
, hash_entry
, vplc_lru_link
);
279 TAILQ_INSERT_TAIL(&volfs_PLCLRUList
, hash_entry
, vplc_lru_link
);
285 simple_unlock(&volfs_PLChashtable_slock
);
291 volfs_PLCEnter(int32_t fsid
, u_int target_id
, uid_t uid
, pid_t pid
)
293 struct volfs_PLCEntry
*new_entry
;
295 simple_lock(&volfs_PLChashtable_slock
);
296 if (!TAILQ_EMPTY(&volfs_PLCFreeList
)) {
297 new_entry
= TAILQ_FIRST(&volfs_PLCFreeList
);
298 TAILQ_REMOVE(&volfs_PLCFreeList
, new_entry
, vplc_lru_link
);
301 * Allocate up to the predetermined maximum number of new entries:
302 * [must be done now to avoid blocking in MALLOC() with volfs_PLChashtable_slock held locked]
304 if (volfs_PLCEntryCount
< MAXPLCENTRIES
) {
305 simple_unlock(&volfs_PLChashtable_slock
);
306 new_entry
= MALLOC(new_entry
, struct volfs_PLCEntry
*, sizeof(struct volfs_PLCEntry
), M_TEMP
, M_WAITOK
);
307 simple_lock(&volfs_PLChashtable_slock
);
308 ++volfs_PLCEntryCount
;
310 new_entry
= TAILQ_FIRST(&volfs_PLCLRUList
);
311 TAILQ_REMOVE(&volfs_PLCLRUList
, new_entry
, vplc_lru_link
);
312 LIST_REMOVE(new_entry
, vplc_hash_link
);
316 new_entry
->vplc_fsid
= fsid
;
317 new_entry
->vplc_item_id
= target_id
;
318 new_entry
->vplc_uid
= uid
;
319 new_entry
->vplc_pid
= pid
;
321 /* Link the new entry on the hash list for the fsid/target_id as well as the tail of the LRU list: */
322 LIST_INSERT_HEAD(&volfs_PLCHashTable
[VOLFSPLCHASH(fsid
, target_id
)], new_entry
, vplc_hash_link
);
323 TAILQ_INSERT_TAIL(&volfs_PLCLRUList
, new_entry
, vplc_lru_link
);
324 simple_unlock(&volfs_PLChashtable_slock
);
330 * volfs_reclaim - Reclaim a vnode so that it can be used for other purposes.
332 * Locking policy: ignored
336 struct vop_reclaim_args
/* { struct vnode *a_vp; struct proc *a_p; } */ *ap
;
338 struct vnode
*vp
= ap
->a_vp
;
339 void *data
= vp
->v_data
;
341 DBG_FUNC_NAME("volfs_reclaim");
342 DBG_VOP_LOCKS_DECL(1);
343 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
345 DBG_VOP_LOCKS_INIT(0, vp
, VOPDBG_UNLOCKED
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_ZERO
);
348 FREE(data
, M_VOLFSNODE
);
350 DBG_VOP_LOCKS_TEST(0);
355 * volfs_access - same access policy for all vnodes and all users (file/directory vnodes
356 * for the actual file systems are handled by actual file system)
358 * Locking policy: a_vp locked on input and output
362 struct vop_access_args
/* { struct vnode *a_vp; int a_mode; struct
363 ucred *a_cred; struct proc *a_p; } */ *ap
;
366 DBG_FUNC_NAME("volfs_access");
367 DBG_VOP_LOCKS_DECL(1);
368 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
370 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
373 * We don't need to check credentials! FS is read-only for everyone
375 if ((ap
->a_mode
& ~(VREAD
| VEXEC
)) == 0)
380 DBG_VOP_LOCKS_TEST(ret_err
);
385 * volfs_getattr - fill in the attributes for this vnode
387 * Locking policy: don't change anything
391 struct vop_getattr_args
/* { struct vnode *a_vp; struct vattr *a_vap;
392 struct ucred *a_cred; struct proc *a_p; } */ *ap
;
394 struct volfs_vndata
*priv_data
;
398 DBG_FUNC_NAME("volfs_getattr");
399 DBG_VOP_LOCKS_DECL(1);
400 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
402 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_SAME
, VOPDBG_SAME
, VOPDBG_SAME
, VOPDBG_POS
);
407 priv_data
= a_vp
->v_data
;
409 a_vap
->va_type
= VDIR
;
410 a_vap
->va_mode
= 0444; /* Yup, hard - coded to read - only */
412 a_vap
->va_uid
= 0; /* Always owned by root */
413 a_vap
->va_gid
= 0; /* Always part of group 0 */
414 a_vap
->va_fsid
= (int) a_vp
->v_mount
->mnt_stat
.f_fsid
.val
[0];
415 a_vap
->va_fileid
= priv_data
->nodeID
;
418 * If it's the root vnode calculate its size based on the number of eligible
421 if (priv_data
->vnode_type
== VOLFS_ROOT
)
423 register struct mount
*mp
, *nmp
;
425 simple_lock(&mountlist_slock
);
426 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
427 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, ap
->a_p
)) {
428 nmp
= mp
->mnt_list
.cqe_next
;
432 if (mp
!= a_vp
->v_mount
&& validfsnode(mp
))
435 simple_lock(&mountlist_slock
);
436 nmp
= mp
->mnt_list
.cqe_next
;
437 vfs_unbusy(mp
, ap
->a_p
);
439 simple_unlock(&mountlist_slock
);
441 DBG_VOP(("found %d file systems that volfs can support\n", numMounts
));
442 a_vap
->va_size
= (numMounts
+ 2) * VLFSDIRENTLEN
;
446 a_vap
->va_size
= 2 * VLFSDIRENTLEN
;
448 DBG_VOP(("va_size = %d, VLFSDIRENTLEN = %ld\n", (int) a_vap
->va_size
, VLFSDIRENTLEN
));
449 a_vap
->va_blocksize
= 512;
451 a_vap
->va_atime
.tv_sec
= boottime
.tv_sec
;
452 a_vap
->va_atime
.tv_nsec
= 0;
454 a_vap
->va_mtime
.tv_sec
= boottime
.tv_sec
;
455 a_vap
->va_mtime
.tv_nsec
= 0;
457 a_vap
->va_ctime
.tv_sec
= boottime
.tv_sec
;
458 a_vap
->va_ctime
.tv_nsec
= 0;
463 a_vap
->va_bytes
= a_vap
->va_size
;
464 a_vap
->va_filerev
= 0;
465 a_vap
->va_vaflags
= 0;
467 DBG_VOP_LOCKS_TEST(0);
472 * volfs_select - just say OK. Only possible op is readdir
474 * Locking policy: ignore
478 struct vop_select_args
/* { struct vnode *a_vp; int a_which; int
479 * a_fflags; struct ucred *a_cred; void * a_wql; struct
482 DBG_VOP(("volfs_select called\n"));
488 * vofls_rmdir - not possible to remove directories in volfs
490 * Locking policy: a_dvp & a_vp - locked on entry, unlocked on exit
494 struct vop_rmdir_args
/* { struct vnode *a_dvp; struct vnode *a_vp;
495 struct componentname *a_cnp; } */ *ap
;
497 DBG_VOP(("volfs_rmdir called\n"));
498 if (ap
->a_dvp
== ap
->a_vp
) {
499 (void) nop_rmdir(ap
);
502 return (err_rmdir(ap
));
506 * volfs_readdir - Get directory entries
508 * Directory listings are only produced for the root volfs node. Filesystems
510 * Filesystems contained within the volfs root are named by the decimal
511 * equivalent of the f_fsid.val[0] from their mount structure (typically
512 * the device id of the volume). The maximum length for a name, then is
515 * Locking policy: a_vp locked on entry and exit
519 struct vop_readdir_args
/* { struct vnode *a_vp; struct uio *a_uio;
520 * struct ucred *a_cred; int *a_eofflag; int
521 *ncookies; u_long **a_cookies; } */ *ap
;
523 struct volfs_vndata
*priv_data
;
524 register struct uio
*uio
= ap
->a_uio
;
528 struct dirent local_dir
;
532 DBG_FUNC_NAME("volfs_readdir");
533 DBG_VOP_LOCKS_DECL(1);
535 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
536 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
538 DBG_VOP(("\tuio_offset = %d, uio_resid = %d\n", (int) uio
->uio_offset
, uio
->uio_resid
));
539 /* We assume it's all one big buffer... */
540 if (uio
->uio_iovcnt
> 1)
541 DBG_VOP(("\tuio->uio_iovcnt = %d?\n", uio
->uio_iovcnt
));
543 off
= uio
->uio_offset
;
544 priv_data
= ap
->a_vp
->v_data
;
545 starting_resid
= uio
->uio_resid
;
546 count
= uio
->uio_resid
;
548 /* Make sure we don't return partial entries. */
549 count
-= (uio
->uio_offset
+ count
) & (VLFSDIRENTLEN
- 1);
552 DBG_VOP(("volfs_readdir: Not enough buffer to read in entries\n"));
553 DBG_VOP_LOCKS_TEST(EINVAL
);
557 * Make sure we're starting on a directory boundary
559 if (off
& (VLFSDIRENTLEN
- 1))
561 DBG_VOP_LOCKS_TEST(EINVAL
);
564 rec_offset
= off
/ VLFSDIRENTLEN
;
565 lost
= uio
->uio_resid
- count
;
566 uio
->uio_resid
= count
;
567 uio
->uio_iov
->iov_len
= count
;
569 local_dir
.d_reclen
= VLFSDIRENTLEN
;
571 * We must synthesize . and ..
573 DBG_VOP(("\tstarting ... uio_offset = %d, uio_resid = %d\n",
574 (int) uio
->uio_offset
, uio
->uio_resid
));
577 DBG_VOP(("\tAdding .\n"));
581 local_dir
.d_fileno
= priv_data
->nodeID
;
582 local_dir
.d_type
= DT_DIR
;
583 local_dir
.d_namlen
= 1;
584 local_dir
.d_name
[0] = '.';
585 for (i
= 1; i
< MAXVLFSNAMLEN
; i
++)
586 local_dir
.d_name
[i
] = 0;
587 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
588 DBG_VOP(("\t after adding ., uio_offset = %d, uio_resid = %d\n",
589 (int) uio
->uio_offset
, uio
->uio_resid
));
594 DBG_VOP(("\tAdding ..\n"));
597 * We only have two levels in the volfs hierarchy. Root's
598 * .. points to itself and the second level points to root,
599 * hence we've hardcoded d_fileno for .. here
601 local_dir
.d_fileno
= ROOT_DIRID
;
602 local_dir
.d_type
= DT_DIR
;
603 local_dir
.d_namlen
= 2;
604 local_dir
.d_name
[0] = '.';
605 local_dir
.d_name
[1] = '.';
606 for (i
= 2; i
< MAXVLFSNAMLEN
; i
++)
607 local_dir
.d_name
[i
] = 0;
608 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
610 DBG_VOP(("\t after adding .., uio_offset = %d, uio_resid = %d\n",
611 (int) uio
->uio_offset
, uio
->uio_resid
));
615 * OK, we've given them the . & .. entries. If this is a
616 * filesystem node then we've gone as far as we're going
619 if (priv_data
->vnode_type
== VOLFS_FSNODE
)
621 *ap
->a_eofflag
= 1; /* we got all the way to the end */
622 DBG_VOP_LOCKS_TEST(error
);
626 if (rec_offset
> 1) {
627 register struct mount
*mp
, *nmp
;
629 struct proc
*p
= uio
->uio_procp
;
631 validnodeindex
= 1; /* we always have "." and ".." */
633 simple_lock(&mountlist_slock
);
634 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
635 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
636 nmp
= mp
->mnt_list
.cqe_next
;
640 if (mp
!= ap
->a_vp
->v_mount
&& validfsnode(mp
))
643 if (rec_offset
== validnodeindex
)
645 local_dir
.d_fileno
= mp
->mnt_stat
.f_fsid
.val
[0];
646 local_dir
.d_type
= DT_DIR
;
647 local_dir
.d_reclen
= VLFSDIRENTLEN
;
648 DBG_VOP(("\tAdding dir entry %d for offset %d\n", mp
->mnt_stat
.f_fsid
.val
[0], rec_offset
));
649 local_dir
.d_namlen
= sprintf(&local_dir
.d_name
[0], "%d", mp
->mnt_stat
.f_fsid
.val
[0]);
650 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
651 DBG_VOP(("\t after adding entry '%s', uio_offset = %d, uio_resid = %d\n",
652 &local_dir
.d_name
[0], (int) uio
->uio_offset
, uio
->uio_resid
));
656 simple_lock(&mountlist_slock
);
657 nmp
= mp
->mnt_list
.cqe_next
;
660 simple_unlock(&mountlist_slock
);
662 if (mp
== (void *) &mountlist
)
663 *ap
->a_eofflag
= 1; /* we got all the way to the end */
666 uio
->uio_resid
+= lost
;
667 if (starting_resid
== uio
->uio_resid
)
670 DBG_VOP(("\tExiting, uio_offset = %d, uio_resid = %d, ap->a_eofflag = %d\n",
671 (int) uio
->uio_offset
, uio
->uio_resid
, *ap
->a_eofflag
));
673 DBG_VOP_LOCKS_TEST(error
);
679 * validfsnode - test to see if a file system supports VGET
681 * This can cause context switching, so caller should be lock safe
684 validfsnode(struct mount
*fsnode
)
688 * Just check to see if the the mount flag is set, if it is we assume the
689 * file system supports all of volfs symantecs
692 if ((! (fsnode
->mnt_kern_flag
& MNTK_UNMOUNT
)) && (fsnode
->mnt_flag
& MNT_DOVOLFS
))
699 * volfs_lock - Lock an inode.
700 * If its already locked, set the WANT bit and sleep.
702 * Locking policy: handled by lockmgr
706 struct vop_lock_args
/* { struct vnode *a_vp; int a_flags; struct
710 struct volfs_vndata
*priv_data
;
711 DBG_FUNC_NAME("volfs_lock");
712 DBG_VOP_LOCKS_DECL(1);
714 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 0)) | DBG_FUNC_START
,
715 (unsigned int)ap
->a_vp
, (unsigned int)ap
->a_flags
, (unsigned int)ap
->a_p
, 0, 0);
717 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
719 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_UNLOCKED
, VOPDBG_LOCKED
, VOPDBG_UNLOCKED
, VOPDBG_ZERO
);
721 priv_data
= (struct volfs_vndata
*) ap
->a_vp
->v_data
;
722 retval
= lockmgr(&priv_data
->lock
, ap
->a_flags
, &ap
->a_vp
->v_interlock
, ap
->a_p
);
723 DBG_VOP_LOCKS_TEST(retval
);
725 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 0)) | DBG_FUNC_END
,
726 (unsigned int)ap
->a_vp
, (unsigned int)ap
->a_flags
, (unsigned int)ap
->a_p
, retval
, 0);
732 * volfs_unlock - Unlock an inode.
734 * Locking policy: handled by lockmgr
738 struct vop_unlock_args
/* { struct vnode *a_vp; int a_flags; struct
742 struct volfs_vndata
*priv_data
;
743 DBG_FUNC_NAME("volfs_unlock");
744 DBG_VOP_LOCKS_DECL(1);
746 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 4)) | DBG_FUNC_START
,
747 (unsigned int)ap
->a_vp
, (unsigned int)ap
->a_flags
, (unsigned int)ap
->a_p
, 0, 0);
749 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
751 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_UNLOCKED
, VOPDBG_LOCKED
, VOPDBG_ZERO
);
753 priv_data
= (struct volfs_vndata
*) ap
->a_vp
->v_data
;
754 retval
= lockmgr(&priv_data
->lock
, ap
->a_flags
| LK_RELEASE
,
755 &ap
->a_vp
->v_interlock
, ap
->a_p
);
757 DBG_VOP_LOCKS_TEST(retval
);
759 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 4)) | DBG_FUNC_END
,
760 (unsigned int)ap
->a_vp
, (unsigned int)ap
->a_flags
, (unsigned int)ap
->a_p
, retval
, 0);
766 * volfs_islocked - Check for a locked inode.
768 * Locking policy: ignore
772 struct vop_islocked_args
/* { struct vnode *a_vp; } */ *ap
;
775 struct volfs_vndata
*priv_data
;
777 DBG_FUNC_NAME("volfs_islocked");
778 DBG_VOP_LOCKS_DECL(1);
779 //DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
781 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_ZERO
);
782 priv_data
= (struct volfs_vndata
*) ap
->a_vp
->v_data
;
783 retval
= lockstatus(&priv_data
->lock
);
785 DBG_VOP_LOCKS_TEST(retval
);
790 * volfs_pathconf - Return POSIX pathconf information applicable to ufs filesystems.
792 * Locking policy: a_vp locked on input and output
796 struct vop_pathconf_args
/* { struct vnode *a_vp; int a_name; int
799 DBG_VOP(("volfs_pathconf called\n"));
804 *ap
->a_retval
= LINK_MAX
;
807 *ap
->a_retval
= NAME_MAX
;
810 *ap
->a_retval
= PATH_MAX
;
813 *ap
->a_retval
= PIPE_BUF
;
815 case _PC_CHOWN_RESTRICTED
:
829 * Call VOP_GETATTRLIST on a given vnode
832 vp_getattrlist(struct vnode
*vp
, struct attrlist alist
, void *attrbufptr
, size_t bufsize
, unsigned long options
, struct proc
*p
) {
836 iov
.iov_base
= (char *)attrbufptr
;
837 iov
.iov_len
= bufsize
;
839 bufuio
.uio_iov
= &iov
;
840 bufuio
.uio_iovcnt
= 1;
841 bufuio
.uio_offset
= 0;
842 bufuio
.uio_resid
= iov
.iov_len
;
843 bufuio
.uio_segflg
= UIO_SYSSPACE
;
844 bufuio
.uio_rw
= UIO_READ
;
845 bufuio
.uio_procp
= p
;
847 return VOP_GETATTRLIST(vp
, &alist
, &bufuio
, p
->p_ucred
, p
);
851 * get_parentvp() - internal routine that tries to lookup the parent of vpp.
852 * On success, *vpp is the parent vp and is returned locked and the original child
853 * is left unlocked. On failure, the original child will be locked upon return.
856 get_parentvp(struct vnode
**vpp
, struct mount
*mp
, struct proc
*p
)
859 struct attrlist alist
;
860 struct finfoattrbuf finfobuf
;
861 struct vnode
*child_vp
= *vpp
;
863 alist
.bitmapcount
= 5;
865 alist
.commonattr
= ATTR_CMN_PAROBJID
;
870 result
= vp_getattrlist(child_vp
, alist
, &finfobuf
, sizeof(finfobuf
), 0, p
);
874 /* Release the child vnode before trying to acquire its parent
875 to avoid vnode deadlock problems with parsing code
876 coming top-down through the directory hierarchy: */
877 VOP_UNLOCK(child_vp
, 0, p
);
879 /* Shift attention to the parent directory vnode: */
880 result
= VFS_VGET(mp
, &finfobuf
.fi
.parID
.fid_objno
, vpp
);
882 /* Make sure child_vp is still locked on exit: */
883 vn_lock(child_vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
891 * Look up the parent directory of a given vnode.
894 lookup_parent(u_int id
, struct vnode
*child_vp
, struct vnode
**parent_vp
, struct proc
*p
)
897 struct componentname
*cnp
= &nd
.ni_cnd
;
898 struct filedesc
*fdp
= p
->p_fd
;
904 * Special case lookups for root's parent directory,
905 * recognized by its special id of "1":
909 nd
.ni_startdir
= child_vp
;
910 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_SYSSPACE
, (caddr_t
)&gDotDot
, p
);
912 struct vnode
*root_vp
;
914 error
= VFS_ROOT(child_vp
->v_mount
, &root_vp
);
915 if (error
) return error
;
916 VOP_UNLOCK(root_vp
, 0, p
); /* Hold on to the reference */
917 nd
.ni_startdir
= root_vp
;
918 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_SYSSPACE
, (caddr_t
)&gDot
, p
);
920 nd
.ni_cnd
.cn_cred
= nd
.ni_cnd
.cn_proc
->p_ucred
;
922 /* Since we can't hit any symlinks, use the source path string directly: */
923 cnp
->cn_pnbuf
= nd
.ni_dirp
;
924 nd
.ni_pathlen
= strlen(cnp
->cn_pnbuf
);
925 cnp
->cn_pnlen
= nd
.ni_pathlen
+ 1;
926 cnp
->cn_flags
|= (HASBUF
| SAVENAME
);
930 if ((nd
.ni_rootdir
= fdp
->fd_rdir
) == NULL
) nd
.ni_rootdir
= rootvnode
;
931 cnp
->cn_nameptr
= cnp
->cn_pnbuf
;
932 if (error
= lookup(&nd
)) {
933 cnp
->cn_pnbuf
= NULL
;
937 * Check for symbolic link
939 if (cnp
->cn_flags
& ISSYMLINK
) return ENOENT
;
940 if (nd
.ni_vp
== child_vp
) return ELOOP
;
942 *parent_vp
= nd
.ni_vp
;
949 * verify_fullpathaccess(ret_vnode);
953 verify_fullpathaccess(u_int id
, struct vnode
*targetvp
, struct proc
*p
) {
954 struct vnode
*vp
, *parent_vp
;
955 struct mount
*mp
= targetvp
->v_mount
;
956 struct attrlist alist
;
957 struct finfoattrbuf finfobuf
;
959 struct filedesc
*fdp
= p
->p_fd
; /* pointer to file descriptor state */
964 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 12)) | DBG_FUNC_START
,
965 (unsigned int)targetvp
, (unsigned int)mp
, (unsigned int)p
, 0, 0);
970 if (vp
->v_type
!= VDIR
) {
972 /* The target is a file: get the parent directory. */
973 result
= get_parentvp(&vp
, mp
, p
);
974 if (result
) goto err_exit
;
976 /* At this point, targetvp is unlocked (but still referenced), and
977 vp is the parent directory vnode, held locked */
982 if (volfs_PLCLookup(mp
->mnt_stat
.f_fsid
.val
[0], id
, p
->p_ucred
->cr_uid
, p
->p_pid
)) goto lookup_success
;
984 /* Keep going up until either the process's root or the process's working directory is hit,
985 either one of which are potential valid starting points for a full pathname: */
987 while (vp
!= NULL
&& (!((vp
->v_flag
& VROOT
) || /* Hit "/" */
988 (vp
== fdp
->fd_cdir
) || /* Hit process's working directory */
989 (vp
== fdp
->fd_rdir
)))) { /* Hit process chroot()-ed root */
991 /* At this point, vp is some directory node and it's always locked */
992 /* Unlock the starting directory for namei(), retaining a reference... */
993 VOP_UNLOCK(vp
, 0, p
);
995 if (result
= lookup_parent(target_id
, vp
, &parent_vp
, p
)) {
997 * If the lookup fails with EACCES and the targetvp is a directory,
998 * we should try again using get_parentvp(). Without this check,
999 * directories that you can navigate to but not traverse will
1000 * disappear when clicked in the Finder.
1002 if (result
== EACCES
&& vp
== targetvp
&& vp
->v_type
== VDIR
&& (vp
->v_flag
& VROOT
) == 0) {
1003 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1005 if (get_parentvp(&parent_vp
, mp
, p
)) {
1006 /* on error, vp is still locked... unlock for lookup_err_exit path */
1007 VOP_UNLOCK(vp
, 0, p
);
1009 /* on success, vp is returned unlocked, parent_vp is returned locked */
1013 if (result
) goto lookup_err_exit
;
1016 if (vp
!= targetvp
) {
1017 vrele(vp
); /* Completely done with that vp now... */
1021 target_id
= 0; /* It's unknown at this point */
1023 if (((result
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
)) != 0) &&
1024 ((result
= VOP_ACCESS(vp
, VREAD
, p
->p_ucred
, p
)) != 0)) {
1025 VOP_UNLOCK(vp
, 0, p
);
1026 goto lookup_err_exit
;
1031 volfs_PLCEnter(mp
->mnt_stat
.f_fsid
.val
[0], id
, p
->p_ucred
->cr_uid
, p
->p_pid
);
1035 /* Success: the caller has complete access to the initial vnode: */
1038 if (vp
&& vp
!= targetvp
) VOP_UNLOCK(vp
, 0, p
);
1041 if (vp
&& vp
!= targetvp
) {
1043 vn_lock(targetvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1044 if (vp_id
!= targetvp
->v_id
|| targetvp
->v_type
== VBAD
) {
1045 result
= EAGAIN
; /* vnode was recycled */
1051 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 12)) | DBG_FUNC_END
,
1052 (unsigned int)targetvp
, (unsigned int)mp
, (unsigned int)p
, result
, 0);
1059 * get_fsvnode - internal routine to create a vnode for a file system. Called with mount pointer,
1060 * id of filesystem to lookup and pointer to vnode pointer to fill in
1063 get_fsvnode(our_mount
, id
, ret_vnode
)
1064 struct mount
*our_mount
;
1066 struct vnode
**ret_vnode
;
1068 register struct mount
*mp
;
1069 struct mount
*cur_mount
;
1070 struct vnode
*cur_vnode
;
1071 struct volfs_vndata
*cur_privdata
;
1074 //DBG_VOP(("volfs: get_fsvnode called\n"));
1077 * OK, first look up the matching mount on the list of mounted file systems
1080 simple_lock(&mountlist_slock
);
1081 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= mp
->mnt_list
.cqe_next
)
1083 if (validfsnode(mp
) && mp
->mnt_stat
.f_fsid
.val
[0] == id
)
1089 simple_unlock(&mountlist_slock
);
1091 if (cur_mount
== NULL
) {
1093 * No mounted file system by the specified ID currently exists in the system.
1095 * XXX We could deal with a vnode that is still hanging about for an FS that
1096 * does not exists or has been unmounted now, or count on the update below
1097 * to happen later...
1104 * Now search the list attached to the mount structure to
1105 * see if this vnode is already floating around
1108 cur_vnode
= our_mount
->mnt_vnodelist
.lh_first
;
1109 while (cur_vnode
!= NULL
)
1111 cur_privdata
= (struct volfs_vndata
*) cur_vnode
->v_data
;
1112 if (cur_privdata
->nodeID
== id
)
1114 if (cur_privdata
->fs_mount
!= cur_mount
) {
1115 DBG_VOP(("volfs get_fsvnode: Updating fs_mount for vnode 0x%08lX (id = %d) from 0x%08lX to 0x%08lX...\n",
1116 (unsigned long)cur_vnode
,
1117 cur_privdata
->nodeID
,
1118 (unsigned long)cur_privdata
->fs_mount
,
1119 (unsigned long)cur_mount
));
1120 cur_privdata
->fs_mount
= cur_mount
;
1124 cur_vnode
= cur_vnode
->v_mntvnodes
.le_next
;
1127 //DBG_VOP(("\tfinal cur_mount: 0x%x\n",cur_mount));
1129 /* If vget returns an error, cur_vnode will not be what we think it is, try again */
1130 if (vget(cur_vnode
, LK_EXCLUSIVE
, current_proc()) != 0) {
1131 goto search_vnodelist
;
1136 MALLOC(cur_privdata
, struct volfs_vndata
*,
1137 sizeof(struct volfs_vndata
), M_VOLFSNODE
, M_WAITOK
);
1138 retval
= getnewvnode(VT_VOLFS
, our_mount
, volfs_vnodeop_p
, &cur_vnode
);
1140 FREE(cur_privdata
, M_VOLFSNODE
);
1144 cur_privdata
->vnode_type
= VOLFS_FSNODE
;
1145 cur_privdata
->nodeID
= id
;
1147 cur_privdata
->fs_mount
= cur_mount
;
1148 lockinit(&cur_privdata
->lock
, PINOD
, "volfsnode", 0, 0);
1149 lockmgr(&cur_privdata
->lock
, LK_EXCLUSIVE
, (struct slock
*)0, current_proc());
1150 cur_vnode
->v_data
= cur_privdata
;
1151 cur_vnode
->v_type
= VDIR
;
1152 DBG_VOP(("get_fsvnode returned with new node of "));
1153 DBG_VOP_PRINT_VNODE_INFO(cur_vnode
);DBG_VOP(("\n"));
1156 *ret_vnode
= cur_vnode
;
1164 * get_filevnode - returns the vnode for the given id within a filesystem. The parent vnode
1165 * is a filesystem, id is the 32-bit id of the file/directory and ret_vnode is a pointer
1166 * to a vnode pointer
1169 get_filevnode(parent_fs
, id
, ret_vnode
, p
)
1170 struct mount
*parent_fs
;
1172 struct vnode
**ret_vnode
;
1179 * Special case 2 to mean the root of a file system
1182 retval
= VFS_ROOT(parent_fs
, ret_vnode
);
1184 retval
= VFS_VGET(parent_fs
, &id
, ret_vnode
);
1185 if (retval
) goto error
;
1187 retval
= verify_fullpathaccess(id
, *ret_vnode
, p
);
1189 /* An error was encountered verifying that the caller has,
1190 in fact, got access all the way from "/" or their working
1191 directory to the specified item...
1195 /* vnode was recycled during access verification. */
1196 if (retval
== EAGAIN
) {
1208 struct vop_lookup_args
/* { struct vnode *a_dvp; struct vnode
1209 **a_vpp; struct componentname *a_cnp; } */ *ap
;
1211 struct volfs_vndata
*priv_data
;
1214 struct mount
*parent_fs
;
1215 int unlocked_parent
= 0, isdot_or_dotdot
= 0;
1216 int ret_err
= ENOENT
;
1217 DBG_FUNC_NAME("volfs_lookup");
1218 DBG_VOP_LOCKS_DECL(2);
1221 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 8)) | DBG_FUNC_START
,
1222 (unsigned int)ap
->a_dvp
, (unsigned int)ap
->a_cnp
, (unsigned int)p
, 0, 0);
1225 DBG_VOP(("volfs_lookup called, name = %s, namelen = %ld\n", ap
->a_cnp
->cn_nameptr
, ap
->a_cnp
->cn_namelen
));
1227 DBG_VOP_LOCKS_INIT(0,ap
->a_dvp
, VOPDBG_LOCKED
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_POS
);
1228 DBG_VOP_LOCKS_INIT(1,*ap
->a_vpp
, VOPDBG_IGNORE
, VOPDBG_LOCKED
, VOPDBG_IGNORE
, VOPDBG_POS
);
1229 DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
1230 DBG_VOP(("\t"));DBG_VOP_PRINT_CPN_INFO(ap
->a_cnp
);DBG_VOP(("\n"));
1231 if (ap
->a_cnp
->cn_flags
& LOCKPARENT
)
1232 DBG_VOP(("\tLOCKPARENT is set\n"));
1233 if (ap
->a_cnp
->cn_flags
& ISLASTCN
)
1235 DBG_VOP(("\tISLASTCN is set\n"));
1236 if (ap
->a_cnp
->cn_nameiop
== DELETE
|| ap
->a_cnp
->cn_nameiop
== RENAME
) /* XXX PPD Shouldn't we check for CREATE, too? */
1242 priv_data
= ap
->a_dvp
->v_data
;
1243 cnp
= ap
->a_cnp
->cn_nameptr
;
1244 namelen
= ap
->a_cnp
->cn_namelen
;
1247 switch (priv_data
->vnode_type
) {
1249 DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_ROOT.\n", (unsigned long)ap
->a_dvp
));
1253 DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_FSNODE, nodeID = %d, fs_mount = 0x%08lX.\n",
1254 (unsigned long)ap
->a_dvp
,
1256 (unsigned long)priv_data
->fs_mount
));
1259 DBG_VOP(("\tparent directory (vnode 0x%08lX) has unknown vnode_type (%d), nodeID = %d.\n",
1260 (unsigned long)ap
->a_dvp
,
1261 priv_data
->vnode_type
,
1262 priv_data
->nodeID
));
1264 #endif /* VOLFS_DEBUG */
1266 /* first check for "." and ".." */
1272 isdot_or_dotdot
= 1;
1273 *ap
->a_vpp
= ap
->a_dvp
;
1275 DBG_VOP_LOCKS_TEST(0);
1278 else if (cnp
[1] == '.' && namelen
== 2)
1280 /* ".." requested */
1281 isdot_or_dotdot
= 1;
1282 ret_err
= volfs_root(ap
->a_dvp
->v_mount
, ap
->a_vpp
);
1286 /* then look for special file system root symbol ('@') */
1287 else if (cnp
[0] == '@')
1289 if ((namelen
== 1) && (priv_data
->vnode_type
!= VOLFS_ROOT
)) {
1290 parent_fs
= priv_data
->fs_mount
;
1291 if (!(ap
->a_cnp
->cn_flags
& LOCKPARENT
) || !(ap
->a_cnp
->cn_flags
& ISLASTCN
)) {
1292 VOP_UNLOCK(ap
->a_dvp
, 0, ap
->a_cnp
->cn_proc
);
1293 unlocked_parent
= 1;
1295 ret_err
= VFS_ROOT(parent_fs
, ap
->a_vpp
);
1297 DBG_VOP(("volfs_lookup: pathname = '@' but namelen = %ld and parent vnode_type = %d.\n", namelen
, priv_data
->vnode_type
));
1303 /* finally, just look for numeric ids... */
1304 else if (namelen
<= 10 && cnp
[0] > '0' && cnp
[0] <= '9') /* 10 digits max lead digit must be 1 - 9 */
1309 id
= strtoul(cnp
, &check_ptr
, 10);
1312 * strtol will leave us at the first non-numeric character.
1313 * we've checked to make sure the component name does
1314 * begin with a numeric so check_ptr must wind up on
1315 * the terminating null or there was other junk following the
1318 if ((check_ptr
- cnp
) == namelen
)
1320 if (priv_data
->vnode_type
== VOLFS_ROOT
)
1321 ret_err
= get_fsvnode(ap
->a_dvp
->v_mount
, id
, ap
->a_vpp
);
1323 parent_fs
= priv_data
->fs_mount
;
1324 if (!(ap
->a_cnp
->cn_flags
& LOCKPARENT
) || !(ap
->a_cnp
->cn_flags
& ISLASTCN
)) {
1325 VOP_UNLOCK(ap
->a_dvp
, 0, ap
->a_cnp
->cn_proc
);
1326 unlocked_parent
= 1;
1328 ret_err
= get_filevnode(parent_fs
, id
, ap
->a_vpp
, ap
->a_cnp
->cn_proc
);
1333 if (!isdot_or_dotdot
&& *ap
->a_vpp
&& VPARENT(*ap
->a_vpp
) == NULL
&& ap
->a_dvp
!= *ap
->a_vpp
) {
1334 if (VPARENT(ap
->a_dvp
) == *ap
->a_vpp
) {
1335 panic("volfs: ap->a_dvp 0x%x has parent == a_vpp 0x%x\n",
1336 ap
->a_dvp
, *ap
->a_vpp
);
1338 vget(ap
->a_dvp
, 0, ap
->a_cnp
->cn_proc
);
1339 VPARENT(*ap
->a_vpp
) = ap
->a_dvp
;
1342 if (!unlocked_parent
&& (!(ap
->a_cnp
->cn_flags
& LOCKPARENT
) || !(ap
->a_cnp
->cn_flags
& ISLASTCN
))) {
1343 VOP_UNLOCK(ap
->a_dvp
, 0, ap
->a_cnp
->cn_proc
);
1346 /* XXX PPD Should we do something special in case LOCKLEAF isn't set? */
1350 DBG_VOP_UPDATE_VP(1, *ap
->a_vpp
);
1351 DBG_VOP_LOCKS_TEST(ret_err
);
1354 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN
, 8)) | DBG_FUNC_START
,
1355 (unsigned int)ap
->a_dvp
, (unsigned int)ap
->a_cnp
, (unsigned int)p
, ret_err
, 0);
1360 #if DBG_VOP_TEST_LOCKS
1363 static void DbgLookupTest( char *funcname
, struct componentname
*cnp
, struct vnode
*dvp
, struct vnode
*vp
)
1365 int flags
= cnp
->cn_flags
;
1366 int nameiop
= cnp
->cn_nameiop
;
1368 DBG_VOP (("%s: Action:", funcname
));
1384 PRINTIT ("!!!UNKNOWN!!!!");
1387 PRINTIT(" flags: 0x%x ",flags
);
1388 if (flags
& LOCKPARENT
)
1389 PRINTIT (" Lock Parent");
1390 if (flags
& ISLASTCN
)
1391 PRINTIT (" Last Action");
1396 PRINTIT ("%s: Parent vnode exited ", funcname
);
1397 if (VOP_ISLOCKED(dvp
))
1398 PRINTIT("LOCKED\n");
1400 PRINTIT("UNLOCKED\n");
1404 PRINTIT ("%s: Found and Parent are the same\n", funcname
);
1408 PRINTIT ("%s: Found vnode exited ", funcname
);
1409 if (VOP_ISLOCKED(vp
))
1410 PRINTIT("LOCKED\n");
1412 PRINTIT("UNLOCKED\n");
1415 PRINTIT ("%s: Found vnode exited NULL\n", funcname
);
1421 static void DbgVopTest( int maxSlots
,
1423 VopDbgStoreRec
*VopDbgStore
,
1428 for (index
= 0; index
< maxSlots
; index
++)
1430 if (VopDbgStore
[index
].id
!= index
) {
1431 PRINTIT("%s: DBG_VOP_LOCK: invalid id field (%d) in target entry (#%d).\n", funcname
, VopDbgStore
[index
].id
, index
);
1435 if ((VopDbgStore
[index
].vp
!= NULL
) &&
1436 ((VopDbgStore
[index
].vp
->v_data
==NULL
)))
1439 switch (VopDbgStore
[index
].inState
)
1443 /* Do Nothing !!! */
1446 case VOPDBG_UNLOCKED
:
1447 case VOPDBG_LOCKNOTNIL
:
1449 if (VopDbgStore
[index
].vp
== NULL
&& (VopDbgStore
[index
].inState
!= VOPDBG_LOCKNOTNIL
)) {
1450 PRINTIT ("%s: InState check: Null vnode ptr in entry #%d\n", funcname
, index
);
1451 } else if (VopDbgStore
[index
].vp
!= NULL
) {
1452 switch (VopDbgStore
[index
].inState
)
1455 case VOPDBG_LOCKNOTNIL
:
1456 if (VopDbgStore
[index
].inValue
== 0)
1458 PRINTIT ("%s: %d Entry: not LOCKED:", funcname
, index
); DBG_VOP(("\n"));
1461 case VOPDBG_UNLOCKED
:
1462 if (VopDbgStore
[index
].inValue
!= 0)
1464 PRINTIT ("%s: %d Entry: not UNLOCKED:", funcname
, index
); DBG_VOP(("\n"));
1472 PRINTIT ("%s: DBG_VOP_LOCK on entry: bad lock test value: %d\n", funcname
, VopDbgStore
[index
].errState
);
1478 switch (VopDbgStore
[index
].errState
)
1481 /* Do Nothing !!! */
1484 case VOPDBG_UNLOCKED
:
1487 if (VopDbgStore
[index
].vp
== NULL
) {
1488 PRINTIT ("%s: ErrState check: Null vnode ptr in entry #%d\n", funcname
, index
);
1490 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1491 switch (VopDbgStore
[index
].errState
)
1494 if (VopDbgStore
[index
].outValue
== 0)
1496 PRINTIT ("%s: %d Error: not LOCKED:", funcname
, index
); DBG_VOP(("\n"));
1499 case VOPDBG_UNLOCKED
:
1500 if (VopDbgStore
[index
].outValue
!= 0)
1502 PRINTIT ("%s: %d Error: not UNLOCKED:", funcname
, index
); DBG_VOP(("\n"));
1506 if (VopDbgStore
[index
].outValue
!= VopDbgStore
[index
].inValue
)
1507 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
);
1513 case VOPDBG_LOCKNOTNIL
:
1514 if (VopDbgStore
[index
].vp
!= NULL
) {
1515 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1516 if (VopDbgStore
[index
].outValue
== 0)
1517 PRINTIT ("%s: Error: %d Not LOCKED: 0x%x\n", funcname
, index
, (u_int
)VopDbgStore
[index
].vp
);
1521 PRINTIT ("%s: Error: bad lock test value: %d\n", funcname
, VopDbgStore
[index
].errState
);
1526 switch (VopDbgStore
[index
].outState
)
1529 /* Do Nothing !!! */
1532 case VOPDBG_UNLOCKED
:
1534 if (VopDbgStore
[index
].vp
== NULL
) {
1535 PRINTIT ("%s: OutState: Null vnode ptr in entry #%d\n", funcname
, index
);
1537 if (VopDbgStore
[index
].vp
!= NULL
)
1539 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1540 switch (VopDbgStore
[index
].outState
)
1543 if (VopDbgStore
[index
].outValue
== 0)
1545 PRINTIT ("%s: %d Out: not LOCKED:", funcname
, index
); DBG_VOP(("\n"));
1548 case VOPDBG_UNLOCKED
:
1549 if (VopDbgStore
[index
].outValue
!= 0)
1551 PRINTIT ("%s: %d Out: not UNLOCKED:", funcname
, index
); DBG_VOP(("\n"));
1555 if (VopDbgStore
[index
].outValue
!= VopDbgStore
[index
].inValue
)
1556 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
);
1561 case VOPDBG_LOCKNOTNIL
:
1562 if (VopDbgStore
[index
].vp
!= NULL
) {
1563 if (&((struct volfs_vndata
*)(VopDbgStore
[index
].vp
->v_data
))->lock
== NULL
)
1564 PRINTIT ("%s: DBG_VOP_LOCK on out: Null lock on vnode 0x%x\n", funcname
, (u_int
)VopDbgStore
[index
].vp
);
1566 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1567 if (VopDbgStore
[index
].outValue
== 0)
1569 PRINTIT ("%s: DBG_VOP_LOCK on out: Should be LOCKED:", funcname
); DBG_VOP(("\n"));
1575 PRINTIT ("%s: DBG_VOP_LOCK on out: bad lock test value: %d\n", funcname
, VopDbgStore
[index
].outState
);
1579 VopDbgStore
[index
].id
= -1; /* Invalidate the entry to allow panic-free re-use */
1583 #endif /* DBG_VOP_TEST_LOCKS */