]> git.saurik.com Git - apple/xnu.git/blame - bsd/miscfs/volfs/volfs_vnops.c
xnu-517.12.7.tar.gz
[apple/xnu.git] / bsd / miscfs / volfs / volfs_vnops.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
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.
1c79356b 11 *
e5568f75
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
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.
1c79356b
A
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>
55e303ae 46#include <sys/filedesc.h>
1c79356b
A
47#include <sys/stat.h>
48#include <sys/buf.h>
49#include <sys/proc.h>
50#include <sys/conf.h>
51#include <sys/mount.h>
52#include <sys/vnode.h>
53#include <sys/malloc.h>
54#include <sys/dirent.h>
55#include <sys/namei.h>
56#include <sys/attr.h>
55e303ae
A
57#include <sys/kdebug.h>
58#include <sys/queue.h>
1c79356b
A
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. */
98int (**volfs_vnodeop_p) (void *);
99struct 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 */
168struct vnodeopv_desc volfs_vnodeop_opv_desc =
169{&volfs_vnodeop_p, volfs_vnodeop_entries};
170
55e303ae
A
171static char gDot[] = ".";
172static char gDotDot[] = "..";
173
174struct finfo {
175 fsobj_id_t parID;
176};
177
178struct finfoattrbuf {
179 unsigned long length;
180 struct finfo fi;
181};
1c79356b
A
182
183static int validfsnode(struct mount *fsnode);
184
55e303ae
A
185struct volfs_PLCEntry
186{
187 LIST_ENTRY(volfs_PLCEntry) vplc_hash_link; /* entry's hash chain */
188 TAILQ_ENTRY(volfs_PLCEntry) vplc_lru_link; /* entry's LRU chain link */
189 int32_t vplc_fsid;
190 u_int vplc_item_id;
191 uid_t vplc_uid;
192 pid_t vplc_pid;
193};
194
195#define VOLFSPLCHASH(fsid, inum) ((((unsigned long)fsid) + (unsigned long)(inum)) & volfs_PLCHashMask)
196
197static struct slock volfs_PLChashtable_slock;
198static TAILQ_HEAD(volfs_PLCLRUListHead, volfs_PLCEntry) volfs_PLCLRUList;
199static TAILQ_HEAD(volfs_PLCFreeListHead, volfs_PLCEntry) volfs_PLCFreeList;
200static LIST_HEAD(, volfs_PLCEntry) *volfs_PLCHashTable;
201static u_long volfs_PLCHashMask; /* size of hash table - 1 */
202static u_long volfs_PLCEntryCount;
203
1c79356b
A
204#if DBG_VOP_TEST_LOCKS
205static void DbgVopTest (int max, int error, VopDbgStoreRec *VopDbgStore, char *funcname);
206#endif /* DBG_VOP_TEST_LOCKS */
207
208
55e303ae
A
209/*
210 * volfs_PLChashinit
211 */
212__private_extern__ void
213volfs_PLChashinit(void)
214{
215 int i;
216
217 TAILQ_INIT(&volfs_PLCLRUList);
218 TAILQ_INIT(&volfs_PLCFreeList);
219 simple_lock_init(&volfs_PLChashtable_slock);
220#if MAXPLCENTRIES
221 volfs_PLCHashTable = hashinit(PLCHASHSIZE, M_TEMP, &volfs_PLCHashMask);
222
223 for (i = 0; i < PLCHASHSIZE; ++i) {
224 LIST_INIT(&volfs_PLCHashTable[i]);
225 };
226#endif
227 volfs_PLCEntryCount = 0;
228}
229
230
231
232__private_extern__ void
233volfs_PLC_reclaim_entries(int entrycount)
234{
235#if MAXPLCENTRIES
236 int i;
237 struct volfs_PLCEntry *reclaim_target;
238
239 simple_lock(&volfs_PLChashtable_slock);
240
241 for (i = entrycount; i > 0; --i) {
242 if (TAILQ_EMPTY(&volfs_PLCLRUList)) break;
243
244 /* Pick the next entry to be recycled and free it: */
245 reclaim_target = TAILQ_FIRST(&volfs_PLCLRUList);
246 TAILQ_REMOVE(&volfs_PLCLRUList, reclaim_target, vplc_lru_link);
247 LIST_REMOVE(reclaim_target, vplc_hash_link);
248 TAILQ_INSERT_TAIL(&volfs_PLCFreeList, reclaim_target, vplc_lru_link);
249 };
250
251 simple_unlock(&volfs_PLChashtable_slock);
252#endif
253}
254
255
256
257#if MAXPLCENTRIES
258/*
259 * volfs_PLCLookup
260 *
261 * Look up a PLC entry in the hash
262 */
263static int
264volfs_PLCLookup(int32_t fsid, u_int target_id, uid_t uid, pid_t pid)
265{
266 struct volfs_PLCEntry *hash_entry;
267 int result = 0;
268
269 simple_lock(&volfs_PLChashtable_slock);
270 LIST_FOREACH(hash_entry, &volfs_PLCHashTable[VOLFSPLCHASH(fsid, target_id)], vplc_hash_link) {
271 if ((hash_entry->vplc_item_id == target_id) &&
272 (hash_entry->vplc_pid == pid) &&
273 (hash_entry->vplc_uid == uid) &&
274 (hash_entry->vplc_fsid == fsid)) {
275 result = 1;
276#if 0
277 if (hash_entry != TAILQ_LAST(&volfs_PLCLRUList, volfs_PLCLRUListHead)) {
278 TAILQ_REMOVE(&volfs_PLCLRUList, hash_entry, vplc_lru_link);
279 TAILQ_INSERT_TAIL(&volfs_PLCLRUList, hash_entry, vplc_lru_link);
280 };
281#endif
282 break;
283 };
284 };
285 simple_unlock(&volfs_PLChashtable_slock);
286 return result;
287}
288
289
290static void
291volfs_PLCEnter(int32_t fsid, u_int target_id, uid_t uid, pid_t pid)
292{
293 struct volfs_PLCEntry *new_entry;
294
295 simple_lock(&volfs_PLChashtable_slock);
296 if (!TAILQ_EMPTY(&volfs_PLCFreeList)) {
297 new_entry = TAILQ_FIRST(&volfs_PLCFreeList);
298 TAILQ_REMOVE(&volfs_PLCFreeList, new_entry, vplc_lru_link);
299 } else {
300 /*
301 * Allocate up to the predetermined maximum number of new entries:
302 * [must be done now to avoid blocking in MALLOC() with volfs_PLChashtable_slock held locked]
303 */
304 if (volfs_PLCEntryCount < MAXPLCENTRIES) {
305 simple_unlock(&volfs_PLChashtable_slock);
306 new_entry = MALLOC(new_entry, struct volfs_PLCEntry *, sizeof(struct volfs_PLCEntry), M_TEMP, M_WAITOK);
307 simple_lock(&volfs_PLChashtable_slock);
308 ++volfs_PLCEntryCount;
309 } else {
310 new_entry = TAILQ_FIRST(&volfs_PLCLRUList);
311 TAILQ_REMOVE(&volfs_PLCLRUList, new_entry, vplc_lru_link);
312 LIST_REMOVE(new_entry, vplc_hash_link);
313 };
314 };
315
316 new_entry->vplc_fsid = fsid;
317 new_entry->vplc_item_id = target_id;
318 new_entry->vplc_uid = uid;
319 new_entry->vplc_pid = pid;
320
321 /* Link the new entry on the hash list for the fsid/target_id as well as the tail of the LRU list: */
322 LIST_INSERT_HEAD(&volfs_PLCHashTable[VOLFSPLCHASH(fsid, target_id)], new_entry, vplc_hash_link);
323 TAILQ_INSERT_TAIL(&volfs_PLCLRUList, new_entry, vplc_lru_link);
324 simple_unlock(&volfs_PLChashtable_slock);
325}
326#endif
327
328
1c79356b
A
329/*
330 * volfs_reclaim - Reclaim a vnode so that it can be used for other purposes.
331 *
332 * Locking policy: ignored
333 */
334int
335volfs_reclaim(ap)
336 struct vop_reclaim_args /* { struct vnode *a_vp; struct proc *a_p; } */ *ap;
337{
338 struct vnode *vp = ap->a_vp;
339 void *data = vp->v_data;
340
341 DBG_FUNC_NAME("volfs_reclaim");
342 DBG_VOP_LOCKS_DECL(1);
343 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
344
345 DBG_VOP_LOCKS_INIT(0, vp, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO);
346
347 vp->v_data = NULL;
348 FREE(data, M_VOLFSNODE);
349
350 DBG_VOP_LOCKS_TEST(0);
351 return (0);
352}
353
354/*
355 * volfs_access - same access policy for all vnodes and all users (file/directory vnodes
356 * for the actual file systems are handled by actual file system)
357 *
358 * Locking policy: a_vp locked on input and output
359 */
360int
361volfs_access(ap)
362 struct vop_access_args /* { struct vnode *a_vp; int a_mode; struct
363 ucred *a_cred; struct proc *a_p; } */ *ap;
364{
365 int ret_err;
366 DBG_FUNC_NAME("volfs_access");
367 DBG_VOP_LOCKS_DECL(1);
368 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
369
370 DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
371
372 /*
373 * We don't need to check credentials! FS is read-only for everyone
374 */
55e303ae 375 if ((ap->a_mode & ~(VREAD | VEXEC)) == 0)
1c79356b
A
376 ret_err = 0;
377 else
378 ret_err = EACCES;
379
380 DBG_VOP_LOCKS_TEST(ret_err);
381 return (ret_err);
382}
383
384/*
385 * volfs_getattr - fill in the attributes for this vnode
386 *
387 * Locking policy: don't change anything
388 */
389int
390volfs_getattr(ap)
391 struct vop_getattr_args /* { struct vnode *a_vp; struct vattr *a_vap;
392 struct ucred *a_cred; struct proc *a_p; } */ *ap;
393{
394 struct volfs_vndata *priv_data;
395 struct vnode *a_vp;
396 struct vattr *a_vap;
397 int numMounts = 0;
398 DBG_FUNC_NAME("volfs_getattr");
399 DBG_VOP_LOCKS_DECL(1);
400 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
401
402 DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS);
403
404 a_vp = ap->a_vp;
405 a_vap = ap->a_vap;
406
407 priv_data = a_vp->v_data;
408
409 a_vap->va_type = VDIR;
410 a_vap->va_mode = 0444; /* Yup, hard - coded to read - only */
411 a_vap->va_nlink = 2;
412 a_vap->va_uid = 0; /* Always owned by root */
413 a_vap->va_gid = 0; /* Always part of group 0 */
414 a_vap->va_fsid = (int) a_vp->v_mount->mnt_stat.f_fsid.val[0];
415 a_vap->va_fileid = priv_data->nodeID;
416
417 /*
418 * If it's the root vnode calculate its size based on the number of eligible
419 * file systems
420 */
421 if (priv_data->vnode_type == VOLFS_ROOT)
422 {
423 register struct mount *mp, *nmp;
424
425 simple_lock(&mountlist_slock);
426 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
427 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, ap->a_p)) {
428 nmp = mp->mnt_list.cqe_next;
429 continue;
430 }
431
432 if (mp != a_vp->v_mount && validfsnode(mp))
433 numMounts++;
434
435 simple_lock(&mountlist_slock);
436 nmp = mp->mnt_list.cqe_next;
437 vfs_unbusy(mp, ap->a_p);
438 }
439 simple_unlock(&mountlist_slock);
440
441 DBG_VOP(("found %d file systems that volfs can support\n", numMounts));
442 a_vap->va_size = (numMounts + 2) * VLFSDIRENTLEN;
443 }
444 else
445 {
446 a_vap->va_size = 2 * VLFSDIRENTLEN;
447 }
448 DBG_VOP(("va_size = %d, VLFSDIRENTLEN = %ld\n", (int) a_vap->va_size, VLFSDIRENTLEN));
449 a_vap->va_blocksize = 512;
450
451 a_vap->va_atime.tv_sec = boottime.tv_sec;
452 a_vap->va_atime.tv_nsec = 0;
453
454 a_vap->va_mtime.tv_sec = boottime.tv_sec;
455 a_vap->va_mtime.tv_nsec = 0;
456
457 a_vap->va_ctime.tv_sec = boottime.tv_sec;
458 a_vap->va_ctime.tv_nsec = 0;
459
460 a_vap->va_gen = 0;
461 a_vap->va_flags = 0;
462 a_vap->va_rdev = 0;
463 a_vap->va_bytes = a_vap->va_size;
464 a_vap->va_filerev = 0;
465 a_vap->va_vaflags = 0;
466
467 DBG_VOP_LOCKS_TEST(0);
468 return (0);
469}
470
471/*
472 * volfs_select - just say OK. Only possible op is readdir
473 *
474 * Locking policy: ignore
475 */
476int
477volfs_select(ap)
478 struct vop_select_args /* { struct vnode *a_vp; int a_which; int
0b4e3aa0 479 * a_fflags; struct ucred *a_cred; void * a_wql; struct
1c79356b
A
480 proc *a_p; } */ *ap;
481{
482 DBG_VOP(("volfs_select called\n"));
483
484 return (1);
485}
486
487/*
488 * vofls_rmdir - not possible to remove directories in volfs
489 *
490 * Locking policy: a_dvp & a_vp - locked on entry, unlocked on exit
491 */
492int
493volfs_rmdir(ap)
494 struct vop_rmdir_args /* { struct vnode *a_dvp; struct vnode *a_vp;
495 struct componentname *a_cnp; } */ *ap;
496{
497 DBG_VOP(("volfs_rmdir called\n"));
498 if (ap->a_dvp == ap->a_vp) {
499 (void) nop_rmdir(ap);
500 return (EINVAL);
501 } else
502 return (err_rmdir(ap));
503}
504
505/*
506 * volfs_readdir - Get directory entries
507 *
508 * Directory listings are only produced for the root volfs node. Filesystems
509 * just return . & ..
510 * Filesystems contained within the volfs root are named by the decimal
511 * equivalent of the f_fsid.val[0] from their mount structure (typically
512 * the device id of the volume). The maximum length for a name, then is
513 * 10 characters.
514 *
515 * Locking policy: a_vp locked on entry and exit
516 */
517int
518volfs_readdir(ap)
519 struct vop_readdir_args /* { struct vnode *a_vp; struct uio *a_uio;
520 * struct ucred *a_cred; int *a_eofflag; int
521 *ncookies; u_long **a_cookies; } */ *ap;
522{
523 struct volfs_vndata *priv_data;
524 register struct uio *uio = ap->a_uio;
525 int error = 0;
526 size_t count, lost;
527 int rec_offset;
528 struct dirent local_dir;
529 int i;
530 int starting_resid;
531 off_t off;
532 DBG_FUNC_NAME("volfs_readdir");
533 DBG_VOP_LOCKS_DECL(1);
534
535 DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
536 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
537
538 DBG_VOP(("\tuio_offset = %d, uio_resid = %d\n", (int) uio->uio_offset, uio->uio_resid));
539 /* We assume it's all one big buffer... */
540 if (uio->uio_iovcnt > 1)
541 DBG_VOP(("\tuio->uio_iovcnt = %d?\n", uio->uio_iovcnt));
542
543 off = uio->uio_offset;
544 priv_data = ap->a_vp->v_data;
545 starting_resid = uio->uio_resid;
546 count = uio->uio_resid;
547
548 /* Make sure we don't return partial entries. */
549 count -= (uio->uio_offset + count) & (VLFSDIRENTLEN - 1);
550 if (count <= 0)
551 {
552 DBG_VOP(("volfs_readdir: Not enough buffer to read in entries\n"));
553 DBG_VOP_LOCKS_TEST(EINVAL);
554 return (EINVAL);
555 }
556 /*
557 * Make sure we're starting on a directory boundary
558 */
559 if (off & (VLFSDIRENTLEN - 1))
560 {
561 DBG_VOP_LOCKS_TEST(EINVAL);
562 return (EINVAL);
563 }
564 rec_offset = off / VLFSDIRENTLEN;
565 lost = uio->uio_resid - count;
566 uio->uio_resid = count;
567 uio->uio_iov->iov_len = count;
568
569 local_dir.d_reclen = VLFSDIRENTLEN;
570 /*
571 * We must synthesize . and ..
572 */
573 DBG_VOP(("\tstarting ... uio_offset = %d, uio_resid = %d\n",
574 (int) uio->uio_offset, uio->uio_resid));
575 if (rec_offset == 0)
576 {
577 DBG_VOP(("\tAdding .\n"));
578 /*
579 * Synthesize .
580 */
581 local_dir.d_fileno = priv_data->nodeID;
582 local_dir.d_type = DT_DIR;
583 local_dir.d_namlen = 1;
584 local_dir.d_name[0] = '.';
585 for (i = 1; i < MAXVLFSNAMLEN; i++)
586 local_dir.d_name[i] = 0;
587 error = uiomove((char *) &local_dir, VLFSDIRENTLEN, uio);
588 DBG_VOP(("\t after adding ., uio_offset = %d, uio_resid = %d\n",
589 (int) uio->uio_offset, uio->uio_resid));
590 rec_offset++;
591 }
592 if (rec_offset == 1)
593 {
594 DBG_VOP(("\tAdding ..\n"));
595 /*
596 * Synthesize ..
597 * We only have two levels in the volfs hierarchy. Root's
598 * .. points to itself and the second level points to root,
599 * hence we've hardcoded d_fileno for .. here
600 */
601 local_dir.d_fileno = ROOT_DIRID;
602 local_dir.d_type = DT_DIR;
603 local_dir.d_namlen = 2;
604 local_dir.d_name[0] = '.';
605 local_dir.d_name[1] = '.';
606 for (i = 2; i < MAXVLFSNAMLEN; i++)
607 local_dir.d_name[i] = 0;
608 error = uiomove((char *) &local_dir, VLFSDIRENTLEN, uio);
609 rec_offset++;
610 DBG_VOP(("\t after adding .., uio_offset = %d, uio_resid = %d\n",
611 (int) uio->uio_offset, uio->uio_resid));
612 }
613
614 /*
615 * OK, we've given them the . & .. entries. If this is a
616 * filesystem node then we've gone as far as we're going
617 * to go
618 */
619 if (priv_data->vnode_type == VOLFS_FSNODE)
620 {
621 *ap->a_eofflag = 1; /* we got all the way to the end */
622 DBG_VOP_LOCKS_TEST(error);
623 return (error);
624 }
625
626 if (rec_offset > 1) {
627 register struct mount *mp, *nmp;
628 int validnodeindex;
629 struct proc *p = uio->uio_procp;
630
631 validnodeindex = 1; /* we always have "." and ".." */
632
633 simple_lock(&mountlist_slock);
634 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
635 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
636 nmp = mp->mnt_list.cqe_next;
637 continue;
638 }
639
640 if (mp != ap->a_vp->v_mount && validfsnode(mp))
641 validnodeindex++;
642
643 if (rec_offset == validnodeindex)
644 {
645 local_dir.d_fileno = mp->mnt_stat.f_fsid.val[0];
646 local_dir.d_type = DT_DIR;
647 local_dir.d_reclen = VLFSDIRENTLEN;
648 DBG_VOP(("\tAdding dir entry %d for offset %d\n", mp->mnt_stat.f_fsid.val[0], rec_offset));
649 local_dir.d_namlen = sprintf(&local_dir.d_name[0], "%d", mp->mnt_stat.f_fsid.val[0]);
650 error = uiomove((char *) &local_dir, VLFSDIRENTLEN, uio);
651 DBG_VOP(("\t after adding entry '%s', uio_offset = %d, uio_resid = %d\n",
652 &local_dir.d_name[0], (int) uio->uio_offset, uio->uio_resid));
653 rec_offset++;
654 }
655
656 simple_lock(&mountlist_slock);
657 nmp = mp->mnt_list.cqe_next;
658 vfs_unbusy(mp, p);
659 }
660 simple_unlock(&mountlist_slock);
661
662 if (mp == (void *) &mountlist)
663 *ap->a_eofflag = 1; /* we got all the way to the end */
664 }
665
666 uio->uio_resid += lost;
667 if (starting_resid == uio->uio_resid)
668 uio->uio_offset = 0;
669
670 DBG_VOP(("\tExiting, uio_offset = %d, uio_resid = %d, ap->a_eofflag = %d\n",
671 (int) uio->uio_offset, uio->uio_resid, *ap->a_eofflag));
672
673 DBG_VOP_LOCKS_TEST(error);
674 return (error);
675}
676
677
678/*
679 * validfsnode - test to see if a file system supports VGET
680 *
681 * This can cause context switching, so caller should be lock safe
682 */
683static int
684validfsnode(struct mount *fsnode)
685{
686
687 /*
688 * Just check to see if the the mount flag is set, if it is we assume the
689 * file system supports all of volfs symantecs
690 */
691
692 if ((! (fsnode->mnt_kern_flag & MNTK_UNMOUNT)) && (fsnode->mnt_flag & MNT_DOVOLFS))
693 return 1;
694 else
695 return 0;
696}
697
698/*
699 * volfs_lock - Lock an inode.
700 * If its already locked, set the WANT bit and sleep.
701 *
702 * Locking policy: handled by lockmgr
703 */
704int
705volfs_lock(ap)
706 struct vop_lock_args /* { struct vnode *a_vp; int a_flags; struct
707 proc *a_p; } */ *ap;
55e303ae 708{
1c79356b
A
709 int retval;
710 struct volfs_vndata *priv_data;
711 DBG_FUNC_NAME("volfs_lock");
712 DBG_VOP_LOCKS_DECL(1);
55e303ae
A
713#if 0
714 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN, 0)) | DBG_FUNC_START,
715 (unsigned int)ap->a_vp, (unsigned int)ap->a_flags, (unsigned int)ap->a_p, 0, 0);
716#endif
1c79356b
A
717 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
718
719 DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_ZERO);
55e303ae 720
1c79356b
A
721 priv_data = (struct volfs_vndata *) ap->a_vp->v_data;
722 retval = lockmgr(&priv_data->lock, ap->a_flags, &ap->a_vp->v_interlock, ap->a_p);
723 DBG_VOP_LOCKS_TEST(retval);
55e303ae
A
724#if 0
725 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN, 0)) | DBG_FUNC_END,
726 (unsigned int)ap->a_vp, (unsigned int)ap->a_flags, (unsigned int)ap->a_p, retval, 0);
727#endif
1c79356b
A
728 return (retval);
729}
730
731/*
732 * volfs_unlock - Unlock an inode.
733 *
734 * Locking policy: handled by lockmgr
735 */
736int
737volfs_unlock(ap)
738 struct vop_unlock_args /* { struct vnode *a_vp; int a_flags; struct
739 proc *a_p; } */ *ap;
740{
741 int retval;
742 struct volfs_vndata *priv_data;
743 DBG_FUNC_NAME("volfs_unlock");
744 DBG_VOP_LOCKS_DECL(1);
55e303ae
A
745#if 0
746 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN, 4)) | DBG_FUNC_START,
747 (unsigned int)ap->a_vp, (unsigned int)ap->a_flags, (unsigned int)ap->a_p, 0, 0);
748#endif
1c79356b
A
749 DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
750
751 DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_ZERO);
752
753 priv_data = (struct volfs_vndata *) ap->a_vp->v_data;
754 retval = lockmgr(&priv_data->lock, ap->a_flags | LK_RELEASE,
755 &ap->a_vp->v_interlock, ap->a_p);
756
757 DBG_VOP_LOCKS_TEST(retval);
55e303ae
A
758#if 0
759 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN, 4)) | DBG_FUNC_END,
760 (unsigned int)ap->a_vp, (unsigned int)ap->a_flags, (unsigned int)ap->a_p, retval, 0);
761#endif
1c79356b
A
762 return (retval);
763}
764
765/*
766 * volfs_islocked - Check for a locked inode.
767 *
768 * Locking policy: ignore
769 */
770int
771volfs_islocked(ap)
772 struct vop_islocked_args /* { struct vnode *a_vp; } */ *ap;
773{
774 int retval;
775 struct volfs_vndata *priv_data;
776
777 DBG_FUNC_NAME("volfs_islocked");
778 DBG_VOP_LOCKS_DECL(1);
779 //DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
780
781 DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO);
782 priv_data = (struct volfs_vndata *) ap->a_vp->v_data;
783 retval = lockstatus(&priv_data->lock);
784
785 DBG_VOP_LOCKS_TEST(retval);
786 return (retval);
787}
788
789/*
790 * volfs_pathconf - Return POSIX pathconf information applicable to ufs filesystems.
791 *
792 * Locking policy: a_vp locked on input and output
793 */
794int
795volfs_pathconf(ap)
796 struct vop_pathconf_args /* { struct vnode *a_vp; int a_name; int
797 *a_retval; } */ *ap;
798{
799 DBG_VOP(("volfs_pathconf called\n"));
800
801 switch (ap->a_name)
802 {
803 case _PC_LINK_MAX:
804 *ap->a_retval = LINK_MAX;
805 return (0);
806 case _PC_NAME_MAX:
807 *ap->a_retval = NAME_MAX;
808 return (0);
809 case _PC_PATH_MAX:
810 *ap->a_retval = PATH_MAX;
811 return (0);
812 case _PC_PIPE_BUF:
813 *ap->a_retval = PIPE_BUF;
814 return (0);
815 case _PC_CHOWN_RESTRICTED:
816 *ap->a_retval = 1;
817 return (0);
818 case _PC_NO_TRUNC:
819 *ap->a_retval = 1;
820 return (0);
821 default:
822 return (EINVAL);
823 }
824 /* NOTREACHED */
825}
826
55e303ae
A
827
828/*
829 * Call VOP_GETATTRLIST on a given vnode
830 */
831static int
832vp_getattrlist(struct vnode *vp, struct attrlist alist, void *attrbufptr, size_t bufsize, unsigned long options, struct proc *p) {
833 struct iovec iov;
834 struct uio bufuio;
835
836 iov.iov_base = (char *)attrbufptr;
837 iov.iov_len = bufsize;
838
839 bufuio.uio_iov = &iov;
840 bufuio.uio_iovcnt = 1;
841 bufuio.uio_offset = 0;
842 bufuio.uio_resid = iov.iov_len;
843 bufuio.uio_segflg = UIO_SYSSPACE;
844 bufuio.uio_rw = UIO_READ;
845 bufuio.uio_procp = p;
846
847 return VOP_GETATTRLIST(vp, &alist, &bufuio, p->p_ucred, p);
848}
849
850/*
851 * get_parentvp() - internal routine that tries to lookup the parent of vpp.
852 * On success, *vpp is the parent vp and is returned locked and the original child
853 * is left unlocked. On failure, the original child will be locked upon return.
854 */
855static int
856get_parentvp(struct vnode **vpp, struct mount *mp, struct proc *p)
857{
858 int result;
859 struct attrlist alist;
860 struct finfoattrbuf finfobuf;
861 struct vnode *child_vp = *vpp;
862
863 alist.bitmapcount = 5;
864 alist.reserved = 0;
865 alist.commonattr = ATTR_CMN_PAROBJID;
866 alist.volattr = 0;
867 alist.dirattr = 0;
868 alist.fileattr = 0;
869 alist.forkattr = 0;
870 result = vp_getattrlist(child_vp, alist, &finfobuf, sizeof(finfobuf), 0, p);
871 if (result)
872 return result;
873
874 /* Release the child vnode before trying to acquire its parent
875 to avoid vnode deadlock problems with parsing code
876 coming top-down through the directory hierarchy: */
877 VOP_UNLOCK(child_vp, 0, p);
878
879 /* Shift attention to the parent directory vnode: */
880 result = VFS_VGET(mp, &finfobuf.fi.parID.fid_objno, vpp);
881 if (result) {
882 /* Make sure child_vp is still locked on exit: */
883 vn_lock(child_vp, LK_EXCLUSIVE | LK_RETRY, p);
884 }
885
886 return result;
887}
888
889
890/*
891 * Look up the parent directory of a given vnode.
892 */
893static int
894lookup_parent(u_int id, struct vnode *child_vp, struct vnode **parent_vp, struct proc *p)
895{
896 struct nameidata nd;
897 struct componentname *cnp = &nd.ni_cnd;
898 struct filedesc *fdp = p->p_fd;
899 int error;
900
901 *parent_vp = NULL;
902
903 /*
904 * Special case lookups for root's parent directory,
905 * recognized by its special id of "1":
906 */
907 if (id != 1) {
908 VREF(child_vp);
909 nd.ni_startdir = child_vp;
910 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, (caddr_t)&gDotDot, p);
911 } else {
912 struct vnode *root_vp;
913
914 error = VFS_ROOT(child_vp->v_mount, &root_vp);
915 if (error) return error;
916 VOP_UNLOCK(root_vp, 0, p); /* Hold on to the reference */
917 nd.ni_startdir = root_vp;
918 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, (caddr_t)&gDot, p);
919 };
920 nd.ni_cnd.cn_cred = nd.ni_cnd.cn_proc->p_ucred;
921
922 /* Since we can't hit any symlinks, use the source path string directly: */
923 cnp->cn_pnbuf = nd.ni_dirp;
924 nd.ni_pathlen = strlen(cnp->cn_pnbuf);
925 cnp->cn_pnlen = nd.ni_pathlen + 1;
926 cnp->cn_flags |= (HASBUF | SAVENAME);
927
928 nd.ni_loopcnt = 0;
929
930 if ((nd.ni_rootdir = fdp->fd_rdir) == NULL) nd.ni_rootdir = rootvnode;
931 cnp->cn_nameptr = cnp->cn_pnbuf;
932 if (error = lookup(&nd)) {
933 cnp->cn_pnbuf = NULL;
934 return (error);
935 }
936 /*
937 * Check for symbolic link
938 */
939 if (cnp->cn_flags & ISSYMLINK) return ENOENT;
940 if (nd.ni_vp == child_vp) return ELOOP;
941
942 *parent_vp = nd.ni_vp;
943 return 0;
944}
945
946
947
948/*
949 * verify_fullpathaccess(ret_vnode);
950 */
951
952static int
953verify_fullpathaccess(u_int id, struct vnode *targetvp, struct proc *p) {
954 struct vnode *vp, *parent_vp;
955 struct mount *mp = targetvp->v_mount;
956 struct attrlist alist;
957 struct finfoattrbuf finfobuf;
958 int result;
959 struct filedesc *fdp = p->p_fd; /* pointer to file descriptor state */
960 u_int target_id;
961 u_long vp_id;
962
963#if 0
964 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN, 12)) | DBG_FUNC_START,
965 (unsigned int)targetvp, (unsigned int)mp, (unsigned int)p, 0, 0);
966#endif
967
968 vp = targetvp;
969 vp_id = vp->v_id;
970 if (vp->v_type != VDIR) {
971
972 /* The target is a file: get the parent directory. */
973 result = get_parentvp(&vp, mp, p);
974 if (result) goto err_exit;
975
976 /* At this point, targetvp is unlocked (but still referenced), and
977 vp is the parent directory vnode, held locked */
978 };
979
980
981#if MAXPLCENTRIES
982 if (volfs_PLCLookup(mp->mnt_stat.f_fsid.val[0], id, p->p_ucred->cr_uid, p->p_pid)) goto lookup_success;
983#endif
984 /* Keep going up until either the process's root or the process's working directory is hit,
985 either one of which are potential valid starting points for a full pathname: */
986 target_id = id;
987 while (vp != NULL && (!((vp->v_flag & VROOT) || /* Hit "/" */
988 (vp == fdp->fd_cdir) || /* Hit process's working directory */
989 (vp == fdp->fd_rdir)))) { /* Hit process chroot()-ed root */
990
991 /* At this point, vp is some directory node and it's always locked */
992 /* Unlock the starting directory for namei(), retaining a reference... */
993 VOP_UNLOCK(vp, 0, p);
994
995 if (result = lookup_parent(target_id, vp, &parent_vp, p)) {
996 /*
997 * If the lookup fails with EACCES and the targetvp is a directory,
998 * we should try again using get_parentvp(). Without this check,
999 * directories that you can navigate to but not traverse will
1000 * disappear when clicked in the Finder.
1001 */
1002 if (result == EACCES && vp == targetvp && vp->v_type == VDIR && (vp->v_flag & VROOT) == 0) {
1003 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1004 parent_vp = vp;
1005 if (get_parentvp(&parent_vp, mp, p)) {
1006 /* on error, vp is still locked... unlock for lookup_err_exit path */
1007 VOP_UNLOCK(vp, 0, p);
1008 } else {
1009 /* on success, vp is returned unlocked, parent_vp is returned locked */
1010 result = 0;
1011 }
1012 };
1013 if (result) goto lookup_err_exit;
1014 };
1015
1016 if (vp != targetvp) {
1017 vrele(vp); /* Completely done with that vp now... */
1018 };
1019
1020 vp = parent_vp;
1021 target_id = 0; /* It's unknown at this point */
1022
1023 if (((result = VOP_ACCESS(vp, VEXEC, p->p_ucred, p)) != 0) &&
1024 ((result = VOP_ACCESS(vp, VREAD, p->p_ucred, p)) != 0)) {
1025 VOP_UNLOCK(vp, 0, p);
1026 goto lookup_err_exit;
1027 };
1028 };
1029
1030#if MAXPLCENTRIES
1031 volfs_PLCEnter(mp->mnt_stat.f_fsid.val[0], id, p->p_ucred->cr_uid, p->p_pid);
1032#endif
1033
1034lookup_success:
1035 /* Success: the caller has complete access to the initial vnode: */
1036 result = 0;
1037
1038 if (vp && vp != targetvp) VOP_UNLOCK(vp, 0, p);
1039
1040lookup_err_exit:
1041 if (vp && vp != targetvp) {
1042 vrele(vp);
1043 vn_lock(targetvp, LK_EXCLUSIVE | LK_RETRY, p);
1044 if (vp_id != targetvp->v_id || targetvp->v_type == VBAD) {
1045 result = EAGAIN; /* vnode was recycled */
1046 }
1047 };
1048
1049err_exit:
1050#if 0
1051 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN, 12)) | DBG_FUNC_END,
1052 (unsigned int)targetvp, (unsigned int)mp, (unsigned int)p, result, 0);
1053#endif
1054 return result;
1055};
1056
1057
1c79356b
A
1058/*
1059 * get_fsvnode - internal routine to create a vnode for a file system. Called with mount pointer,
1060 * id of filesystem to lookup and pointer to vnode pointer to fill in
1061 */
1062static int
1063get_fsvnode(our_mount, id, ret_vnode)
1064 struct mount *our_mount;
1065 int id;
1066 struct vnode **ret_vnode;
1067{
1068 register struct mount *mp;
1069 struct mount *cur_mount;
1070 struct vnode *cur_vnode;
1071 struct volfs_vndata *cur_privdata;
1072 int retval;
1073
1074 //DBG_VOP(("volfs: get_fsvnode called\n"));
1075
1076 /*
1077 * OK, first look up the matching mount on the list of mounted file systems
1078 */
1079 cur_mount = NULL;
1080 simple_lock(&mountlist_slock);
1081 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = mp->mnt_list.cqe_next)
1082 {
1083 if (validfsnode(mp) && mp->mnt_stat.f_fsid.val[0] == id)
1084 {
1085 cur_mount = mp;
1086 break;
1087 }
1088 }
1089 simple_unlock(&mountlist_slock);
1090
1091 if (cur_mount == NULL) {
1092 /*
1093 * No mounted file system by the specified ID currently exists in the system.
1094 *
1095 * XXX We could deal with a vnode that is still hanging about for an FS that
1096 * does not exists or has been unmounted now, or count on the update below
1097 * to happen later...
1098 */
1099 *ret_vnode = NULL;
1100 return ENOENT;
1101 };
1102
1103 /*
1104 * Now search the list attached to the mount structure to
1105 * see if this vnode is already floating around
1106 */
1107search_vnodelist:
1108 cur_vnode = our_mount->mnt_vnodelist.lh_first;
1109 while (cur_vnode != NULL)
1110 {
1111 cur_privdata = (struct volfs_vndata *) cur_vnode->v_data;
1112 if (cur_privdata->nodeID == id)
1113 {
1114 if (cur_privdata->fs_mount != cur_mount) {
1115 DBG_VOP(("volfs get_fsvnode: Updating fs_mount for vnode 0x%08lX (id = %d) from 0x%08lX to 0x%08lX...\n",
1116 (unsigned long)cur_vnode,
1117 cur_privdata->nodeID,
1118 (unsigned long)cur_privdata->fs_mount,
1119 (unsigned long)cur_mount));
1120 cur_privdata->fs_mount = cur_mount;
1121 };
1122 break;
1123 }
1124 cur_vnode = cur_vnode->v_mntvnodes.le_next;
1125 }
1126
1127 //DBG_VOP(("\tfinal cur_mount: 0x%x\n",cur_mount));
1128 if (cur_vnode) {
1129 /* If vget returns an error, cur_vnode will not be what we think it is, try again */
1130 if (vget(cur_vnode, LK_EXCLUSIVE, current_proc()) != 0) {
1131 goto search_vnodelist;
1132 };
1133 }
1134 else
1135 {
1136 MALLOC(cur_privdata, struct volfs_vndata *,
1137 sizeof(struct volfs_vndata), M_VOLFSNODE, M_WAITOK);
1138 retval = getnewvnode(VT_VOLFS, our_mount, volfs_vnodeop_p, &cur_vnode);
1139 if (retval != 0) {
1140 FREE(cur_privdata, M_VOLFSNODE);
1141 return retval;
1142 };
1143
1144 cur_privdata->vnode_type = VOLFS_FSNODE;
1145 cur_privdata->nodeID = id;
1146
1147 cur_privdata->fs_mount = cur_mount;
1148 lockinit(&cur_privdata->lock, PINOD, "volfsnode", 0, 0);
1149 lockmgr(&cur_privdata->lock, LK_EXCLUSIVE, (struct slock *)0, current_proc());
1150 cur_vnode->v_data = cur_privdata;
1151 cur_vnode->v_type = VDIR;
1152 DBG_VOP(("get_fsvnode returned with new node of "));
1153 DBG_VOP_PRINT_VNODE_INFO(cur_vnode);DBG_VOP(("\n"));
1154 }
1155
1156 *ret_vnode = cur_vnode;
1157
1158 return (0);
1159}
1160
1161
1162
1163/*
1164 * get_filevnode - returns the vnode for the given id within a filesystem. The parent vnode
1165 * is a filesystem, id is the 32-bit id of the file/directory and ret_vnode is a pointer
1166 * to a vnode pointer
1167 */
1168static int
55e303ae 1169get_filevnode(parent_fs, id, ret_vnode, p)
1c79356b
A
1170 struct mount *parent_fs;
1171 u_int id;
1172 struct vnode **ret_vnode;
55e303ae 1173 struct proc *p;
1c79356b
A
1174{
1175 int retval;
1176
55e303ae 1177again:
1c79356b
A
1178 /*
1179 * Special case 2 to mean the root of a file system
1180 */
1181 if (id == 2)
1182 retval = VFS_ROOT(parent_fs, ret_vnode);
1183 else
1184 retval = VFS_VGET(parent_fs, &id, ret_vnode);
55e303ae
A
1185 if (retval) goto error;
1186
1187 retval = verify_fullpathaccess(id, *ret_vnode, p);
1188 if (retval) {
1189 /* An error was encountered verifying that the caller has,
1190 in fact, got access all the way from "/" or their working
1191 directory to the specified item...
1192 */
1193 vput(*ret_vnode);
1194 *ret_vnode = NULL;
1195 /* vnode was recycled during access verification. */
1196 if (retval == EAGAIN) {
1197 goto again;
1198 }
1199 };
1c79356b 1200
55e303ae 1201error:
1c79356b
A
1202 return (retval);
1203}
1204
1205
1206int
1207volfs_lookup(ap)
1208 struct vop_lookup_args /* { struct vnode *a_dvp; struct vnode
1209 **a_vpp; struct componentname *a_cnp; } */ *ap;
1210{
1211 struct volfs_vndata *priv_data;
1212 char *cnp;
1213 long namelen;
1214 struct mount *parent_fs;
55e303ae 1215 int unlocked_parent = 0, isdot_or_dotdot = 0;
1c79356b
A
1216 int ret_err = ENOENT;
1217 DBG_FUNC_NAME("volfs_lookup");
1218 DBG_VOP_LOCKS_DECL(2);
1219
55e303ae
A
1220#if 0
1221 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN, 8)) | DBG_FUNC_START,
1222 (unsigned int)ap->a_dvp, (unsigned int)ap->a_cnp, (unsigned int)p, 0, 0);
1223#endif
1224
1c79356b
A
1225 DBG_VOP(("volfs_lookup called, name = %s, namelen = %ld\n", ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
1226
1227 DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
1228 DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS);
1229 DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
1230 DBG_VOP(("\t"));DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP(("\n"));
1231 if (ap->a_cnp->cn_flags & LOCKPARENT)
1232 DBG_VOP(("\tLOCKPARENT is set\n"));
1233 if (ap->a_cnp->cn_flags & ISLASTCN)
1234 {
1235 DBG_VOP(("\tISLASTCN is set\n"));
1236 if (ap->a_cnp->cn_nameiop == DELETE || ap->a_cnp->cn_nameiop == RENAME) /* XXX PPD Shouldn't we check for CREATE, too? */
1237 {
1238 ret_err = EROFS;
1239 goto Err_Exit;
1240 }
1241 }
1242 priv_data = ap->a_dvp->v_data;
1243 cnp = ap->a_cnp->cn_nameptr;
1244 namelen = ap->a_cnp->cn_namelen;
1245
1246#if VOLFS_DEBUG
1247 switch (priv_data->vnode_type) {
1248 case VOLFS_ROOT:
1249 DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_ROOT.\n", (unsigned long)ap->a_dvp));
1250 break;
1251
1252 case VOLFS_FSNODE:
1253 DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_FSNODE, nodeID = %d, fs_mount = 0x%08lX.\n",
1254 (unsigned long)ap->a_dvp,
1255 priv_data->nodeID,
1256 (unsigned long)priv_data->fs_mount));
1257
1258 default:
1259 DBG_VOP(("\tparent directory (vnode 0x%08lX) has unknown vnode_type (%d), nodeID = %d.\n",
1260 (unsigned long)ap->a_dvp,
1261 priv_data->vnode_type,
1262 priv_data->nodeID));
1263 };
1264#endif /* VOLFS_DEBUG */
1265
1266 /* first check for "." and ".." */
1267 if (cnp[0] == '.')
1268 {
1269 if (namelen == 1)
1270 {
1271 /* "." requested */
55e303ae 1272 isdot_or_dotdot = 1;
1c79356b
A
1273 *ap->a_vpp = ap->a_dvp;
1274 VREF(*ap->a_vpp);
1275 DBG_VOP_LOCKS_TEST(0);
55e303ae 1276 ret_err = 0;
1c79356b
A
1277 }
1278 else if (cnp[1] == '.' && namelen == 2)
1279 {
1280 /* ".." requested */
55e303ae 1281 isdot_or_dotdot = 1;
1c79356b
A
1282 ret_err = volfs_root(ap->a_dvp->v_mount, ap->a_vpp);
1283 }
1284 }
1285
1286 /* then look for special file system root symbol ('@') */
1287 else if (cnp[0] == '@')
1288 {
1289 if ((namelen == 1) && (priv_data->vnode_type != VOLFS_ROOT)) {
1290 parent_fs = priv_data->fs_mount;
1291 if (!(ap->a_cnp->cn_flags & LOCKPARENT) || !(ap->a_cnp->cn_flags & ISLASTCN)) {
1292 VOP_UNLOCK(ap->a_dvp, 0, ap->a_cnp->cn_proc);
1293 unlocked_parent = 1;
1294 };
1295 ret_err = VFS_ROOT(parent_fs, ap->a_vpp);
1296 } else {
1297 DBG_VOP(("volfs_lookup: pathname = '@' but namelen = %ld and parent vnode_type = %d.\n", namelen, priv_data->vnode_type));
1298 *ap->a_vpp = NULL;
1299 ret_err = ENOENT;
1300 };
1301 }
1302
1303 /* finally, just look for numeric ids... */
1304 else if (namelen <= 10 && cnp[0] > '0' && cnp[0] <= '9') /* 10 digits max lead digit must be 1 - 9 */
1305 {
1306 char *check_ptr;
1307 u_long id;
1308
0b4e3aa0 1309 id = strtoul(cnp, &check_ptr, 10);
1c79356b
A
1310
1311 /*
1312 * strtol will leave us at the first non-numeric character.
1313 * we've checked to make sure the component name does
1314 * begin with a numeric so check_ptr must wind up on
1315 * the terminating null or there was other junk following the
1316 * number
1317 */
1318 if ((check_ptr - cnp) == namelen)
1319 {
1320 if (priv_data->vnode_type == VOLFS_ROOT)
1321 ret_err = get_fsvnode(ap->a_dvp->v_mount, id, ap->a_vpp);
1322 else {
1323 parent_fs = priv_data->fs_mount;
55e303ae
A
1324 if (!(ap->a_cnp->cn_flags & LOCKPARENT) || !(ap->a_cnp->cn_flags & ISLASTCN)) {
1325 VOP_UNLOCK(ap->a_dvp, 0, ap->a_cnp->cn_proc);
1326 unlocked_parent = 1;
1327 };
1328 ret_err = get_filevnode(parent_fs, id, ap->a_vpp, ap->a_cnp->cn_proc);
1c79356b
A
1329 }
1330 }
55e303ae 1331 }
1c79356b 1332
55e303ae
A
1333 if (!isdot_or_dotdot && *ap->a_vpp && VPARENT(*ap->a_vpp) == NULL && ap->a_dvp != *ap->a_vpp) {
1334 if (VPARENT(ap->a_dvp) == *ap->a_vpp) {
1335 panic("volfs: ap->a_dvp 0x%x has parent == a_vpp 0x%x\n",
1336 ap->a_dvp, *ap->a_vpp);
1337 }
1338 vget(ap->a_dvp, 0, ap->a_cnp->cn_proc);
1339 VPARENT(*ap->a_vpp) = ap->a_dvp;
1c79356b
A
1340 }
1341
1342 if (!unlocked_parent && (!(ap->a_cnp->cn_flags & LOCKPARENT) || !(ap->a_cnp->cn_flags & ISLASTCN))) {
1343 VOP_UNLOCK(ap->a_dvp, 0, ap->a_cnp->cn_proc);
1344 };
1345
1346 /* XXX PPD Should we do something special in case LOCKLEAF isn't set? */
1347
1348Err_Exit:
1349
1350 DBG_VOP_UPDATE_VP(1, *ap->a_vpp);
1351 DBG_VOP_LOCKS_TEST(ret_err);
1352
55e303ae
A
1353#if 0
1354 KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN, 8)) | DBG_FUNC_START,
1355 (unsigned int)ap->a_dvp, (unsigned int)ap->a_cnp, (unsigned int)p, ret_err, 0);
1356#endif
1c79356b
A
1357 return (ret_err);
1358}
1359
1360#if DBG_VOP_TEST_LOCKS
1361
1362#if 0
1363static void DbgLookupTest( char *funcname, struct componentname *cnp, struct vnode *dvp, struct vnode *vp)
1364{
1365 int flags = cnp->cn_flags;
1366 int nameiop = cnp->cn_nameiop;
1367
1368 DBG_VOP (("%s: Action:", funcname));
1369 switch (nameiop)
1370 {
1371 case LOOKUP:
1372 PRINTIT ("LOOKUP");
1373 break;
1374 case CREATE:
1375 PRINTIT ("CREATE");
1376 break;
1377 case DELETE:
1378 PRINTIT ("DELETE");
1379 break;
1380 case RENAME:
1381 PRINTIT ("RENAME");
1382 break;
1383 default:
1384 PRINTIT ("!!!UNKNOWN!!!!");
1385 break;
1386 }
1387 PRINTIT(" flags: 0x%x ",flags );
1388 if (flags & LOCKPARENT)
1389 PRINTIT (" Lock Parent");
1390 if (flags & ISLASTCN)
1391 PRINTIT (" Last Action");
1392 PRINTIT("\n");
1393
1394 if (dvp)
1395 {
1396 PRINTIT ("%s: Parent vnode exited ", funcname);
1397 if (VOP_ISLOCKED(dvp))
1398 PRINTIT("LOCKED\n");
1399 else
1400 PRINTIT("UNLOCKED\n");
1401 }
1402 if (vp && vp==dvp)
1403 {
1404 PRINTIT ("%s: Found and Parent are the same\n", funcname);
1405 }
1406 else if (vp)
1407 {
1408 PRINTIT ("%s: Found vnode exited ", funcname);
1409 if (VOP_ISLOCKED(vp))
1410 PRINTIT("LOCKED\n");
1411 else
1412 PRINTIT("UNLOCKED\n");
1413 }
1414 else
1415 PRINTIT ("%s: Found vnode exited NULL\n", funcname);
1416
1417
1418}
1419#endif
1420
1421static void DbgVopTest( int maxSlots,
1422 int retval,
1423 VopDbgStoreRec *VopDbgStore,
1424 char *funcname)
1425{
1426 int index;
1427
1428 for (index = 0; index < maxSlots; index++)
1429 {
1430 if (VopDbgStore[index].id != index) {
1431 PRINTIT("%s: DBG_VOP_LOCK: invalid id field (%d) in target entry (#%d).\n", funcname, VopDbgStore[index].id, index);
1432 return;
1433 };
1434
1435 if ((VopDbgStore[index].vp != NULL) &&
1436 ((VopDbgStore[index].vp->v_data==NULL)))
1437 continue;
1438
1439 switch (VopDbgStore[index].inState)
1440 {
1441 case VOPDBG_IGNORE:
1442 case VOPDBG_SAME:
1443 /* Do Nothing !!! */
1444 break;
1445 case VOPDBG_LOCKED:
1446 case VOPDBG_UNLOCKED:
1447 case VOPDBG_LOCKNOTNIL:
1448 {
1449 if (VopDbgStore[index].vp == NULL && (VopDbgStore[index].inState != VOPDBG_LOCKNOTNIL)) {
1450 PRINTIT ("%s: InState check: Null vnode ptr in entry #%d\n", funcname, index);
1451 } else if (VopDbgStore[index].vp != NULL) {
1452 switch (VopDbgStore[index].inState)
1453 {
1454 case VOPDBG_LOCKED:
1455 case VOPDBG_LOCKNOTNIL:
1456 if (VopDbgStore[index].inValue == 0)
1457 {
1458 PRINTIT ("%s: %d Entry: not LOCKED:", funcname, index); DBG_VOP(("\n"));
1459 }
1460 break;
1461 case VOPDBG_UNLOCKED:
1462 if (VopDbgStore[index].inValue != 0)
1463 {
1464 PRINTIT ("%s: %d Entry: not UNLOCKED:", funcname, index); DBG_VOP(("\n"));
1465 }
1466 break;
1467 }
1468 }
1469 break;
1470 }
1471 default:
1472 PRINTIT ("%s: DBG_VOP_LOCK on entry: bad lock test value: %d\n", funcname, VopDbgStore[index].errState);
1473 }
1474
1475
1476 if (retval != 0)
1477 {
1478 switch (VopDbgStore[index].errState)
1479 {
1480 case VOPDBG_IGNORE:
1481 /* Do Nothing !!! */
1482 break;
1483 case VOPDBG_LOCKED:
1484 case VOPDBG_UNLOCKED:
1485 case VOPDBG_SAME:
1486 {
1487 if (VopDbgStore[index].vp == NULL) {
1488 PRINTIT ("%s: ErrState check: Null vnode ptr in entry #%d\n", funcname, index);
1489 } else {
1490 VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
1491 switch (VopDbgStore[index].errState)
1492 {
1493 case VOPDBG_LOCKED:
1494 if (VopDbgStore[index].outValue == 0)
1495 {
1496 PRINTIT ("%s: %d Error: not LOCKED:", funcname, index); DBG_VOP(("\n"));
1497 }
1498 break;
1499 case VOPDBG_UNLOCKED:
1500 if (VopDbgStore[index].outValue != 0)
1501 {
1502 PRINTIT ("%s: %d Error: not UNLOCKED:", funcname, index); DBG_VOP(("\n"));
1503 }
1504 break;
1505 case VOPDBG_SAME:
1506 if (VopDbgStore[index].outValue != VopDbgStore[index].inValue)
1507 PRINTIT ("%s: Error: In/Out locks are DIFFERENT: 0x%x, inis %d and out is %d\n", funcname, (u_int)VopDbgStore[index].vp, VopDbgStore[index].inValue, VopDbgStore[index].outValue);
1508 break;
1509 }
1510 }
1511 break;
1512 }
1513 case VOPDBG_LOCKNOTNIL:
1514 if (VopDbgStore[index].vp != NULL) {
1515 VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
1516 if (VopDbgStore[index].outValue == 0)
1517 PRINTIT ("%s: Error: %d Not LOCKED: 0x%x\n", funcname, index, (u_int)VopDbgStore[index].vp);
1518 }
1519 break;
1520 default:
1521 PRINTIT ("%s: Error: bad lock test value: %d\n", funcname, VopDbgStore[index].errState);
1522 }
1523 }
1524 else
1525 {
1526 switch (VopDbgStore[index].outState)
1527 {
1528 case VOPDBG_IGNORE:
1529 /* Do Nothing !!! */
1530 break;
1531 case VOPDBG_LOCKED:
1532 case VOPDBG_UNLOCKED:
1533 case VOPDBG_SAME:
1534 if (VopDbgStore[index].vp == NULL) {
1535 PRINTIT ("%s: OutState: Null vnode ptr in entry #%d\n", funcname, index);
1536 };
1537 if (VopDbgStore[index].vp != NULL)
1538 {
1539 VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
1540 switch (VopDbgStore[index].outState)
1541 {
1542 case VOPDBG_LOCKED:
1543 if (VopDbgStore[index].outValue == 0)
1544 {
1545 PRINTIT ("%s: %d Out: not LOCKED:", funcname, index); DBG_VOP(("\n"));
1546 }
1547 break;
1548 case VOPDBG_UNLOCKED:
1549 if (VopDbgStore[index].outValue != 0)
1550 {
1551 PRINTIT ("%s: %d Out: not UNLOCKED:", funcname, index); DBG_VOP(("\n"));
1552 }
1553 break;
1554 case VOPDBG_SAME:
1555 if (VopDbgStore[index].outValue != VopDbgStore[index].inValue)
1556 PRINTIT ("%s: Out: In/Out locks are DIFFERENT: 0x%x, inis %d and out is %d\n", funcname, (u_int)VopDbgStore[index].vp, VopDbgStore[index].inValue, VopDbgStore[index].outValue);
1557 break;
1558 }
1559 }
1560 break;
1561 case VOPDBG_LOCKNOTNIL:
1562 if (VopDbgStore[index].vp != NULL) {
1563 if (&((struct volfs_vndata *)(VopDbgStore[index].vp->v_data))->lock == NULL)
1564 PRINTIT ("%s: DBG_VOP_LOCK on out: Null lock on vnode 0x%x\n", funcname, (u_int)VopDbgStore[index].vp);
1565 else {
1566 VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
1567 if (VopDbgStore[index].outValue == 0)
1568 {
1569 PRINTIT ("%s: DBG_VOP_LOCK on out: Should be LOCKED:", funcname); DBG_VOP(("\n"));
1570 }
1571 }
1572 }
1573 break;
1574 default:
1575 PRINTIT ("%s: DBG_VOP_LOCK on out: bad lock test value: %d\n", funcname, VopDbgStore[index].outState);
1576 }
1577 }
1578
1579 VopDbgStore[index].id = -1; /* Invalidate the entry to allow panic-free re-use */
1580 }
1581}
1582
1583#endif /* DBG_VOP_TEST_LOCKS */
1584