]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/volfs/volfs_vnops.c
xnu-344.21.73.tar.gz
[apple/xnu.git] / bsd / miscfs / volfs / volfs_vnops.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1998-1999 Apple Computer, Inc. All Rights Reserved.
27 *
28 * Modification History:
29 *
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
34 * header includes.
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.
40 */
41
42 #include <mach/mach_types.h>
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/resourcevar.h>
47 #include <sys/kernel.h>
48 #include <sys/file.h>
49 #include <sys/stat.h>
50 #include <sys/buf.h>
51 #include <sys/proc.h>
52 #include <sys/conf.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>
58 #include <sys/attr.h>
59
60 #include <sys/vm.h>
61 #include <sys/errno.h>
62 #include <vfs/vfs_support.h>
63
64 #include "volfs.h"
65
66 /*
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>
71 * pathname.
72 *
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.
78 *
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.
83 *
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").
86 *
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.
89 *
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.
93 */
94
95 #define VOPFUNC int (*)(void *)
96
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}
162 };
163
164 /*
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
167 */
168 struct vnodeopv_desc volfs_vnodeop_opv_desc =
169 {&volfs_vnodeop_p, volfs_vnodeop_entries};
170
171
172 static int validfsnode(struct mount *fsnode);
173
174 #if DBG_VOP_TEST_LOCKS
175 static void DbgVopTest (int max, int error, VopDbgStoreRec *VopDbgStore, char *funcname);
176 #endif /* DBG_VOP_TEST_LOCKS */
177
178
179 /*
180 * volfs_reclaim - Reclaim a vnode so that it can be used for other purposes.
181 *
182 * Locking policy: ignored
183 */
184 int
185 volfs_reclaim(ap)
186 struct vop_reclaim_args /* { struct vnode *a_vp; struct proc *a_p; } */ *ap;
187 {
188 struct vnode *vp = ap->a_vp;
189 void *data = vp->v_data;
190
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"));
194
195 DBG_VOP_LOCKS_INIT(0, vp, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO);
196
197 vp->v_data = NULL;
198 FREE(data, M_VOLFSNODE);
199
200 DBG_VOP_LOCKS_TEST(0);
201 return (0);
202 }
203
204 /*
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)
207 *
208 * Locking policy: a_vp locked on input and output
209 */
210 int
211 volfs_access(ap)
212 struct vop_access_args /* { struct vnode *a_vp; int a_mode; struct
213 ucred *a_cred; struct proc *a_p; } */ *ap;
214 {
215 int ret_err;
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"));
219
220 DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
221
222 /*
223 * We don't need to check credentials! FS is read-only for everyone
224 */
225 if (ap->a_mode == VREAD || ap->a_mode == VEXEC)
226 ret_err = 0;
227 else
228 ret_err = EACCES;
229
230 DBG_VOP_LOCKS_TEST(ret_err);
231 return (ret_err);
232 }
233
234 /*
235 * volfs_getattr - fill in the attributes for this vnode
236 *
237 * Locking policy: don't change anything
238 */
239 int
240 volfs_getattr(ap)
241 struct vop_getattr_args /* { struct vnode *a_vp; struct vattr *a_vap;
242 struct ucred *a_cred; struct proc *a_p; } */ *ap;
243 {
244 struct volfs_vndata *priv_data;
245 struct vnode *a_vp;
246 struct vattr *a_vap;
247 int numMounts = 0;
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"));
251
252 DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS);
253
254 a_vp = ap->a_vp;
255 a_vap = ap->a_vap;
256
257 priv_data = a_vp->v_data;
258
259 a_vap->va_type = VDIR;
260 a_vap->va_mode = 0444; /* Yup, hard - coded to read - only */
261 a_vap->va_nlink = 2;
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;
266
267 /*
268 * If it's the root vnode calculate its size based on the number of eligible
269 * file systems
270 */
271 if (priv_data->vnode_type == VOLFS_ROOT)
272 {
273 register struct mount *mp, *nmp;
274
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;
279 continue;
280 }
281
282 if (mp != a_vp->v_mount && validfsnode(mp))
283 numMounts++;
284
285 simple_lock(&mountlist_slock);
286 nmp = mp->mnt_list.cqe_next;
287 vfs_unbusy(mp, ap->a_p);
288 }
289 simple_unlock(&mountlist_slock);
290
291 DBG_VOP(("found %d file systems that volfs can support\n", numMounts));
292 a_vap->va_size = (numMounts + 2) * VLFSDIRENTLEN;
293 }
294 else
295 {
296 a_vap->va_size = 2 * VLFSDIRENTLEN;
297 }
298 DBG_VOP(("va_size = %d, VLFSDIRENTLEN = %ld\n", (int) a_vap->va_size, VLFSDIRENTLEN));
299 a_vap->va_blocksize = 512;
300
301 a_vap->va_atime.tv_sec = boottime.tv_sec;
302 a_vap->va_atime.tv_nsec = 0;
303
304 a_vap->va_mtime.tv_sec = boottime.tv_sec;
305 a_vap->va_mtime.tv_nsec = 0;
306
307 a_vap->va_ctime.tv_sec = boottime.tv_sec;
308 a_vap->va_ctime.tv_nsec = 0;
309
310 a_vap->va_gen = 0;
311 a_vap->va_flags = 0;
312 a_vap->va_rdev = 0;
313 a_vap->va_bytes = a_vap->va_size;
314 a_vap->va_filerev = 0;
315 a_vap->va_vaflags = 0;
316
317 DBG_VOP_LOCKS_TEST(0);
318 return (0);
319 }
320
321 /*
322 * volfs_select - just say OK. Only possible op is readdir
323 *
324 * Locking policy: ignore
325 */
326 int
327 volfs_select(ap)
328 struct vop_select_args /* { struct vnode *a_vp; int a_which; int
329 * a_fflags; struct ucred *a_cred; void * a_wql; struct
330 proc *a_p; } */ *ap;
331 {
332 DBG_VOP(("volfs_select called\n"));
333
334 return (1);
335 }
336
337 /*
338 * vofls_rmdir - not possible to remove directories in volfs
339 *
340 * Locking policy: a_dvp & a_vp - locked on entry, unlocked on exit
341 */
342 int
343 volfs_rmdir(ap)
344 struct vop_rmdir_args /* { struct vnode *a_dvp; struct vnode *a_vp;
345 struct componentname *a_cnp; } */ *ap;
346 {
347 DBG_VOP(("volfs_rmdir called\n"));
348 if (ap->a_dvp == ap->a_vp) {
349 (void) nop_rmdir(ap);
350 return (EINVAL);
351 } else
352 return (err_rmdir(ap));
353 }
354
355 /*
356 * volfs_readdir - Get directory entries
357 *
358 * Directory listings are only produced for the root volfs node. Filesystems
359 * just return . & ..
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
363 * 10 characters.
364 *
365 * Locking policy: a_vp locked on entry and exit
366 */
367 int
368 volfs_readdir(ap)
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;
372 {
373 struct volfs_vndata *priv_data;
374 register struct uio *uio = ap->a_uio;
375 int error = 0;
376 size_t count, lost;
377 int rec_offset;
378 struct dirent local_dir;
379 int i;
380 int starting_resid;
381 off_t off;
382 DBG_FUNC_NAME("volfs_readdir");
383 DBG_VOP_LOCKS_DECL(1);
384
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"));
387
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));
392
393 off = uio->uio_offset;
394 priv_data = ap->a_vp->v_data;
395 starting_resid = uio->uio_resid;
396 count = uio->uio_resid;
397
398 /* Make sure we don't return partial entries. */
399 count -= (uio->uio_offset + count) & (VLFSDIRENTLEN - 1);
400 if (count <= 0)
401 {
402 DBG_VOP(("volfs_readdir: Not enough buffer to read in entries\n"));
403 DBG_VOP_LOCKS_TEST(EINVAL);
404 return (EINVAL);
405 }
406 /*
407 * Make sure we're starting on a directory boundary
408 */
409 if (off & (VLFSDIRENTLEN - 1))
410 {
411 DBG_VOP_LOCKS_TEST(EINVAL);
412 return (EINVAL);
413 }
414 rec_offset = off / VLFSDIRENTLEN;
415 lost = uio->uio_resid - count;
416 uio->uio_resid = count;
417 uio->uio_iov->iov_len = count;
418
419 local_dir.d_reclen = VLFSDIRENTLEN;
420 /*
421 * We must synthesize . and ..
422 */
423 DBG_VOP(("\tstarting ... uio_offset = %d, uio_resid = %d\n",
424 (int) uio->uio_offset, uio->uio_resid));
425 if (rec_offset == 0)
426 {
427 DBG_VOP(("\tAdding .\n"));
428 /*
429 * Synthesize .
430 */
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));
440 rec_offset++;
441 }
442 if (rec_offset == 1)
443 {
444 DBG_VOP(("\tAdding ..\n"));
445 /*
446 * Synthesize ..
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
450 */
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);
459 rec_offset++;
460 DBG_VOP(("\t after adding .., uio_offset = %d, uio_resid = %d\n",
461 (int) uio->uio_offset, uio->uio_resid));
462 }
463
464 /*
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
467 * to go
468 */
469 if (priv_data->vnode_type == VOLFS_FSNODE)
470 {
471 *ap->a_eofflag = 1; /* we got all the way to the end */
472 DBG_VOP_LOCKS_TEST(error);
473 return (error);
474 }
475
476 if (rec_offset > 1) {
477 register struct mount *mp, *nmp;
478 int validnodeindex;
479 struct proc *p = uio->uio_procp;
480
481 validnodeindex = 1; /* we always have "." and ".." */
482
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;
487 continue;
488 }
489
490 if (mp != ap->a_vp->v_mount && validfsnode(mp))
491 validnodeindex++;
492
493 if (rec_offset == validnodeindex)
494 {
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));
503 rec_offset++;
504 }
505
506 simple_lock(&mountlist_slock);
507 nmp = mp->mnt_list.cqe_next;
508 vfs_unbusy(mp, p);
509 }
510 simple_unlock(&mountlist_slock);
511
512 if (mp == (void *) &mountlist)
513 *ap->a_eofflag = 1; /* we got all the way to the end */
514 }
515
516 uio->uio_resid += lost;
517 if (starting_resid == uio->uio_resid)
518 uio->uio_offset = 0;
519
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));
522
523 DBG_VOP_LOCKS_TEST(error);
524 return (error);
525 }
526
527
528 /*
529 * validfsnode - test to see if a file system supports VGET
530 *
531 * This can cause context switching, so caller should be lock safe
532 */
533 static int
534 validfsnode(struct mount *fsnode)
535 {
536
537 /*
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
540 */
541
542 if ((! (fsnode->mnt_kern_flag & MNTK_UNMOUNT)) && (fsnode->mnt_flag & MNT_DOVOLFS))
543 return 1;
544 else
545 return 0;
546 }
547
548 /*
549 * volfs_lock - Lock an inode.
550 * If its already locked, set the WANT bit and sleep.
551 *
552 * Locking policy: handled by lockmgr
553 */
554 int
555 volfs_lock(ap)
556 struct vop_lock_args /* { struct vnode *a_vp; int a_flags; struct
557 proc *a_p; } */ *ap;
558 {
559 int retval;
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"));
564
565 DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_ZERO);
566
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);
570 return (retval);
571 }
572
573 /*
574 * volfs_unlock - Unlock an inode.
575 *
576 * Locking policy: handled by lockmgr
577 */
578 int
579 volfs_unlock(ap)
580 struct vop_unlock_args /* { struct vnode *a_vp; int a_flags; struct
581 proc *a_p; } */ *ap;
582 {
583 int retval;
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"));
588
589 DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_ZERO);
590
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);
594
595 DBG_VOP_LOCKS_TEST(retval);
596 return (retval);
597 }
598
599 /*
600 * volfs_islocked - Check for a locked inode.
601 *
602 * Locking policy: ignore
603 */
604 int
605 volfs_islocked(ap)
606 struct vop_islocked_args /* { struct vnode *a_vp; } */ *ap;
607 {
608 int retval;
609 struct volfs_vndata *priv_data;
610
611 DBG_FUNC_NAME("volfs_islocked");
612 DBG_VOP_LOCKS_DECL(1);
613 //DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
614
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);
618
619 DBG_VOP_LOCKS_TEST(retval);
620 return (retval);
621 }
622
623 /*
624 * volfs_pathconf - Return POSIX pathconf information applicable to ufs filesystems.
625 *
626 * Locking policy: a_vp locked on input and output
627 */
628 int
629 volfs_pathconf(ap)
630 struct vop_pathconf_args /* { struct vnode *a_vp; int a_name; int
631 *a_retval; } */ *ap;
632 {
633 DBG_VOP(("volfs_pathconf called\n"));
634
635 switch (ap->a_name)
636 {
637 case _PC_LINK_MAX:
638 *ap->a_retval = LINK_MAX;
639 return (0);
640 case _PC_NAME_MAX:
641 *ap->a_retval = NAME_MAX;
642 return (0);
643 case _PC_PATH_MAX:
644 *ap->a_retval = PATH_MAX;
645 return (0);
646 case _PC_PIPE_BUF:
647 *ap->a_retval = PIPE_BUF;
648 return (0);
649 case _PC_CHOWN_RESTRICTED:
650 *ap->a_retval = 1;
651 return (0);
652 case _PC_NO_TRUNC:
653 *ap->a_retval = 1;
654 return (0);
655 default:
656 return (EINVAL);
657 }
658 /* NOTREACHED */
659 }
660
661 /*
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
664 */
665 static int
666 get_fsvnode(our_mount, id, ret_vnode)
667 struct mount *our_mount;
668 int id;
669 struct vnode **ret_vnode;
670 {
671 register struct mount *mp;
672 struct mount *cur_mount;
673 struct vnode *cur_vnode;
674 struct volfs_vndata *cur_privdata;
675 int retval;
676
677 //DBG_VOP(("volfs: get_fsvnode called\n"));
678
679 /*
680 * OK, first look up the matching mount on the list of mounted file systems
681 */
682 cur_mount = NULL;
683 simple_lock(&mountlist_slock);
684 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = mp->mnt_list.cqe_next)
685 {
686 if (validfsnode(mp) && mp->mnt_stat.f_fsid.val[0] == id)
687 {
688 cur_mount = mp;
689 break;
690 }
691 }
692 simple_unlock(&mountlist_slock);
693
694 if (cur_mount == NULL) {
695 /*
696 * No mounted file system by the specified ID currently exists in the system.
697 *
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
700 * to happen later...
701 */
702 *ret_vnode = NULL;
703 return ENOENT;
704 };
705
706 /*
707 * Now search the list attached to the mount structure to
708 * see if this vnode is already floating around
709 */
710 search_vnodelist:
711 cur_vnode = our_mount->mnt_vnodelist.lh_first;
712 while (cur_vnode != NULL)
713 {
714 cur_privdata = (struct volfs_vndata *) cur_vnode->v_data;
715 if (cur_privdata->nodeID == id)
716 {
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;
724 };
725 break;
726 }
727 cur_vnode = cur_vnode->v_mntvnodes.le_next;
728 }
729
730 //DBG_VOP(("\tfinal cur_mount: 0x%x\n",cur_mount));
731 if (cur_vnode) {
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;
735 };
736 }
737 else
738 {
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);
742 if (retval != 0) {
743 FREE(cur_privdata, M_VOLFSNODE);
744 return retval;
745 };
746
747 cur_privdata->vnode_type = VOLFS_FSNODE;
748 cur_privdata->nodeID = id;
749
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"));
757 }
758
759 *ret_vnode = cur_vnode;
760
761 return (0);
762 }
763
764
765
766 /*
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
769 * to a vnode pointer
770 */
771 static int
772 get_filevnode(parent_fs, id, ret_vnode)
773 struct mount *parent_fs;
774 u_int id;
775 struct vnode **ret_vnode;
776 {
777 int retval;
778
779 DBG_VOP(("get_filevnode called for ID %d\n", id));
780
781 /*
782 * Special case 2 to mean the root of a file system
783 */
784 if (id == 2)
785 retval = VFS_ROOT(parent_fs, ret_vnode);
786 else
787 retval = VFS_VGET(parent_fs, &id, ret_vnode);
788
789 return (retval);
790 }
791
792
793 int
794 volfs_lookup(ap)
795 struct vop_lookup_args /* { struct vnode *a_dvp; struct vnode
796 **a_vpp; struct componentname *a_cnp; } */ *ap;
797 {
798 struct volfs_vndata *priv_data;
799 char *cnp;
800 long namelen;
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);
806
807 DBG_VOP(("volfs_lookup called, name = %s, namelen = %ld\n", ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
808
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)
816 {
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? */
819 {
820 ret_err = EROFS;
821 goto Err_Exit;
822 }
823 }
824 priv_data = ap->a_dvp->v_data;
825 cnp = ap->a_cnp->cn_nameptr;
826 namelen = ap->a_cnp->cn_namelen;
827
828 #if VOLFS_DEBUG
829 switch (priv_data->vnode_type) {
830 case VOLFS_ROOT:
831 DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_ROOT.\n", (unsigned long)ap->a_dvp));
832 break;
833
834 case VOLFS_FSNODE:
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,
837 priv_data->nodeID,
838 (unsigned long)priv_data->fs_mount));
839
840 default:
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,
844 priv_data->nodeID));
845 };
846 #endif /* VOLFS_DEBUG */
847
848 /* first check for "." and ".." */
849 if (cnp[0] == '.')
850 {
851 if (namelen == 1)
852 {
853 /* "." requested */
854 *ap->a_vpp = ap->a_dvp;
855 VREF(*ap->a_vpp);
856 DBG_VOP_LOCKS_TEST(0);
857 return (0);
858 }
859 else if (cnp[1] == '.' && namelen == 2)
860 {
861 /* ".." requested */
862 ret_err = volfs_root(ap->a_dvp->v_mount, ap->a_vpp);
863 }
864 }
865
866 /* then look for special file system root symbol ('@') */
867 else if (cnp[0] == '@')
868 {
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);
873 unlocked_parent = 1;
874 };
875 ret_err = VFS_ROOT(parent_fs, ap->a_vpp);
876 } else {
877 DBG_VOP(("volfs_lookup: pathname = '@' but namelen = %ld and parent vnode_type = %d.\n", namelen, priv_data->vnode_type));
878 *ap->a_vpp = NULL;
879 ret_err = ENOENT;
880 };
881 }
882
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 */
885 {
886 char *check_ptr;
887 u_long id;
888
889 id = strtoul(cnp, &check_ptr, 10);
890
891 /*
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
896 * number
897 */
898 if ((check_ptr - cnp) == namelen)
899 {
900 if (priv_data->vnode_type == VOLFS_ROOT)
901 ret_err = get_fsvnode(ap->a_dvp->v_mount, id, ap->a_vpp);
902 else {
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);
906 unlocked_parent = 1;
907 };
908 ret_err = get_filevnode(parent_fs, id, ap->a_vpp);
909 }
910 }
911
912 }
913
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);
916 };
917
918 /* XXX PPD Should we do something special in case LOCKLEAF isn't set? */
919
920 Err_Exit:
921
922 DBG_VOP_UPDATE_VP(1, *ap->a_vpp);
923 DBG_VOP_LOCKS_TEST(ret_err);
924
925 return (ret_err);
926 }
927
928 #if DBG_VOP_TEST_LOCKS
929
930 #if 0
931 static void DbgLookupTest( char *funcname, struct componentname *cnp, struct vnode *dvp, struct vnode *vp)
932 {
933 int flags = cnp->cn_flags;
934 int nameiop = cnp->cn_nameiop;
935
936 DBG_VOP (("%s: Action:", funcname));
937 switch (nameiop)
938 {
939 case LOOKUP:
940 PRINTIT ("LOOKUP");
941 break;
942 case CREATE:
943 PRINTIT ("CREATE");
944 break;
945 case DELETE:
946 PRINTIT ("DELETE");
947 break;
948 case RENAME:
949 PRINTIT ("RENAME");
950 break;
951 default:
952 PRINTIT ("!!!UNKNOWN!!!!");
953 break;
954 }
955 PRINTIT(" flags: 0x%x ",flags );
956 if (flags & LOCKPARENT)
957 PRINTIT (" Lock Parent");
958 if (flags & ISLASTCN)
959 PRINTIT (" Last Action");
960 PRINTIT("\n");
961
962 if (dvp)
963 {
964 PRINTIT ("%s: Parent vnode exited ", funcname);
965 if (VOP_ISLOCKED(dvp))
966 PRINTIT("LOCKED\n");
967 else
968 PRINTIT("UNLOCKED\n");
969 }
970 if (vp && vp==dvp)
971 {
972 PRINTIT ("%s: Found and Parent are the same\n", funcname);
973 }
974 else if (vp)
975 {
976 PRINTIT ("%s: Found vnode exited ", funcname);
977 if (VOP_ISLOCKED(vp))
978 PRINTIT("LOCKED\n");
979 else
980 PRINTIT("UNLOCKED\n");
981 }
982 else
983 PRINTIT ("%s: Found vnode exited NULL\n", funcname);
984
985
986 }
987 #endif
988
989 static void DbgVopTest( int maxSlots,
990 int retval,
991 VopDbgStoreRec *VopDbgStore,
992 char *funcname)
993 {
994 int index;
995
996 for (index = 0; index < maxSlots; index++)
997 {
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);
1000 return;
1001 };
1002
1003 if ((VopDbgStore[index].vp != NULL) &&
1004 ((VopDbgStore[index].vp->v_data==NULL)))
1005 continue;
1006
1007 switch (VopDbgStore[index].inState)
1008 {
1009 case VOPDBG_IGNORE:
1010 case VOPDBG_SAME:
1011 /* Do Nothing !!! */
1012 break;
1013 case VOPDBG_LOCKED:
1014 case VOPDBG_UNLOCKED:
1015 case VOPDBG_LOCKNOTNIL:
1016 {
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)
1021 {
1022 case VOPDBG_LOCKED:
1023 case VOPDBG_LOCKNOTNIL:
1024 if (VopDbgStore[index].inValue == 0)
1025 {
1026 PRINTIT ("%s: %d Entry: not LOCKED:", funcname, index); DBG_VOP(("\n"));
1027 }
1028 break;
1029 case VOPDBG_UNLOCKED:
1030 if (VopDbgStore[index].inValue != 0)
1031 {
1032 PRINTIT ("%s: %d Entry: not UNLOCKED:", funcname, index); DBG_VOP(("\n"));
1033 }
1034 break;
1035 }
1036 }
1037 break;
1038 }
1039 default:
1040 PRINTIT ("%s: DBG_VOP_LOCK on entry: bad lock test value: %d\n", funcname, VopDbgStore[index].errState);
1041 }
1042
1043
1044 if (retval != 0)
1045 {
1046 switch (VopDbgStore[index].errState)
1047 {
1048 case VOPDBG_IGNORE:
1049 /* Do Nothing !!! */
1050 break;
1051 case VOPDBG_LOCKED:
1052 case VOPDBG_UNLOCKED:
1053 case VOPDBG_SAME:
1054 {
1055 if (VopDbgStore[index].vp == NULL) {
1056 PRINTIT ("%s: ErrState check: Null vnode ptr in entry #%d\n", funcname, index);
1057 } else {
1058 VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
1059 switch (VopDbgStore[index].errState)
1060 {
1061 case VOPDBG_LOCKED:
1062 if (VopDbgStore[index].outValue == 0)
1063 {
1064 PRINTIT ("%s: %d Error: not LOCKED:", funcname, index); DBG_VOP(("\n"));
1065 }
1066 break;
1067 case VOPDBG_UNLOCKED:
1068 if (VopDbgStore[index].outValue != 0)
1069 {
1070 PRINTIT ("%s: %d Error: not UNLOCKED:", funcname, index); DBG_VOP(("\n"));
1071 }
1072 break;
1073 case VOPDBG_SAME:
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);
1076 break;
1077 }
1078 }
1079 break;
1080 }
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);
1086 }
1087 break;
1088 default:
1089 PRINTIT ("%s: Error: bad lock test value: %d\n", funcname, VopDbgStore[index].errState);
1090 }
1091 }
1092 else
1093 {
1094 switch (VopDbgStore[index].outState)
1095 {
1096 case VOPDBG_IGNORE:
1097 /* Do Nothing !!! */
1098 break;
1099 case VOPDBG_LOCKED:
1100 case VOPDBG_UNLOCKED:
1101 case VOPDBG_SAME:
1102 if (VopDbgStore[index].vp == NULL) {
1103 PRINTIT ("%s: OutState: Null vnode ptr in entry #%d\n", funcname, index);
1104 };
1105 if (VopDbgStore[index].vp != NULL)
1106 {
1107 VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
1108 switch (VopDbgStore[index].outState)
1109 {
1110 case VOPDBG_LOCKED:
1111 if (VopDbgStore[index].outValue == 0)
1112 {
1113 PRINTIT ("%s: %d Out: not LOCKED:", funcname, index); DBG_VOP(("\n"));
1114 }
1115 break;
1116 case VOPDBG_UNLOCKED:
1117 if (VopDbgStore[index].outValue != 0)
1118 {
1119 PRINTIT ("%s: %d Out: not UNLOCKED:", funcname, index); DBG_VOP(("\n"));
1120 }
1121 break;
1122 case VOPDBG_SAME:
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);
1125 break;
1126 }
1127 }
1128 break;
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);
1133 else {
1134 VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
1135 if (VopDbgStore[index].outValue == 0)
1136 {
1137 PRINTIT ("%s: DBG_VOP_LOCK on out: Should be LOCKED:", funcname); DBG_VOP(("\n"));
1138 }
1139 }
1140 }
1141 break;
1142 default:
1143 PRINTIT ("%s: DBG_VOP_LOCK on out: bad lock test value: %d\n", funcname, VopDbgStore[index].outState);
1144 }
1145 }
1146
1147 VopDbgStore[index].id = -1; /* Invalidate the entry to allow panic-free re-use */
1148 }
1149 }
1150
1151 #endif /* DBG_VOP_TEST_LOCKS */
1152