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>
53 #include <sys/mount.h>
54 #include <sys/vnode.h>
55 #include <sys/malloc.h>
56 #include <sys/dirent.h>
57 #include <sys/namei.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
};
172 static int validfsnode(struct mount
*fsnode
);
174 #if DBG_VOP_TEST_LOCKS
175 static void DbgVopTest (int max
, int error
, VopDbgStoreRec
*VopDbgStore
, char *funcname
);
176 #endif /* DBG_VOP_TEST_LOCKS */
180 * volfs_reclaim - Reclaim a vnode so that it can be used for other purposes.
182 * Locking policy: ignored
186 struct vop_reclaim_args
/* { struct vnode *a_vp; struct proc *a_p; } */ *ap
;
188 struct vnode
*vp
= ap
->a_vp
;
189 void *data
= vp
->v_data
;
191 DBG_FUNC_NAME("volfs_reclaim");
192 DBG_VOP_LOCKS_DECL(1);
193 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
195 DBG_VOP_LOCKS_INIT(0, vp
, VOPDBG_UNLOCKED
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_ZERO
);
198 FREE(data
, M_VOLFSNODE
);
200 DBG_VOP_LOCKS_TEST(0);
205 * volfs_access - same access policy for all vnodes and all users (file/directory vnodes
206 * for the actual file systems are handled by actual file system)
208 * Locking policy: a_vp locked on input and output
212 struct vop_access_args
/* { struct vnode *a_vp; int a_mode; struct
213 ucred *a_cred; struct proc *a_p; } */ *ap
;
216 DBG_FUNC_NAME("volfs_access");
217 DBG_VOP_LOCKS_DECL(1);
218 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
220 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
223 * We don't need to check credentials! FS is read-only for everyone
225 if (ap
->a_mode
== VREAD
|| ap
->a_mode
== VEXEC
)
230 DBG_VOP_LOCKS_TEST(ret_err
);
235 * volfs_getattr - fill in the attributes for this vnode
237 * Locking policy: don't change anything
241 struct vop_getattr_args
/* { struct vnode *a_vp; struct vattr *a_vap;
242 struct ucred *a_cred; struct proc *a_p; } */ *ap
;
244 struct volfs_vndata
*priv_data
;
248 DBG_FUNC_NAME("volfs_getattr");
249 DBG_VOP_LOCKS_DECL(1);
250 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
252 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_SAME
, VOPDBG_SAME
, VOPDBG_SAME
, VOPDBG_POS
);
257 priv_data
= a_vp
->v_data
;
259 a_vap
->va_type
= VDIR
;
260 a_vap
->va_mode
= 0444; /* Yup, hard - coded to read - only */
262 a_vap
->va_uid
= 0; /* Always owned by root */
263 a_vap
->va_gid
= 0; /* Always part of group 0 */
264 a_vap
->va_fsid
= (int) a_vp
->v_mount
->mnt_stat
.f_fsid
.val
[0];
265 a_vap
->va_fileid
= priv_data
->nodeID
;
268 * If it's the root vnode calculate its size based on the number of eligible
271 if (priv_data
->vnode_type
== VOLFS_ROOT
)
273 register struct mount
*mp
, *nmp
;
275 simple_lock(&mountlist_slock
);
276 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
277 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, ap
->a_p
)) {
278 nmp
= mp
->mnt_list
.cqe_next
;
282 if (mp
!= a_vp
->v_mount
&& validfsnode(mp
))
285 simple_lock(&mountlist_slock
);
286 nmp
= mp
->mnt_list
.cqe_next
;
287 vfs_unbusy(mp
, ap
->a_p
);
289 simple_unlock(&mountlist_slock
);
291 DBG_VOP(("found %d file systems that volfs can support\n", numMounts
));
292 a_vap
->va_size
= (numMounts
+ 2) * VLFSDIRENTLEN
;
296 a_vap
->va_size
= 2 * VLFSDIRENTLEN
;
298 DBG_VOP(("va_size = %d, VLFSDIRENTLEN = %ld\n", (int) a_vap
->va_size
, VLFSDIRENTLEN
));
299 a_vap
->va_blocksize
= 512;
301 a_vap
->va_atime
.tv_sec
= boottime
.tv_sec
;
302 a_vap
->va_atime
.tv_nsec
= 0;
304 a_vap
->va_mtime
.tv_sec
= boottime
.tv_sec
;
305 a_vap
->va_mtime
.tv_nsec
= 0;
307 a_vap
->va_ctime
.tv_sec
= boottime
.tv_sec
;
308 a_vap
->va_ctime
.tv_nsec
= 0;
313 a_vap
->va_bytes
= a_vap
->va_size
;
314 a_vap
->va_filerev
= 0;
315 a_vap
->va_vaflags
= 0;
317 DBG_VOP_LOCKS_TEST(0);
322 * volfs_select - just say OK. Only possible op is readdir
324 * Locking policy: ignore
328 struct vop_select_args
/* { struct vnode *a_vp; int a_which; int
329 * a_fflags; struct ucred *a_cred; void * a_wql; struct
332 DBG_VOP(("volfs_select called\n"));
338 * vofls_rmdir - not possible to remove directories in volfs
340 * Locking policy: a_dvp & a_vp - locked on entry, unlocked on exit
344 struct vop_rmdir_args
/* { struct vnode *a_dvp; struct vnode *a_vp;
345 struct componentname *a_cnp; } */ *ap
;
347 DBG_VOP(("volfs_rmdir called\n"));
348 if (ap
->a_dvp
== ap
->a_vp
) {
349 (void) nop_rmdir(ap
);
352 return (err_rmdir(ap
));
356 * volfs_readdir - Get directory entries
358 * Directory listings are only produced for the root volfs node. Filesystems
360 * Filesystems contained within the volfs root are named by the decimal
361 * equivalent of the f_fsid.val[0] from their mount structure (typically
362 * the device id of the volume). The maximum length for a name, then is
365 * Locking policy: a_vp locked on entry and exit
369 struct vop_readdir_args
/* { struct vnode *a_vp; struct uio *a_uio;
370 * struct ucred *a_cred; int *a_eofflag; int
371 *ncookies; u_long **a_cookies; } */ *ap
;
373 struct volfs_vndata
*priv_data
;
374 register struct uio
*uio
= ap
->a_uio
;
378 struct dirent local_dir
;
382 DBG_FUNC_NAME("volfs_readdir");
383 DBG_VOP_LOCKS_DECL(1);
385 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
386 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
388 DBG_VOP(("\tuio_offset = %d, uio_resid = %d\n", (int) uio
->uio_offset
, uio
->uio_resid
));
389 /* We assume it's all one big buffer... */
390 if (uio
->uio_iovcnt
> 1)
391 DBG_VOP(("\tuio->uio_iovcnt = %d?\n", uio
->uio_iovcnt
));
393 off
= uio
->uio_offset
;
394 priv_data
= ap
->a_vp
->v_data
;
395 starting_resid
= uio
->uio_resid
;
396 count
= uio
->uio_resid
;
398 /* Make sure we don't return partial entries. */
399 count
-= (uio
->uio_offset
+ count
) & (VLFSDIRENTLEN
- 1);
402 DBG_VOP(("volfs_readdir: Not enough buffer to read in entries\n"));
403 DBG_VOP_LOCKS_TEST(EINVAL
);
407 * Make sure we're starting on a directory boundary
409 if (off
& (VLFSDIRENTLEN
- 1))
411 DBG_VOP_LOCKS_TEST(EINVAL
);
414 rec_offset
= off
/ VLFSDIRENTLEN
;
415 lost
= uio
->uio_resid
- count
;
416 uio
->uio_resid
= count
;
417 uio
->uio_iov
->iov_len
= count
;
419 local_dir
.d_reclen
= VLFSDIRENTLEN
;
421 * We must synthesize . and ..
423 DBG_VOP(("\tstarting ... uio_offset = %d, uio_resid = %d\n",
424 (int) uio
->uio_offset
, uio
->uio_resid
));
427 DBG_VOP(("\tAdding .\n"));
431 local_dir
.d_fileno
= priv_data
->nodeID
;
432 local_dir
.d_type
= DT_DIR
;
433 local_dir
.d_namlen
= 1;
434 local_dir
.d_name
[0] = '.';
435 for (i
= 1; i
< MAXVLFSNAMLEN
; i
++)
436 local_dir
.d_name
[i
] = 0;
437 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
438 DBG_VOP(("\t after adding ., uio_offset = %d, uio_resid = %d\n",
439 (int) uio
->uio_offset
, uio
->uio_resid
));
444 DBG_VOP(("\tAdding ..\n"));
447 * We only have two levels in the volfs hierarchy. Root's
448 * .. points to itself and the second level points to root,
449 * hence we've hardcoded d_fileno for .. here
451 local_dir
.d_fileno
= ROOT_DIRID
;
452 local_dir
.d_type
= DT_DIR
;
453 local_dir
.d_namlen
= 2;
454 local_dir
.d_name
[0] = '.';
455 local_dir
.d_name
[1] = '.';
456 for (i
= 2; i
< MAXVLFSNAMLEN
; i
++)
457 local_dir
.d_name
[i
] = 0;
458 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
460 DBG_VOP(("\t after adding .., uio_offset = %d, uio_resid = %d\n",
461 (int) uio
->uio_offset
, uio
->uio_resid
));
465 * OK, we've given them the . & .. entries. If this is a
466 * filesystem node then we've gone as far as we're going
469 if (priv_data
->vnode_type
== VOLFS_FSNODE
)
471 *ap
->a_eofflag
= 1; /* we got all the way to the end */
472 DBG_VOP_LOCKS_TEST(error
);
476 if (rec_offset
> 1) {
477 register struct mount
*mp
, *nmp
;
479 struct proc
*p
= uio
->uio_procp
;
481 validnodeindex
= 1; /* we always have "." and ".." */
483 simple_lock(&mountlist_slock
);
484 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
485 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
486 nmp
= mp
->mnt_list
.cqe_next
;
490 if (mp
!= ap
->a_vp
->v_mount
&& validfsnode(mp
))
493 if (rec_offset
== validnodeindex
)
495 local_dir
.d_fileno
= mp
->mnt_stat
.f_fsid
.val
[0];
496 local_dir
.d_type
= DT_DIR
;
497 local_dir
.d_reclen
= VLFSDIRENTLEN
;
498 DBG_VOP(("\tAdding dir entry %d for offset %d\n", mp
->mnt_stat
.f_fsid
.val
[0], rec_offset
));
499 local_dir
.d_namlen
= sprintf(&local_dir
.d_name
[0], "%d", mp
->mnt_stat
.f_fsid
.val
[0]);
500 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
501 DBG_VOP(("\t after adding entry '%s', uio_offset = %d, uio_resid = %d\n",
502 &local_dir
.d_name
[0], (int) uio
->uio_offset
, uio
->uio_resid
));
506 simple_lock(&mountlist_slock
);
507 nmp
= mp
->mnt_list
.cqe_next
;
510 simple_unlock(&mountlist_slock
);
512 if (mp
== (void *) &mountlist
)
513 *ap
->a_eofflag
= 1; /* we got all the way to the end */
516 uio
->uio_resid
+= lost
;
517 if (starting_resid
== uio
->uio_resid
)
520 DBG_VOP(("\tExiting, uio_offset = %d, uio_resid = %d, ap->a_eofflag = %d\n",
521 (int) uio
->uio_offset
, uio
->uio_resid
, *ap
->a_eofflag
));
523 DBG_VOP_LOCKS_TEST(error
);
529 * validfsnode - test to see if a file system supports VGET
531 * This can cause context switching, so caller should be lock safe
534 validfsnode(struct mount
*fsnode
)
538 * Just check to see if the the mount flag is set, if it is we assume the
539 * file system supports all of volfs symantecs
542 if ((! (fsnode
->mnt_kern_flag
& MNTK_UNMOUNT
)) && (fsnode
->mnt_flag
& MNT_DOVOLFS
))
549 * volfs_lock - Lock an inode.
550 * If its already locked, set the WANT bit and sleep.
552 * Locking policy: handled by lockmgr
556 struct vop_lock_args
/* { struct vnode *a_vp; int a_flags; struct
560 struct volfs_vndata
*priv_data
;
561 DBG_FUNC_NAME("volfs_lock");
562 DBG_VOP_LOCKS_DECL(1);
563 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
565 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_UNLOCKED
, VOPDBG_LOCKED
, VOPDBG_UNLOCKED
, VOPDBG_ZERO
);
567 priv_data
= (struct volfs_vndata
*) ap
->a_vp
->v_data
;
568 retval
= lockmgr(&priv_data
->lock
, ap
->a_flags
, &ap
->a_vp
->v_interlock
, ap
->a_p
);
569 DBG_VOP_LOCKS_TEST(retval
);
574 * volfs_unlock - Unlock an inode.
576 * Locking policy: handled by lockmgr
580 struct vop_unlock_args
/* { struct vnode *a_vp; int a_flags; struct
584 struct volfs_vndata
*priv_data
;
585 DBG_FUNC_NAME("volfs_unlock");
586 DBG_VOP_LOCKS_DECL(1);
587 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
589 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_UNLOCKED
, VOPDBG_LOCKED
, VOPDBG_ZERO
);
591 priv_data
= (struct volfs_vndata
*) ap
->a_vp
->v_data
;
592 retval
= lockmgr(&priv_data
->lock
, ap
->a_flags
| LK_RELEASE
,
593 &ap
->a_vp
->v_interlock
, ap
->a_p
);
595 DBG_VOP_LOCKS_TEST(retval
);
600 * volfs_islocked - Check for a locked inode.
602 * Locking policy: ignore
606 struct vop_islocked_args
/* { struct vnode *a_vp; } */ *ap
;
609 struct volfs_vndata
*priv_data
;
611 DBG_FUNC_NAME("volfs_islocked");
612 DBG_VOP_LOCKS_DECL(1);
613 //DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
615 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_ZERO
);
616 priv_data
= (struct volfs_vndata
*) ap
->a_vp
->v_data
;
617 retval
= lockstatus(&priv_data
->lock
);
619 DBG_VOP_LOCKS_TEST(retval
);
624 * volfs_pathconf - Return POSIX pathconf information applicable to ufs filesystems.
626 * Locking policy: a_vp locked on input and output
630 struct vop_pathconf_args
/* { struct vnode *a_vp; int a_name; int
633 DBG_VOP(("volfs_pathconf called\n"));
638 *ap
->a_retval
= LINK_MAX
;
641 *ap
->a_retval
= NAME_MAX
;
644 *ap
->a_retval
= PATH_MAX
;
647 *ap
->a_retval
= PIPE_BUF
;
649 case _PC_CHOWN_RESTRICTED
:
662 * get_fsvnode - internal routine to create a vnode for a file system. Called with mount pointer,
663 * id of filesystem to lookup and pointer to vnode pointer to fill in
666 get_fsvnode(our_mount
, id
, ret_vnode
)
667 struct mount
*our_mount
;
669 struct vnode
**ret_vnode
;
671 register struct mount
*mp
;
672 struct mount
*cur_mount
;
673 struct vnode
*cur_vnode
;
674 struct volfs_vndata
*cur_privdata
;
677 //DBG_VOP(("volfs: get_fsvnode called\n"));
680 * OK, first look up the matching mount on the list of mounted file systems
683 simple_lock(&mountlist_slock
);
684 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= mp
->mnt_list
.cqe_next
)
686 if (validfsnode(mp
) && mp
->mnt_stat
.f_fsid
.val
[0] == id
)
692 simple_unlock(&mountlist_slock
);
694 if (cur_mount
== NULL
) {
696 * No mounted file system by the specified ID currently exists in the system.
698 * XXX We could deal with a vnode that is still hanging about for an FS that
699 * does not exists or has been unmounted now, or count on the update below
707 * Now search the list attached to the mount structure to
708 * see if this vnode is already floating around
711 cur_vnode
= our_mount
->mnt_vnodelist
.lh_first
;
712 while (cur_vnode
!= NULL
)
714 cur_privdata
= (struct volfs_vndata
*) cur_vnode
->v_data
;
715 if (cur_privdata
->nodeID
== id
)
717 if (cur_privdata
->fs_mount
!= cur_mount
) {
718 DBG_VOP(("volfs get_fsvnode: Updating fs_mount for vnode 0x%08lX (id = %d) from 0x%08lX to 0x%08lX...\n",
719 (unsigned long)cur_vnode
,
720 cur_privdata
->nodeID
,
721 (unsigned long)cur_privdata
->fs_mount
,
722 (unsigned long)cur_mount
));
723 cur_privdata
->fs_mount
= cur_mount
;
727 cur_vnode
= cur_vnode
->v_mntvnodes
.le_next
;
730 //DBG_VOP(("\tfinal cur_mount: 0x%x\n",cur_mount));
732 /* If vget returns an error, cur_vnode will not be what we think it is, try again */
733 if (vget(cur_vnode
, LK_EXCLUSIVE
, current_proc()) != 0) {
734 goto search_vnodelist
;
739 MALLOC(cur_privdata
, struct volfs_vndata
*,
740 sizeof(struct volfs_vndata
), M_VOLFSNODE
, M_WAITOK
);
741 retval
= getnewvnode(VT_VOLFS
, our_mount
, volfs_vnodeop_p
, &cur_vnode
);
743 FREE(cur_privdata
, M_VOLFSNODE
);
747 cur_privdata
->vnode_type
= VOLFS_FSNODE
;
748 cur_privdata
->nodeID
= id
;
750 cur_privdata
->fs_mount
= cur_mount
;
751 lockinit(&cur_privdata
->lock
, PINOD
, "volfsnode", 0, 0);
752 lockmgr(&cur_privdata
->lock
, LK_EXCLUSIVE
, (struct slock
*)0, current_proc());
753 cur_vnode
->v_data
= cur_privdata
;
754 cur_vnode
->v_type
= VDIR
;
755 DBG_VOP(("get_fsvnode returned with new node of "));
756 DBG_VOP_PRINT_VNODE_INFO(cur_vnode
);DBG_VOP(("\n"));
759 *ret_vnode
= cur_vnode
;
767 * get_filevnode - returns the vnode for the given id within a filesystem. The parent vnode
768 * is a filesystem, id is the 32-bit id of the file/directory and ret_vnode is a pointer
772 get_filevnode(parent_fs
, id
, ret_vnode
)
773 struct mount
*parent_fs
;
775 struct vnode
**ret_vnode
;
779 DBG_VOP(("get_filevnode called for ID %d\n", id
));
782 * Special case 2 to mean the root of a file system
785 retval
= VFS_ROOT(parent_fs
, ret_vnode
);
787 retval
= VFS_VGET(parent_fs
, &id
, ret_vnode
);
795 struct vop_lookup_args
/* { struct vnode *a_dvp; struct vnode
796 **a_vpp; struct componentname *a_cnp; } */ *ap
;
798 struct volfs_vndata
*priv_data
;
801 struct mount
*parent_fs
;
802 int unlocked_parent
= 0;
803 int ret_err
= ENOENT
;
804 DBG_FUNC_NAME("volfs_lookup");
805 DBG_VOP_LOCKS_DECL(2);
807 DBG_VOP(("volfs_lookup called, name = %s, namelen = %ld\n", ap
->a_cnp
->cn_nameptr
, ap
->a_cnp
->cn_namelen
));
809 DBG_VOP_LOCKS_INIT(0,ap
->a_dvp
, VOPDBG_LOCKED
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_POS
);
810 DBG_VOP_LOCKS_INIT(1,*ap
->a_vpp
, VOPDBG_IGNORE
, VOPDBG_LOCKED
, VOPDBG_IGNORE
, VOPDBG_POS
);
811 DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
812 DBG_VOP(("\t"));DBG_VOP_PRINT_CPN_INFO(ap
->a_cnp
);DBG_VOP(("\n"));
813 if (ap
->a_cnp
->cn_flags
& LOCKPARENT
)
814 DBG_VOP(("\tLOCKPARENT is set\n"));
815 if (ap
->a_cnp
->cn_flags
& ISLASTCN
)
817 DBG_VOP(("\tISLASTCN is set\n"));
818 if (ap
->a_cnp
->cn_nameiop
== DELETE
|| ap
->a_cnp
->cn_nameiop
== RENAME
) /* XXX PPD Shouldn't we check for CREATE, too? */
824 priv_data
= ap
->a_dvp
->v_data
;
825 cnp
= ap
->a_cnp
->cn_nameptr
;
826 namelen
= ap
->a_cnp
->cn_namelen
;
829 switch (priv_data
->vnode_type
) {
831 DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_ROOT.\n", (unsigned long)ap
->a_dvp
));
835 DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_FSNODE, nodeID = %d, fs_mount = 0x%08lX.\n",
836 (unsigned long)ap
->a_dvp
,
838 (unsigned long)priv_data
->fs_mount
));
841 DBG_VOP(("\tparent directory (vnode 0x%08lX) has unknown vnode_type (%d), nodeID = %d.\n",
842 (unsigned long)ap
->a_dvp
,
843 priv_data
->vnode_type
,
846 #endif /* VOLFS_DEBUG */
848 /* first check for "." and ".." */
854 *ap
->a_vpp
= ap
->a_dvp
;
856 DBG_VOP_LOCKS_TEST(0);
859 else if (cnp
[1] == '.' && namelen
== 2)
862 ret_err
= volfs_root(ap
->a_dvp
->v_mount
, ap
->a_vpp
);
866 /* then look for special file system root symbol ('@') */
867 else if (cnp
[0] == '@')
869 if ((namelen
== 1) && (priv_data
->vnode_type
!= VOLFS_ROOT
)) {
870 parent_fs
= priv_data
->fs_mount
;
871 if (!(ap
->a_cnp
->cn_flags
& LOCKPARENT
) || !(ap
->a_cnp
->cn_flags
& ISLASTCN
)) {
872 VOP_UNLOCK(ap
->a_dvp
, 0, ap
->a_cnp
->cn_proc
);
875 ret_err
= VFS_ROOT(parent_fs
, ap
->a_vpp
);
877 DBG_VOP(("volfs_lookup: pathname = '@' but namelen = %ld and parent vnode_type = %d.\n", namelen
, priv_data
->vnode_type
));
883 /* finally, just look for numeric ids... */
884 else if (namelen
<= 10 && cnp
[0] > '0' && cnp
[0] <= '9') /* 10 digits max lead digit must be 1 - 9 */
889 id
= strtoul(cnp
, &check_ptr
, 10);
892 * strtol will leave us at the first non-numeric character.
893 * we've checked to make sure the component name does
894 * begin with a numeric so check_ptr must wind up on
895 * the terminating null or there was other junk following the
898 if ((check_ptr
- cnp
) == namelen
)
900 if (priv_data
->vnode_type
== VOLFS_ROOT
)
901 ret_err
= get_fsvnode(ap
->a_dvp
->v_mount
, id
, ap
->a_vpp
);
903 parent_fs
= priv_data
->fs_mount
;
904 if (!(ap
->a_cnp
->cn_flags
& LOCKPARENT
) || !(ap
->a_cnp
->cn_flags
& ISLASTCN
)) {
905 VOP_UNLOCK(ap
->a_dvp
, 0, ap
->a_cnp
->cn_proc
);
908 ret_err
= get_filevnode(parent_fs
, id
, ap
->a_vpp
);
914 if (!unlocked_parent
&& (!(ap
->a_cnp
->cn_flags
& LOCKPARENT
) || !(ap
->a_cnp
->cn_flags
& ISLASTCN
))) {
915 VOP_UNLOCK(ap
->a_dvp
, 0, ap
->a_cnp
->cn_proc
);
918 /* XXX PPD Should we do something special in case LOCKLEAF isn't set? */
922 DBG_VOP_UPDATE_VP(1, *ap
->a_vpp
);
923 DBG_VOP_LOCKS_TEST(ret_err
);
928 #if DBG_VOP_TEST_LOCKS
931 static void DbgLookupTest( char *funcname
, struct componentname
*cnp
, struct vnode
*dvp
, struct vnode
*vp
)
933 int flags
= cnp
->cn_flags
;
934 int nameiop
= cnp
->cn_nameiop
;
936 DBG_VOP (("%s: Action:", funcname
));
952 PRINTIT ("!!!UNKNOWN!!!!");
955 PRINTIT(" flags: 0x%x ",flags
);
956 if (flags
& LOCKPARENT
)
957 PRINTIT (" Lock Parent");
958 if (flags
& ISLASTCN
)
959 PRINTIT (" Last Action");
964 PRINTIT ("%s: Parent vnode exited ", funcname
);
965 if (VOP_ISLOCKED(dvp
))
968 PRINTIT("UNLOCKED\n");
972 PRINTIT ("%s: Found and Parent are the same\n", funcname
);
976 PRINTIT ("%s: Found vnode exited ", funcname
);
977 if (VOP_ISLOCKED(vp
))
980 PRINTIT("UNLOCKED\n");
983 PRINTIT ("%s: Found vnode exited NULL\n", funcname
);
989 static void DbgVopTest( int maxSlots
,
991 VopDbgStoreRec
*VopDbgStore
,
996 for (index
= 0; index
< maxSlots
; index
++)
998 if (VopDbgStore
[index
].id
!= index
) {
999 PRINTIT("%s: DBG_VOP_LOCK: invalid id field (%d) in target entry (#%d).\n", funcname
, VopDbgStore
[index
].id
, index
);
1003 if ((VopDbgStore
[index
].vp
!= NULL
) &&
1004 ((VopDbgStore
[index
].vp
->v_data
==NULL
)))
1007 switch (VopDbgStore
[index
].inState
)
1011 /* Do Nothing !!! */
1014 case VOPDBG_UNLOCKED
:
1015 case VOPDBG_LOCKNOTNIL
:
1017 if (VopDbgStore
[index
].vp
== NULL
&& (VopDbgStore
[index
].inState
!= VOPDBG_LOCKNOTNIL
)) {
1018 PRINTIT ("%s: InState check: Null vnode ptr in entry #%d\n", funcname
, index
);
1019 } else if (VopDbgStore
[index
].vp
!= NULL
) {
1020 switch (VopDbgStore
[index
].inState
)
1023 case VOPDBG_LOCKNOTNIL
:
1024 if (VopDbgStore
[index
].inValue
== 0)
1026 PRINTIT ("%s: %d Entry: not LOCKED:", funcname
, index
); DBG_VOP(("\n"));
1029 case VOPDBG_UNLOCKED
:
1030 if (VopDbgStore
[index
].inValue
!= 0)
1032 PRINTIT ("%s: %d Entry: not UNLOCKED:", funcname
, index
); DBG_VOP(("\n"));
1040 PRINTIT ("%s: DBG_VOP_LOCK on entry: bad lock test value: %d\n", funcname
, VopDbgStore
[index
].errState
);
1046 switch (VopDbgStore
[index
].errState
)
1049 /* Do Nothing !!! */
1052 case VOPDBG_UNLOCKED
:
1055 if (VopDbgStore
[index
].vp
== NULL
) {
1056 PRINTIT ("%s: ErrState check: Null vnode ptr in entry #%d\n", funcname
, index
);
1058 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1059 switch (VopDbgStore
[index
].errState
)
1062 if (VopDbgStore
[index
].outValue
== 0)
1064 PRINTIT ("%s: %d Error: not LOCKED:", funcname
, index
); DBG_VOP(("\n"));
1067 case VOPDBG_UNLOCKED
:
1068 if (VopDbgStore
[index
].outValue
!= 0)
1070 PRINTIT ("%s: %d Error: not UNLOCKED:", funcname
, index
); DBG_VOP(("\n"));
1074 if (VopDbgStore
[index
].outValue
!= VopDbgStore
[index
].inValue
)
1075 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
);
1081 case VOPDBG_LOCKNOTNIL
:
1082 if (VopDbgStore
[index
].vp
!= NULL
) {
1083 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1084 if (VopDbgStore
[index
].outValue
== 0)
1085 PRINTIT ("%s: Error: %d Not LOCKED: 0x%x\n", funcname
, index
, (u_int
)VopDbgStore
[index
].vp
);
1089 PRINTIT ("%s: Error: bad lock test value: %d\n", funcname
, VopDbgStore
[index
].errState
);
1094 switch (VopDbgStore
[index
].outState
)
1097 /* Do Nothing !!! */
1100 case VOPDBG_UNLOCKED
:
1102 if (VopDbgStore
[index
].vp
== NULL
) {
1103 PRINTIT ("%s: OutState: Null vnode ptr in entry #%d\n", funcname
, index
);
1105 if (VopDbgStore
[index
].vp
!= NULL
)
1107 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1108 switch (VopDbgStore
[index
].outState
)
1111 if (VopDbgStore
[index
].outValue
== 0)
1113 PRINTIT ("%s: %d Out: not LOCKED:", funcname
, index
); DBG_VOP(("\n"));
1116 case VOPDBG_UNLOCKED
:
1117 if (VopDbgStore
[index
].outValue
!= 0)
1119 PRINTIT ("%s: %d Out: not UNLOCKED:", funcname
, index
); DBG_VOP(("\n"));
1123 if (VopDbgStore
[index
].outValue
!= VopDbgStore
[index
].inValue
)
1124 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
);
1129 case VOPDBG_LOCKNOTNIL
:
1130 if (VopDbgStore
[index
].vp
!= NULL
) {
1131 if (&((struct volfs_vndata
*)(VopDbgStore
[index
].vp
->v_data
))->lock
== NULL
)
1132 PRINTIT ("%s: DBG_VOP_LOCK on out: Null lock on vnode 0x%x\n", funcname
, (u_int
)VopDbgStore
[index
].vp
);
1134 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1135 if (VopDbgStore
[index
].outValue
== 0)
1137 PRINTIT ("%s: DBG_VOP_LOCK on out: Should be LOCKED:", funcname
); DBG_VOP(("\n"));
1143 PRINTIT ("%s: DBG_VOP_LOCK on out: bad lock test value: %d\n", funcname
, VopDbgStore
[index
].outState
);
1147 VopDbgStore
[index
].id
= -1; /* Invalidate the entry to allow panic-free re-use */
1151 #endif /* DBG_VOP_TEST_LOCKS */