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