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