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>
50 #include <sys/mount.h>
51 #include <sys/vnode.h>
52 #include <sys/malloc.h>
53 #include <sys/dirent.h>
54 #include <sys/namei.h>
58 #include <sys/errno.h>
59 #include <vfs/vfs_support.h>
64 * volfs acts as a bridge between the requirements of the MacOS API and the Unix API.
65 * MacOS applications describe files by a <Volume ID><Directory ID><File Name> triple.
66 * The Unix API describes files by pathname. Volfs is a virtual file system that sits over
67 * the HFS VFS interface and allows files to be described by a <Volume ID>/<Directory ID>/<File Name>
70 * The root of the volfs filesystem consists of directories named the volume ID's of all the
71 * currently mounted filesystems which support the VFS vget() routine. Each of those directories
72 * supports the lookup by file ID of all files and directories within the filesystem. When a
73 * file or directory is resolved its vnode from that filesystem rather than a volfs vnode is returned
74 * allowing immediate access to the target file or directory.
76 * Readdir on the root of the volfs filesystem returns the list of available file systems. Readdir
77 * on a filesystem node, however, returns only . and .. since it is not practical to list all
78 * of the file ID's in a timely fashion and furthermore VFS does not provide a mechanism for
79 * enumerating all of the file id's.
81 * Volume ID's are taken from the low 32 bits of the f_fsid field, formatted as a base 10 ASCII
82 * string with no leading zeros (volume ID 1 is represented as "1").
84 * File ID's are created in same manner, with their 32 bits formatted as a base 10 ASCII
85 * string with no leading zeros.
87 * Volfs does create a security hole since it is possible to bypass directory permissions higher
88 * in the namespace tree. This security hole is about the same as the one created by NFS which uses
89 * a similar mechanism.
92 #define VOPFUNC int (*)(void *)
94 /* Global vfs data structures for volfs. */
95 int (**volfs_vnodeop_p
) (void *);
96 struct vnodeopv_entry_desc volfs_vnodeop_entries
[] = {
97 {&vop_default_desc
, (VOPFUNC
)vn_default_error
},
98 {&vop_strategy_desc
, (VOPFUNC
)err_strategy
}, /* strategy */
99 {&vop_bwrite_desc
, (VOPFUNC
)err_bwrite
}, /* bwrite */
100 {&vop_lookup_desc
, (VOPFUNC
)volfs_lookup
}, /* lookup */
101 {&vop_create_desc
, (VOPFUNC
)err_create
}, /* create */
102 {&vop_whiteout_desc
, (VOPFUNC
)err_whiteout
}, /* whiteout */
103 {&vop_mknod_desc
, (VOPFUNC
)err_mknod
}, /* mknod */
104 {&vop_mkcomplex_desc
, (VOPFUNC
)err_mkcomplex
}, /* mkcomplex */
105 {&vop_open_desc
, (VOPFUNC
)nop_open
}, /* open */
106 {&vop_close_desc
, (VOPFUNC
)nop_close
}, /* close */
107 {&vop_access_desc
, (VOPFUNC
)volfs_access
}, /* access */
108 {&vop_getattr_desc
, (VOPFUNC
)volfs_getattr
}, /* getattr */
109 {&vop_setattr_desc
, (VOPFUNC
)err_setattr
}, /* setattr */
110 {&vop_getattrlist_desc
, (VOPFUNC
)err_getattrlist
}, /* getattrlist */
111 {&vop_setattrlist_desc
, (VOPFUNC
)err_setattrlist
}, /* setattrlist */
112 {&vop_read_desc
, (VOPFUNC
)err_read
}, /* read */
113 {&vop_write_desc
, (VOPFUNC
)err_write
}, /* write */
114 {&vop_lease_desc
, (VOPFUNC
)err_lease
}, /* lease */
115 {&vop_ioctl_desc
, (VOPFUNC
)err_ioctl
}, /* ioctl */
116 {&vop_select_desc
, (VOPFUNC
)volfs_select
}, /* select */
117 {&vop_exchange_desc
, (VOPFUNC
)err_exchange
}, /* exchange */
118 {&vop_revoke_desc
, (VOPFUNC
)nop_revoke
}, /* revoke */
119 {&vop_mmap_desc
, (VOPFUNC
)err_mmap
}, /* mmap */
120 {&vop_fsync_desc
, (VOPFUNC
)err_fsync
}, /* fsync */
121 {&vop_seek_desc
, (VOPFUNC
)nop_seek
}, /* seek */
122 {&vop_remove_desc
, (VOPFUNC
)err_remove
}, /* remove */
123 {&vop_link_desc
, (VOPFUNC
)err_link
}, /* link */
124 {&vop_rename_desc
, (VOPFUNC
)err_rename
}, /* rename */
125 {&vop_mkdir_desc
, (VOPFUNC
)err_mkdir
}, /* mkdir */
126 {&vop_rmdir_desc
, (VOPFUNC
)volfs_rmdir
}, /* rmdir */
127 {&vop_symlink_desc
, (VOPFUNC
)err_symlink
}, /* symlink */
128 {&vop_readdir_desc
, (VOPFUNC
)volfs_readdir
}, /* readdir */
129 {&vop_readdirattr_desc
, (VOPFUNC
)err_readdirattr
}, /* readdirattr */
130 {&vop_readlink_desc
, (VOPFUNC
)err_readlink
}, /* readlink */
131 {&vop_abortop_desc
, (VOPFUNC
)err_abortop
}, /* abortop */
132 {&vop_inactive_desc
, (VOPFUNC
)err_inactive
}, /* inactive */
133 {&vop_reclaim_desc
, (VOPFUNC
)volfs_reclaim
}, /* reclaim */
134 {&vop_lock_desc
, (VOPFUNC
)volfs_lock
}, /* lock */
135 {&vop_unlock_desc
, (VOPFUNC
)volfs_unlock
}, /* unlock */
136 {&vop_bmap_desc
, (VOPFUNC
)err_bmap
}, /* bmap */
137 {&vop_print_desc
, (VOPFUNC
)err_print
}, /* print */
138 {&vop_islocked_desc
, (VOPFUNC
)volfs_islocked
}, /* islocked */
139 {&vop_pathconf_desc
, (VOPFUNC
)volfs_pathconf
}, /* pathconf */
140 {&vop_advlock_desc
, (VOPFUNC
)err_advlock
}, /* advlock */
141 {&vop_blkatoff_desc
, (VOPFUNC
)err_blkatoff
}, /* blkatoff */
142 {&vop_valloc_desc
, (VOPFUNC
)err_valloc
}, /* valloc */
143 {&vop_reallocblks_desc
, (VOPFUNC
)err_reallocblks
}, /* reallocblks */
144 {&vop_vfree_desc
, (VOPFUNC
)err_vfree
}, /* vfree */
145 {&vop_truncate_desc
, (VOPFUNC
)err_truncate
}, /* truncate */
146 {&vop_allocate_desc
, (VOPFUNC
)err_allocate
}, /* allocate */
147 {&vop_update_desc
, (VOPFUNC
)err_update
}, /* update */
148 {&vop_pgrd_desc
, (VOPFUNC
)err_pgrd
}, /* pgrd */
149 {&vop_pgwr_desc
, (VOPFUNC
)err_pgwr
}, /* pgwr */
150 {&vop_pagein_desc
, (VOPFUNC
)err_pagein
}, /* pagein */
151 {&vop_pageout_desc
, (VOPFUNC
)err_pageout
}, /* pageout */
152 {&vop_devblocksize_desc
, (VOPFUNC
)err_devblocksize
}, /* devblocksize */
153 {&vop_searchfs_desc
, (VOPFUNC
)err_searchfs
}, /* searchfs */
154 {&vop_copyfile_desc
, (VOPFUNC
)err_copyfile
}, /* Copyfile */
155 {&vop_blktooff_desc
, (VOPFUNC
)err_blktooff
}, /* blktooff */
156 {&vop_offtoblk_desc
, (VOPFUNC
)err_offtoblk
}, /* offtoblk */
157 {&vop_cmap_desc
, (VOPFUNC
)err_cmap
}, /* cmap */
158 {(struct vnodeop_desc
*) NULL
, (int (*) ()) NULL
}
162 * Oh what a tangled web we weave. This structure will be used by
163 * bsd/vfs/vfs_conf.c to actually do the initialization of volfs_vnodeop_p
165 struct vnodeopv_desc volfs_vnodeop_opv_desc
=
166 {&volfs_vnodeop_p
, volfs_vnodeop_entries
};
169 static int validfsnode(struct mount
*fsnode
);
171 #if DBG_VOP_TEST_LOCKS
172 static void DbgVopTest (int max
, int error
, VopDbgStoreRec
*VopDbgStore
, char *funcname
);
173 #endif /* DBG_VOP_TEST_LOCKS */
177 * volfs_reclaim - Reclaim a vnode so that it can be used for other purposes.
179 * Locking policy: ignored
183 struct vop_reclaim_args
/* { struct vnode *a_vp; struct proc *a_p; } */ *ap
;
185 struct vnode
*vp
= ap
->a_vp
;
186 void *data
= vp
->v_data
;
188 DBG_FUNC_NAME("volfs_reclaim");
189 DBG_VOP_LOCKS_DECL(1);
190 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
192 DBG_VOP_LOCKS_INIT(0, vp
, VOPDBG_UNLOCKED
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_ZERO
);
195 FREE(data
, M_VOLFSNODE
);
197 DBG_VOP_LOCKS_TEST(0);
202 * volfs_access - same access policy for all vnodes and all users (file/directory vnodes
203 * for the actual file systems are handled by actual file system)
205 * Locking policy: a_vp locked on input and output
209 struct vop_access_args
/* { struct vnode *a_vp; int a_mode; struct
210 ucred *a_cred; struct proc *a_p; } */ *ap
;
213 DBG_FUNC_NAME("volfs_access");
214 DBG_VOP_LOCKS_DECL(1);
215 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
217 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
220 * We don't need to check credentials! FS is read-only for everyone
222 if (ap
->a_mode
== VREAD
|| ap
->a_mode
== VEXEC
)
227 DBG_VOP_LOCKS_TEST(ret_err
);
232 * volfs_getattr - fill in the attributes for this vnode
234 * Locking policy: don't change anything
238 struct vop_getattr_args
/* { struct vnode *a_vp; struct vattr *a_vap;
239 struct ucred *a_cred; struct proc *a_p; } */ *ap
;
241 struct volfs_vndata
*priv_data
;
245 DBG_FUNC_NAME("volfs_getattr");
246 DBG_VOP_LOCKS_DECL(1);
247 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
249 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_SAME
, VOPDBG_SAME
, VOPDBG_SAME
, VOPDBG_POS
);
254 priv_data
= a_vp
->v_data
;
256 a_vap
->va_type
= VDIR
;
257 a_vap
->va_mode
= 0444; /* Yup, hard - coded to read - only */
259 a_vap
->va_uid
= 0; /* Always owned by root */
260 a_vap
->va_gid
= 0; /* Always part of group 0 */
261 a_vap
->va_fsid
= (int) a_vp
->v_mount
->mnt_stat
.f_fsid
.val
[0];
262 a_vap
->va_fileid
= priv_data
->nodeID
;
265 * If it's the root vnode calculate its size based on the number of eligible
268 if (priv_data
->vnode_type
== VOLFS_ROOT
)
270 register struct mount
*mp
, *nmp
;
272 simple_lock(&mountlist_slock
);
273 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
274 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, ap
->a_p
)) {
275 nmp
= mp
->mnt_list
.cqe_next
;
279 if (mp
!= a_vp
->v_mount
&& validfsnode(mp
))
282 simple_lock(&mountlist_slock
);
283 nmp
= mp
->mnt_list
.cqe_next
;
284 vfs_unbusy(mp
, ap
->a_p
);
286 simple_unlock(&mountlist_slock
);
288 DBG_VOP(("found %d file systems that volfs can support\n", numMounts
));
289 a_vap
->va_size
= (numMounts
+ 2) * VLFSDIRENTLEN
;
293 a_vap
->va_size
= 2 * VLFSDIRENTLEN
;
295 DBG_VOP(("va_size = %d, VLFSDIRENTLEN = %ld\n", (int) a_vap
->va_size
, VLFSDIRENTLEN
));
296 a_vap
->va_blocksize
= 512;
298 a_vap
->va_atime
.tv_sec
= boottime
.tv_sec
;
299 a_vap
->va_atime
.tv_nsec
= 0;
301 a_vap
->va_mtime
.tv_sec
= boottime
.tv_sec
;
302 a_vap
->va_mtime
.tv_nsec
= 0;
304 a_vap
->va_ctime
.tv_sec
= boottime
.tv_sec
;
305 a_vap
->va_ctime
.tv_nsec
= 0;
310 a_vap
->va_bytes
= a_vap
->va_size
;
311 a_vap
->va_filerev
= 0;
312 a_vap
->va_vaflags
= 0;
314 DBG_VOP_LOCKS_TEST(0);
319 * volfs_select - just say OK. Only possible op is readdir
321 * Locking policy: ignore
325 struct vop_select_args
/* { struct vnode *a_vp; int a_which; int
326 * a_fflags; struct ucred *a_cred; void * a_wql; struct
329 DBG_VOP(("volfs_select called\n"));
335 * vofls_rmdir - not possible to remove directories in volfs
337 * Locking policy: a_dvp & a_vp - locked on entry, unlocked on exit
341 struct vop_rmdir_args
/* { struct vnode *a_dvp; struct vnode *a_vp;
342 struct componentname *a_cnp; } */ *ap
;
344 DBG_VOP(("volfs_rmdir called\n"));
345 if (ap
->a_dvp
== ap
->a_vp
) {
346 (void) nop_rmdir(ap
);
349 return (err_rmdir(ap
));
353 * volfs_readdir - Get directory entries
355 * Directory listings are only produced for the root volfs node. Filesystems
357 * Filesystems contained within the volfs root are named by the decimal
358 * equivalent of the f_fsid.val[0] from their mount structure (typically
359 * the device id of the volume). The maximum length for a name, then is
362 * Locking policy: a_vp locked on entry and exit
366 struct vop_readdir_args
/* { struct vnode *a_vp; struct uio *a_uio;
367 * struct ucred *a_cred; int *a_eofflag; int
368 *ncookies; u_long **a_cookies; } */ *ap
;
370 struct volfs_vndata
*priv_data
;
371 register struct uio
*uio
= ap
->a_uio
;
375 struct dirent local_dir
;
379 DBG_FUNC_NAME("volfs_readdir");
380 DBG_VOP_LOCKS_DECL(1);
382 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
383 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
385 DBG_VOP(("\tuio_offset = %d, uio_resid = %d\n", (int) uio
->uio_offset
, uio
->uio_resid
));
386 /* We assume it's all one big buffer... */
387 if (uio
->uio_iovcnt
> 1)
388 DBG_VOP(("\tuio->uio_iovcnt = %d?\n", uio
->uio_iovcnt
));
390 off
= uio
->uio_offset
;
391 priv_data
= ap
->a_vp
->v_data
;
392 starting_resid
= uio
->uio_resid
;
393 count
= uio
->uio_resid
;
395 /* Make sure we don't return partial entries. */
396 count
-= (uio
->uio_offset
+ count
) & (VLFSDIRENTLEN
- 1);
399 DBG_VOP(("volfs_readdir: Not enough buffer to read in entries\n"));
400 DBG_VOP_LOCKS_TEST(EINVAL
);
404 * Make sure we're starting on a directory boundary
406 if (off
& (VLFSDIRENTLEN
- 1))
408 DBG_VOP_LOCKS_TEST(EINVAL
);
411 rec_offset
= off
/ VLFSDIRENTLEN
;
412 lost
= uio
->uio_resid
- count
;
413 uio
->uio_resid
= count
;
414 uio
->uio_iov
->iov_len
= count
;
416 local_dir
.d_reclen
= VLFSDIRENTLEN
;
418 * We must synthesize . and ..
420 DBG_VOP(("\tstarting ... uio_offset = %d, uio_resid = %d\n",
421 (int) uio
->uio_offset
, uio
->uio_resid
));
424 DBG_VOP(("\tAdding .\n"));
428 local_dir
.d_fileno
= priv_data
->nodeID
;
429 local_dir
.d_type
= DT_DIR
;
430 local_dir
.d_namlen
= 1;
431 local_dir
.d_name
[0] = '.';
432 for (i
= 1; i
< MAXVLFSNAMLEN
; i
++)
433 local_dir
.d_name
[i
] = 0;
434 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
435 DBG_VOP(("\t after adding ., uio_offset = %d, uio_resid = %d\n",
436 (int) uio
->uio_offset
, uio
->uio_resid
));
441 DBG_VOP(("\tAdding ..\n"));
444 * We only have two levels in the volfs hierarchy. Root's
445 * .. points to itself and the second level points to root,
446 * hence we've hardcoded d_fileno for .. here
448 local_dir
.d_fileno
= ROOT_DIRID
;
449 local_dir
.d_type
= DT_DIR
;
450 local_dir
.d_namlen
= 2;
451 local_dir
.d_name
[0] = '.';
452 local_dir
.d_name
[1] = '.';
453 for (i
= 2; i
< MAXVLFSNAMLEN
; i
++)
454 local_dir
.d_name
[i
] = 0;
455 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
457 DBG_VOP(("\t after adding .., uio_offset = %d, uio_resid = %d\n",
458 (int) uio
->uio_offset
, uio
->uio_resid
));
462 * OK, we've given them the . & .. entries. If this is a
463 * filesystem node then we've gone as far as we're going
466 if (priv_data
->vnode_type
== VOLFS_FSNODE
)
468 *ap
->a_eofflag
= 1; /* we got all the way to the end */
469 DBG_VOP_LOCKS_TEST(error
);
473 if (rec_offset
> 1) {
474 register struct mount
*mp
, *nmp
;
476 struct proc
*p
= uio
->uio_procp
;
478 validnodeindex
= 1; /* we always have "." and ".." */
480 simple_lock(&mountlist_slock
);
481 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
482 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
483 nmp
= mp
->mnt_list
.cqe_next
;
487 if (mp
!= ap
->a_vp
->v_mount
&& validfsnode(mp
))
490 if (rec_offset
== validnodeindex
)
492 local_dir
.d_fileno
= mp
->mnt_stat
.f_fsid
.val
[0];
493 local_dir
.d_type
= DT_DIR
;
494 local_dir
.d_reclen
= VLFSDIRENTLEN
;
495 DBG_VOP(("\tAdding dir entry %d for offset %d\n", mp
->mnt_stat
.f_fsid
.val
[0], rec_offset
));
496 local_dir
.d_namlen
= sprintf(&local_dir
.d_name
[0], "%d", mp
->mnt_stat
.f_fsid
.val
[0]);
497 error
= uiomove((char *) &local_dir
, VLFSDIRENTLEN
, uio
);
498 DBG_VOP(("\t after adding entry '%s', uio_offset = %d, uio_resid = %d\n",
499 &local_dir
.d_name
[0], (int) uio
->uio_offset
, uio
->uio_resid
));
503 simple_lock(&mountlist_slock
);
504 nmp
= mp
->mnt_list
.cqe_next
;
507 simple_unlock(&mountlist_slock
);
509 if (mp
== (void *) &mountlist
)
510 *ap
->a_eofflag
= 1; /* we got all the way to the end */
513 uio
->uio_resid
+= lost
;
514 if (starting_resid
== uio
->uio_resid
)
517 DBG_VOP(("\tExiting, uio_offset = %d, uio_resid = %d, ap->a_eofflag = %d\n",
518 (int) uio
->uio_offset
, uio
->uio_resid
, *ap
->a_eofflag
));
520 DBG_VOP_LOCKS_TEST(error
);
526 * validfsnode - test to see if a file system supports VGET
528 * This can cause context switching, so caller should be lock safe
531 validfsnode(struct mount
*fsnode
)
535 * Just check to see if the the mount flag is set, if it is we assume the
536 * file system supports all of volfs symantecs
539 if ((! (fsnode
->mnt_kern_flag
& MNTK_UNMOUNT
)) && (fsnode
->mnt_flag
& MNT_DOVOLFS
))
546 * volfs_lock - Lock an inode.
547 * If its already locked, set the WANT bit and sleep.
549 * Locking policy: handled by lockmgr
553 struct vop_lock_args
/* { struct vnode *a_vp; int a_flags; struct
557 struct volfs_vndata
*priv_data
;
558 DBG_FUNC_NAME("volfs_lock");
559 DBG_VOP_LOCKS_DECL(1);
560 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
562 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_UNLOCKED
, VOPDBG_LOCKED
, VOPDBG_UNLOCKED
, VOPDBG_ZERO
);
564 priv_data
= (struct volfs_vndata
*) ap
->a_vp
->v_data
;
565 retval
= lockmgr(&priv_data
->lock
, ap
->a_flags
, &ap
->a_vp
->v_interlock
, ap
->a_p
);
566 DBG_VOP_LOCKS_TEST(retval
);
571 * volfs_unlock - Unlock an inode.
573 * Locking policy: handled by lockmgr
577 struct vop_unlock_args
/* { struct vnode *a_vp; int a_flags; struct
581 struct volfs_vndata
*priv_data
;
582 DBG_FUNC_NAME("volfs_unlock");
583 DBG_VOP_LOCKS_DECL(1);
584 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP(("\n"));
586 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_UNLOCKED
, VOPDBG_LOCKED
, VOPDBG_ZERO
);
588 priv_data
= (struct volfs_vndata
*) ap
->a_vp
->v_data
;
589 retval
= lockmgr(&priv_data
->lock
, ap
->a_flags
| LK_RELEASE
,
590 &ap
->a_vp
->v_interlock
, ap
->a_p
);
592 DBG_VOP_LOCKS_TEST(retval
);
597 * volfs_islocked - Check for a locked inode.
599 * Locking policy: ignore
603 struct vop_islocked_args
/* { struct vnode *a_vp; } */ *ap
;
606 struct volfs_vndata
*priv_data
;
608 DBG_FUNC_NAME("volfs_islocked");
609 DBG_VOP_LOCKS_DECL(1);
610 //DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
612 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_ZERO
);
613 priv_data
= (struct volfs_vndata
*) ap
->a_vp
->v_data
;
614 retval
= lockstatus(&priv_data
->lock
);
616 DBG_VOP_LOCKS_TEST(retval
);
621 * volfs_pathconf - Return POSIX pathconf information applicable to ufs filesystems.
623 * Locking policy: a_vp locked on input and output
627 struct vop_pathconf_args
/* { struct vnode *a_vp; int a_name; int
630 DBG_VOP(("volfs_pathconf called\n"));
635 *ap
->a_retval
= LINK_MAX
;
638 *ap
->a_retval
= NAME_MAX
;
641 *ap
->a_retval
= PATH_MAX
;
644 *ap
->a_retval
= PIPE_BUF
;
646 case _PC_CHOWN_RESTRICTED
:
659 * get_fsvnode - internal routine to create a vnode for a file system. Called with mount pointer,
660 * id of filesystem to lookup and pointer to vnode pointer to fill in
663 get_fsvnode(our_mount
, id
, ret_vnode
)
664 struct mount
*our_mount
;
666 struct vnode
**ret_vnode
;
668 register struct mount
*mp
;
669 struct mount
*cur_mount
;
670 struct vnode
*cur_vnode
;
671 struct volfs_vndata
*cur_privdata
;
674 //DBG_VOP(("volfs: get_fsvnode called\n"));
677 * OK, first look up the matching mount on the list of mounted file systems
680 simple_lock(&mountlist_slock
);
681 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= mp
->mnt_list
.cqe_next
)
683 if (validfsnode(mp
) && mp
->mnt_stat
.f_fsid
.val
[0] == id
)
689 simple_unlock(&mountlist_slock
);
691 if (cur_mount
== NULL
) {
693 * No mounted file system by the specified ID currently exists in the system.
695 * XXX We could deal with a vnode that is still hanging about for an FS that
696 * does not exists or has been unmounted now, or count on the update below
704 * Now search the list attached to the mount structure to
705 * see if this vnode is already floating around
708 cur_vnode
= our_mount
->mnt_vnodelist
.lh_first
;
709 while (cur_vnode
!= NULL
)
711 cur_privdata
= (struct volfs_vndata
*) cur_vnode
->v_data
;
712 if (cur_privdata
->nodeID
== id
)
714 if (cur_privdata
->fs_mount
!= cur_mount
) {
715 DBG_VOP(("volfs get_fsvnode: Updating fs_mount for vnode 0x%08lX (id = %d) from 0x%08lX to 0x%08lX...\n",
716 (unsigned long)cur_vnode
,
717 cur_privdata
->nodeID
,
718 (unsigned long)cur_privdata
->fs_mount
,
719 (unsigned long)cur_mount
));
720 cur_privdata
->fs_mount
= cur_mount
;
724 cur_vnode
= cur_vnode
->v_mntvnodes
.le_next
;
727 //DBG_VOP(("\tfinal cur_mount: 0x%x\n",cur_mount));
729 /* If vget returns an error, cur_vnode will not be what we think it is, try again */
730 if (vget(cur_vnode
, LK_EXCLUSIVE
, current_proc()) != 0) {
731 goto search_vnodelist
;
736 MALLOC(cur_privdata
, struct volfs_vndata
*,
737 sizeof(struct volfs_vndata
), M_VOLFSNODE
, M_WAITOK
);
738 retval
= getnewvnode(VT_VOLFS
, our_mount
, volfs_vnodeop_p
, &cur_vnode
);
740 FREE(cur_privdata
, M_VOLFSNODE
);
744 cur_privdata
->vnode_type
= VOLFS_FSNODE
;
745 cur_privdata
->nodeID
= id
;
747 cur_privdata
->fs_mount
= cur_mount
;
748 lockinit(&cur_privdata
->lock
, PINOD
, "volfsnode", 0, 0);
749 lockmgr(&cur_privdata
->lock
, LK_EXCLUSIVE
, (struct slock
*)0, current_proc());
750 cur_vnode
->v_data
= cur_privdata
;
751 cur_vnode
->v_type
= VDIR
;
752 DBG_VOP(("get_fsvnode returned with new node of "));
753 DBG_VOP_PRINT_VNODE_INFO(cur_vnode
);DBG_VOP(("\n"));
756 *ret_vnode
= cur_vnode
;
764 * get_filevnode - returns the vnode for the given id within a filesystem. The parent vnode
765 * is a filesystem, id is the 32-bit id of the file/directory and ret_vnode is a pointer
769 get_filevnode(parent_fs
, id
, ret_vnode
)
770 struct mount
*parent_fs
;
772 struct vnode
**ret_vnode
;
776 DBG_VOP(("get_filevnode called for ID %d\n", id
));
779 * Special case 2 to mean the root of a file system
782 retval
= VFS_ROOT(parent_fs
, ret_vnode
);
784 retval
= VFS_VGET(parent_fs
, &id
, ret_vnode
);
792 struct vop_lookup_args
/* { struct vnode *a_dvp; struct vnode
793 **a_vpp; struct componentname *a_cnp; } */ *ap
;
795 struct volfs_vndata
*priv_data
;
798 struct mount
*parent_fs
;
799 int unlocked_parent
= 0;
800 int ret_err
= ENOENT
;
801 DBG_FUNC_NAME("volfs_lookup");
802 DBG_VOP_LOCKS_DECL(2);
804 DBG_VOP(("volfs_lookup called, name = %s, namelen = %ld\n", ap
->a_cnp
->cn_nameptr
, ap
->a_cnp
->cn_namelen
));
806 DBG_VOP_LOCKS_INIT(0,ap
->a_dvp
, VOPDBG_LOCKED
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_POS
);
807 DBG_VOP_LOCKS_INIT(1,*ap
->a_vpp
, VOPDBG_IGNORE
, VOPDBG_LOCKED
, VOPDBG_IGNORE
, VOPDBG_POS
);
808 DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
809 DBG_VOP(("\t"));DBG_VOP_PRINT_CPN_INFO(ap
->a_cnp
);DBG_VOP(("\n"));
810 if (ap
->a_cnp
->cn_flags
& LOCKPARENT
)
811 DBG_VOP(("\tLOCKPARENT is set\n"));
812 if (ap
->a_cnp
->cn_flags
& ISLASTCN
)
814 DBG_VOP(("\tISLASTCN is set\n"));
815 if (ap
->a_cnp
->cn_nameiop
== DELETE
|| ap
->a_cnp
->cn_nameiop
== RENAME
) /* XXX PPD Shouldn't we check for CREATE, too? */
821 priv_data
= ap
->a_dvp
->v_data
;
822 cnp
= ap
->a_cnp
->cn_nameptr
;
823 namelen
= ap
->a_cnp
->cn_namelen
;
826 switch (priv_data
->vnode_type
) {
828 DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_ROOT.\n", (unsigned long)ap
->a_dvp
));
832 DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_FSNODE, nodeID = %d, fs_mount = 0x%08lX.\n",
833 (unsigned long)ap
->a_dvp
,
835 (unsigned long)priv_data
->fs_mount
));
838 DBG_VOP(("\tparent directory (vnode 0x%08lX) has unknown vnode_type (%d), nodeID = %d.\n",
839 (unsigned long)ap
->a_dvp
,
840 priv_data
->vnode_type
,
843 #endif /* VOLFS_DEBUG */
845 /* first check for "." and ".." */
851 *ap
->a_vpp
= ap
->a_dvp
;
853 DBG_VOP_LOCKS_TEST(0);
856 else if (cnp
[1] == '.' && namelen
== 2)
859 ret_err
= volfs_root(ap
->a_dvp
->v_mount
, ap
->a_vpp
);
863 /* then look for special file system root symbol ('@') */
864 else if (cnp
[0] == '@')
866 if ((namelen
== 1) && (priv_data
->vnode_type
!= VOLFS_ROOT
)) {
867 parent_fs
= priv_data
->fs_mount
;
868 if (!(ap
->a_cnp
->cn_flags
& LOCKPARENT
) || !(ap
->a_cnp
->cn_flags
& ISLASTCN
)) {
869 VOP_UNLOCK(ap
->a_dvp
, 0, ap
->a_cnp
->cn_proc
);
872 ret_err
= VFS_ROOT(parent_fs
, ap
->a_vpp
);
874 DBG_VOP(("volfs_lookup: pathname = '@' but namelen = %ld and parent vnode_type = %d.\n", namelen
, priv_data
->vnode_type
));
880 /* finally, just look for numeric ids... */
881 else if (namelen
<= 10 && cnp
[0] > '0' && cnp
[0] <= '9') /* 10 digits max lead digit must be 1 - 9 */
886 id
= strtoul(cnp
, &check_ptr
, 10);
889 * strtol will leave us at the first non-numeric character.
890 * we've checked to make sure the component name does
891 * begin with a numeric so check_ptr must wind up on
892 * the terminating null or there was other junk following the
895 if ((check_ptr
- cnp
) == namelen
)
897 if (priv_data
->vnode_type
== VOLFS_ROOT
)
898 ret_err
= get_fsvnode(ap
->a_dvp
->v_mount
, id
, ap
->a_vpp
);
900 parent_fs
= priv_data
->fs_mount
;
901 if (!(ap
->a_cnp
->cn_flags
& LOCKPARENT
) || !(ap
->a_cnp
->cn_flags
& ISLASTCN
)) {
902 VOP_UNLOCK(ap
->a_dvp
, 0, ap
->a_cnp
->cn_proc
);
905 ret_err
= get_filevnode(parent_fs
, id
, ap
->a_vpp
);
911 if (!unlocked_parent
&& (!(ap
->a_cnp
->cn_flags
& LOCKPARENT
) || !(ap
->a_cnp
->cn_flags
& ISLASTCN
))) {
912 VOP_UNLOCK(ap
->a_dvp
, 0, ap
->a_cnp
->cn_proc
);
915 /* XXX PPD Should we do something special in case LOCKLEAF isn't set? */
919 DBG_VOP_UPDATE_VP(1, *ap
->a_vpp
);
920 DBG_VOP_LOCKS_TEST(ret_err
);
925 #if DBG_VOP_TEST_LOCKS
928 static void DbgLookupTest( char *funcname
, struct componentname
*cnp
, struct vnode
*dvp
, struct vnode
*vp
)
930 int flags
= cnp
->cn_flags
;
931 int nameiop
= cnp
->cn_nameiop
;
933 DBG_VOP (("%s: Action:", funcname
));
949 PRINTIT ("!!!UNKNOWN!!!!");
952 PRINTIT(" flags: 0x%x ",flags
);
953 if (flags
& LOCKPARENT
)
954 PRINTIT (" Lock Parent");
955 if (flags
& ISLASTCN
)
956 PRINTIT (" Last Action");
961 PRINTIT ("%s: Parent vnode exited ", funcname
);
962 if (VOP_ISLOCKED(dvp
))
965 PRINTIT("UNLOCKED\n");
969 PRINTIT ("%s: Found and Parent are the same\n", funcname
);
973 PRINTIT ("%s: Found vnode exited ", funcname
);
974 if (VOP_ISLOCKED(vp
))
977 PRINTIT("UNLOCKED\n");
980 PRINTIT ("%s: Found vnode exited NULL\n", funcname
);
986 static void DbgVopTest( int maxSlots
,
988 VopDbgStoreRec
*VopDbgStore
,
993 for (index
= 0; index
< maxSlots
; index
++)
995 if (VopDbgStore
[index
].id
!= index
) {
996 PRINTIT("%s: DBG_VOP_LOCK: invalid id field (%d) in target entry (#%d).\n", funcname
, VopDbgStore
[index
].id
, index
);
1000 if ((VopDbgStore
[index
].vp
!= NULL
) &&
1001 ((VopDbgStore
[index
].vp
->v_data
==NULL
)))
1004 switch (VopDbgStore
[index
].inState
)
1008 /* Do Nothing !!! */
1011 case VOPDBG_UNLOCKED
:
1012 case VOPDBG_LOCKNOTNIL
:
1014 if (VopDbgStore
[index
].vp
== NULL
&& (VopDbgStore
[index
].inState
!= VOPDBG_LOCKNOTNIL
)) {
1015 PRINTIT ("%s: InState check: Null vnode ptr in entry #%d\n", funcname
, index
);
1016 } else if (VopDbgStore
[index
].vp
!= NULL
) {
1017 switch (VopDbgStore
[index
].inState
)
1020 case VOPDBG_LOCKNOTNIL
:
1021 if (VopDbgStore
[index
].inValue
== 0)
1023 PRINTIT ("%s: %d Entry: not LOCKED:", funcname
, index
); DBG_VOP(("\n"));
1026 case VOPDBG_UNLOCKED
:
1027 if (VopDbgStore
[index
].inValue
!= 0)
1029 PRINTIT ("%s: %d Entry: not UNLOCKED:", funcname
, index
); DBG_VOP(("\n"));
1037 PRINTIT ("%s: DBG_VOP_LOCK on entry: bad lock test value: %d\n", funcname
, VopDbgStore
[index
].errState
);
1043 switch (VopDbgStore
[index
].errState
)
1046 /* Do Nothing !!! */
1049 case VOPDBG_UNLOCKED
:
1052 if (VopDbgStore
[index
].vp
== NULL
) {
1053 PRINTIT ("%s: ErrState check: Null vnode ptr in entry #%d\n", funcname
, index
);
1055 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1056 switch (VopDbgStore
[index
].errState
)
1059 if (VopDbgStore
[index
].outValue
== 0)
1061 PRINTIT ("%s: %d Error: not LOCKED:", funcname
, index
); DBG_VOP(("\n"));
1064 case VOPDBG_UNLOCKED
:
1065 if (VopDbgStore
[index
].outValue
!= 0)
1067 PRINTIT ("%s: %d Error: not UNLOCKED:", funcname
, index
); DBG_VOP(("\n"));
1071 if (VopDbgStore
[index
].outValue
!= VopDbgStore
[index
].inValue
)
1072 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
);
1078 case VOPDBG_LOCKNOTNIL
:
1079 if (VopDbgStore
[index
].vp
!= NULL
) {
1080 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1081 if (VopDbgStore
[index
].outValue
== 0)
1082 PRINTIT ("%s: Error: %d Not LOCKED: 0x%x\n", funcname
, index
, (u_int
)VopDbgStore
[index
].vp
);
1086 PRINTIT ("%s: Error: bad lock test value: %d\n", funcname
, VopDbgStore
[index
].errState
);
1091 switch (VopDbgStore
[index
].outState
)
1094 /* Do Nothing !!! */
1097 case VOPDBG_UNLOCKED
:
1099 if (VopDbgStore
[index
].vp
== NULL
) {
1100 PRINTIT ("%s: OutState: Null vnode ptr in entry #%d\n", funcname
, index
);
1102 if (VopDbgStore
[index
].vp
!= NULL
)
1104 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1105 switch (VopDbgStore
[index
].outState
)
1108 if (VopDbgStore
[index
].outValue
== 0)
1110 PRINTIT ("%s: %d Out: not LOCKED:", funcname
, index
); DBG_VOP(("\n"));
1113 case VOPDBG_UNLOCKED
:
1114 if (VopDbgStore
[index
].outValue
!= 0)
1116 PRINTIT ("%s: %d Out: not UNLOCKED:", funcname
, index
); DBG_VOP(("\n"));
1120 if (VopDbgStore
[index
].outValue
!= VopDbgStore
[index
].inValue
)
1121 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
);
1126 case VOPDBG_LOCKNOTNIL
:
1127 if (VopDbgStore
[index
].vp
!= NULL
) {
1128 if (&((struct volfs_vndata
*)(VopDbgStore
[index
].vp
->v_data
))->lock
== NULL
)
1129 PRINTIT ("%s: DBG_VOP_LOCK on out: Null lock on vnode 0x%x\n", funcname
, (u_int
)VopDbgStore
[index
].vp
);
1131 VopDbgStore
[index
].outValue
= VOP_ISLOCKED(VopDbgStore
[index
].vp
);
1132 if (VopDbgStore
[index
].outValue
== 0)
1134 PRINTIT ("%s: DBG_VOP_LOCK on out: Should be LOCKED:", funcname
); DBG_VOP(("\n"));
1140 PRINTIT ("%s: DBG_VOP_LOCK on out: bad lock test value: %d\n", funcname
, VopDbgStore
[index
].outState
);
1144 VopDbgStore
[index
].id
= -1; /* Invalidate the entry to allow panic-free re-use */
1148 #endif /* DBG_VOP_TEST_LOCKS */