1/*
2 * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29/*
30 * Copyright (c) 1989, 1993
31 *	The Regents of the University of California.  All rights reserved.
32 *
33 * This code is derived from software contributed
34 * to Berkeley by John Heidemann of the UCLA Ficus project.
35 *
36 * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 *    notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 *    notice, this list of conditions and the following disclaimer in the
45 *    documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 *    must display the following acknowledgement:
48 *	This product includes software developed by the University of
49 *	California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 *    may be used to endorse or promote products derived from this software
52 *    without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 *
66 *	@(#)vfs_init.c	8.5 (Berkeley) 5/11/95
67 */
68/*
69 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
70 * support for mandatory and extensible security protections.  This notice
71 * is included in support of clause 2.2 (b) of the Apple Public License,
72 * Version 2.0.
73 */
74
75
76#include <sys/param.h>
77#include <sys/mount_internal.h>
78#include <sys/time.h>
79#include <sys/vm.h>
80#include <sys/vnode_internal.h>
81#include <sys/stat.h>
82#include <sys/namei.h>
83#include <sys/ucred.h>
84#include <sys/errno.h>
85#include <sys/malloc.h>
86
87#include <vfs/vfs_journal.h>	/* journal_init() */
88#if CONFIG_MACF
89#include <security/mac_framework.h>
90#include <sys/kauth.h>
91#endif
92#if QUOTA
93#include <sys/quota.h>
94#endif
95
96/*
97 * Sigh, such primitive tools are these...
98 */
99#if 0
100#define DODEBUG(A) A
101#else
102#define DODEBUG(A)
103#endif
104
105__private_extern__ void vntblinit(void);
106
107extern struct vnodeopv_desc *vfs_opv_descs[];
108				/* a list of lists of vnodeops defns */
109extern struct vnodeop_desc *vfs_op_descs[];
110				/* and the operations they perform */
111/*
112 * This code doesn't work if the defn is **vnodop_defns with cc.
113 * The problem is because of the compiler sometimes putting in an
114 * extra level of indirection for arrays.  It's an interesting
115 * "feature" of C.
116 */
117int vfs_opv_numops;
118
119typedef int (*PFIvp)(void *);
120
121/*
122 * A miscellaneous routine.
123 * A generic "default" routine that just returns an error.
124 */
125int
126vn_default_error(void)
127{
128
129	return (ENOTSUP);
130}
131
132/*
133 * vfs_init.c
134 *
135 * Allocate and fill in operations vectors.
136 *
137 * An undocumented feature of this approach to defining operations is that
138 * there can be multiple entries in vfs_opv_descs for the same operations
139 * vector. This allows third parties to extend the set of operations
140 * supported by another layer in a binary compatibile way. For example,
141 * assume that NFS needed to be modified to support Ficus. NFS has an entry
142 * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
143 * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
144 * listing those new operations Ficus adds to NFS, all without modifying the
145 * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but
146 * that is a(whole)nother story.) This is a feature.
147 */
148void
149vfs_opv_init(void)
150{
151	int i, j, k;
152	int (***opv_desc_vector_p)(void *);
153	int (**opv_desc_vector)(void *);
154	struct vnodeopv_entry_desc *opve_descp;
155
156	/*
157	 * Allocate the dynamic vectors and fill them in.
158	 */
159	for (i=0; vfs_opv_descs[i]; i++) {
160		opv_desc_vector_p = vfs_opv_descs[i]->opv_desc_vector_p;
161		/*
162		 * Allocate and init the vector, if it needs it.
163		 * Also handle backwards compatibility.
164		 */
165		if (*opv_desc_vector_p == NULL) {
166			MALLOC(*opv_desc_vector_p, PFIvp*,
167			       vfs_opv_numops*sizeof(PFIvp), M_TEMP, M_WAITOK);
168			bzero (*opv_desc_vector_p, vfs_opv_numops*sizeof(PFIvp));
169			DODEBUG(printf("vector at %x allocated\n",
170			    opv_desc_vector_p));
171		}
172		opv_desc_vector = *opv_desc_vector_p;
173		for (j=0; vfs_opv_descs[i]->opv_desc_ops[j].opve_op; j++) {
174			opve_descp = &(vfs_opv_descs[i]->opv_desc_ops[j]);
175
176			/*
177			 * Sanity check:  is this operation listed
178			 * in the list of operations?  We check this
179			 * by seeing if its offest is zero.  Since
180			 * the default routine should always be listed
181			 * first, it should be the only one with a zero
182			 * offset.  Any other operation with a zero
183			 * offset is probably not listed in
184			 * vfs_op_descs, and so is probably an error.
185			 *
186			 * A panic here means the layer programmer
187			 * has committed the all-too common bug
188			 * of adding a new operation to the layer's
189			 * list of vnode operations but
190			 * not adding the operation to the system-wide
191			 * list of supported operations.
192			 */
193			if (opve_descp->opve_op->vdesc_offset == 0 &&
194				    opve_descp->opve_op->vdesc_offset !=
195				    	VOFFSET(vnop_default)) {
196				printf("operation %s not listed in %s.\n",
197				    opve_descp->opve_op->vdesc_name,
198				    "vfs_op_descs");
199				panic ("vfs_opv_init: bad operation");
200			}
201			/*
202			 * Fill in this entry.
203			 */
204			opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
205					opve_descp->opve_impl;
206		}
207	}
208	/*
209	 * Finally, go back and replace unfilled routines
210	 * with their default.  (Sigh, an O(n^3) algorithm.  I
211	 * could make it better, but that'd be work, and n is small.)
212	 */
213	for (i = 0; vfs_opv_descs[i]; i++) {
214		opv_desc_vector = *(vfs_opv_descs[i]->opv_desc_vector_p);
215		/*
216		 * Force every operations vector to have a default routine.
217		 */
218		if (opv_desc_vector[VOFFSET(vnop_default)]==NULL) {
219			panic("vfs_opv_init: operation vector without default routine.");
220		}
221		for (k = 0; k<vfs_opv_numops; k++)
222			if (opv_desc_vector[k] == NULL)
223				opv_desc_vector[k] =
224					opv_desc_vector[VOFFSET(vnop_default)];
225	}
226}
227
228/*
229 * Initialize known vnode operations vectors.
230 */
231void
232vfs_op_init(void)
233{
234	int i;
235
236	DODEBUG(printf("Vnode_interface_init.\n"));
237	/*
238	 * Set all vnode vectors to a well known value.
239	 */
240	for (i = 0; vfs_opv_descs[i]; i++)
241		*(vfs_opv_descs[i]->opv_desc_vector_p) = NULL;
242	/*
243	 * Figure out how many ops there are by counting the table,
244	 * and assign each its offset.
245	 */
246	for (vfs_opv_numops = 0, i = 0; vfs_op_descs[i]; i++) {
247		vfs_op_descs[i]->vdesc_offset = vfs_opv_numops;
248		vfs_opv_numops++;
249	}
250	DODEBUG(printf ("vfs_opv_numops=%d\n", vfs_opv_numops));
251}
252
253/*
254 * Routines having to do with the management of the vnode table.
255 */
256extern struct vnodeops dead_vnodeops;
257extern struct vnodeops spec_vnodeops;
258
259/* vars for vnode lock */
260lck_grp_t * vnode_lck_grp;
261lck_grp_attr_t * vnode_lck_grp_attr;
262lck_attr_t * vnode_lck_attr;
263
264#if CONFIG_TRIGGERS
265/* vars for vnode trigger resolver */
266lck_grp_t * trigger_vnode_lck_grp;
267lck_grp_attr_t * trigger_vnode_lck_grp_attr;
268lck_attr_t * trigger_vnode_lck_attr;
269#endif
270
271/* vars for vnode list lock */
272lck_grp_t * vnode_list_lck_grp;
273lck_grp_attr_t * vnode_list_lck_grp_attr;
274lck_attr_t * vnode_list_lck_attr;
275lck_spin_t * vnode_list_spin_lock;
276lck_mtx_t * spechash_mtx_lock;
277
278/* vars for vfsconf lock */
279lck_grp_t * fsconf_lck_grp;
280lck_grp_attr_t * fsconf_lck_grp_attr;
281lck_attr_t * fsconf_lck_attr;
282
283
284/* vars for mount lock */
285lck_grp_t * mnt_lck_grp;
286lck_grp_attr_t * mnt_lck_grp_attr;
287lck_attr_t * mnt_lck_attr;
288
289/* vars for mount list lock */
290lck_grp_t * mnt_list_lck_grp;
291lck_grp_attr_t * mnt_list_lck_grp_attr;
292lck_attr_t * mnt_list_lck_attr;
293lck_mtx_t * mnt_list_mtx_lock;
294
295lck_mtx_t *pkg_extensions_lck;
296
297struct mount * dead_mountp;
298
299extern void nspace_handler_init(void);
300
301/*
302 * Initialize the vnode structures and initialize each file system type.
303 */
304void
305vfsinit(void)
306{
307	struct vfstable *vfsp;
308	int i, maxtypenum;
309	struct mount * mp;
310
311	/* Allocate vnode list lock group attribute and group */
312	vnode_list_lck_grp_attr = lck_grp_attr_alloc_init();
313
314	vnode_list_lck_grp = lck_grp_alloc_init("vnode list",  vnode_list_lck_grp_attr);
315
316	/* Allocate vnode list lock attribute */
317	vnode_list_lck_attr = lck_attr_alloc_init();
318
319	/* Allocate vnode list lock */
320	vnode_list_spin_lock = lck_spin_alloc_init(vnode_list_lck_grp, vnode_list_lck_attr);
321
322	/* Allocate spec hash list lock */
323	spechash_mtx_lock = lck_mtx_alloc_init(vnode_list_lck_grp, vnode_list_lck_attr);
324
325	/* Allocate the package extensions table lock */
326	pkg_extensions_lck = lck_mtx_alloc_init(vnode_list_lck_grp, vnode_list_lck_attr);
327
328	/* allocate vnode lock group attribute and group */
329	vnode_lck_grp_attr= lck_grp_attr_alloc_init();
330
331	vnode_lck_grp = lck_grp_alloc_init("vnode",  vnode_lck_grp_attr);
332
333	/* Allocate vnode lock attribute */
334	vnode_lck_attr = lck_attr_alloc_init();
335
336#if CONFIG_TRIGGERS
337	trigger_vnode_lck_grp_attr = lck_grp_attr_alloc_init();
338	trigger_vnode_lck_grp = lck_grp_alloc_init("trigger_vnode", trigger_vnode_lck_grp_attr);
339	trigger_vnode_lck_attr = lck_attr_alloc_init();
340#endif
341
342	/* Allocate fs config lock group attribute and group */
343	fsconf_lck_grp_attr= lck_grp_attr_alloc_init();
344
345	fsconf_lck_grp = lck_grp_alloc_init("fs conf",  fsconf_lck_grp_attr);
346
347	/* Allocate fs config lock attribute */
348	fsconf_lck_attr = lck_attr_alloc_init();
349
350	/* Allocate mount point related lock structures  */
351
352	/* Allocate mount list lock group attribute and group */
353	mnt_list_lck_grp_attr= lck_grp_attr_alloc_init();
354
355	mnt_list_lck_grp = lck_grp_alloc_init("mount list",  mnt_list_lck_grp_attr);
356
357	/* Allocate mount list lock attribute */
358	mnt_list_lck_attr = lck_attr_alloc_init();
359
360	/* Allocate mount list lock */
361	mnt_list_mtx_lock = lck_mtx_alloc_init(mnt_list_lck_grp, mnt_list_lck_attr);
362
363
364	/* allocate mount lock group attribute and group */
365	mnt_lck_grp_attr= lck_grp_attr_alloc_init();
366
367	mnt_lck_grp = lck_grp_alloc_init("mount",  mnt_lck_grp_attr);
368
369	/* Allocate mount lock attribute */
370	mnt_lck_attr = lck_attr_alloc_init();
371
372	/*
373	 * Initialize the vnode table
374	 */
375	vntblinit();
376	/*
377	 * Initialize the filesystem event mechanism.
378	 */
379	vfs_event_init();
380	/*
381	 * Initialize the vnode name cache
382	 */
383	nchinit();
384
385#if JOURNALING
386	/*
387	 * Initialize the journaling locks
388	 */
389	journal_init();
390#endif
391	nspace_handler_init();
392
393	/*
394	 * Build vnode operation vectors.
395	 */
396	vfs_op_init();
397	vfs_opv_init();   /* finish the job */
398	/*
399	 * Initialize each file system type in the static list,
400	 * until the first NULL ->vfs_vfsops is encountered.
401	 */
402	numused_vfsslots = maxtypenum = 0;
403	for (vfsp = vfsconf, i = 0; i < maxvfsslots; i++, vfsp++) {
404		struct vfsconf vfsc;
405		if (vfsp->vfc_vfsops == (struct	vfsops *)0)
406			break;
407		if (i) vfsconf[i-1].vfc_next = vfsp;
408		if (maxtypenum <= vfsp->vfc_typenum)
409			maxtypenum = vfsp->vfc_typenum + 1;
410
411		bzero(&vfsc, sizeof(struct vfsconf));
412		vfsc.vfc_reserved1 = 0;
413		bcopy(vfsp->vfc_name, vfsc.vfc_name, sizeof(vfsc.vfc_name));
414		vfsc.vfc_typenum = vfsp->vfc_typenum;
415		vfsc.vfc_refcount = vfsp->vfc_refcount;
416		vfsc.vfc_flags = vfsp->vfc_flags;
417		vfsc.vfc_reserved2 = 0;
418		vfsc.vfc_reserved3 = 0;
419
420		(*vfsp->vfc_vfsops->vfs_init)(&vfsc);
421
422		numused_vfsslots++;
423	}
424	/* next vfc_typenum to be used */
425	maxvfsconf = maxtypenum;
426
427	/*
428	 * Initialize the vnop authorization scope.
429	 */
430	vnode_authorize_init();
431
432	/*
433	 * Initialiize the quota system.
434	 */
435#if QUOTA
436	dqinit();
437#endif
438
439	/*
440	 * create a mount point for dead vnodes
441	 */
442	MALLOC_ZONE(mp, struct mount *, sizeof(struct mount),
443		M_MOUNT, M_WAITOK);
444	bzero((char *)mp, sizeof(struct mount));
445	/* Initialize the default IO constraints */
446	mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS;
447	mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32;
448	mp->mnt_maxsegreadsize = mp->mnt_maxreadcnt;
449	mp->mnt_maxsegwritesize = mp->mnt_maxwritecnt;
450	mp->mnt_devblocksize = DEV_BSIZE;
451	mp->mnt_alignmentmask = PAGE_MASK;
452	mp->mnt_ioqueue_depth = MNT_DEFAULT_IOQUEUE_DEPTH;
453	mp->mnt_ioscale = 1;
454	mp->mnt_ioflags = 0;
455	mp->mnt_realrootvp = NULLVP;
456	mp->mnt_authcache_ttl = CACHED_LOOKUP_RIGHT_TTL;
457
458	TAILQ_INIT(&mp->mnt_vnodelist);
459	TAILQ_INIT(&mp->mnt_workerqueue);
460	TAILQ_INIT(&mp->mnt_newvnodes);
461	mp->mnt_flag = MNT_LOCAL;
462	mp->mnt_lflag = MNT_LDEAD;
463	mount_lock_init(mp);
464
465#if CONFIG_MACF
466	mac_mount_label_init(mp);
467	mac_mount_label_associate(vfs_context_kernel(), mp);
468#endif
469	dead_mountp = mp;
470}
471
472void
473vnode_list_lock(void)
474{
475	lck_spin_lock(vnode_list_spin_lock);
476}
477
478void
479vnode_list_unlock(void)
480{
481	lck_spin_unlock(vnode_list_spin_lock);
482}
483
484void
485mount_list_lock(void)
486{
487	lck_mtx_lock(mnt_list_mtx_lock);
488}
489
490void
491mount_list_unlock(void)
492{
493	lck_mtx_unlock(mnt_list_mtx_lock);
494}
495
496void
497mount_lock_init(mount_t mp)
498{
499	lck_mtx_init(&mp->mnt_mlock, mnt_lck_grp, mnt_lck_attr);
500	lck_mtx_init(&mp->mnt_renamelock, mnt_lck_grp, mnt_lck_attr);
501	lck_rw_init(&mp->mnt_rwlock, mnt_lck_grp, mnt_lck_attr);
502}
503
504void
505mount_lock_destroy(mount_t mp)
506{
507	lck_mtx_destroy(&mp->mnt_mlock, mnt_lck_grp);
508	lck_mtx_destroy(&mp->mnt_renamelock, mnt_lck_grp);
509	lck_rw_destroy(&mp->mnt_rwlock, mnt_lck_grp);
510}
511
512
513/*
514 * Name:	vfstable_add
515 *
516 * Description:	Add a filesystem to the vfsconf list at the first
517 *		unused slot.  If no slots are available, return an
518 *		error.
519 *
520 * Parameter:	nvfsp		vfsconf for VFS to add
521 *
522 * Returns:	0		Success
523 *		-1		Failure
524 *
525 * Notes:	The vfsconf should be treated as a linked list by
526 *		all external references, as the implementation is
527 *		expected to change in the future.  The linkage is
528 *		through ->vfc_next, and the list is NULL terminated.
529 *
530 * Warning:	This code assumes that vfsconf[0] is non-empty.
531 */
532struct vfstable *
533vfstable_add(struct vfstable  *nvfsp)
534{
535	int slot;
536	struct vfstable *slotp, *allocated = NULL;
537
538	/*
539	 * Find the next empty slot; we recognize an empty slot by a
540	 * NULL-valued ->vfc_vfsops, so if we delete a VFS, we must
541	 * ensure we set the entry back to NULL.
542	 */
543findslot:
544	mount_list_lock();
545	for (slot = 0; slot < maxvfsslots; slot++) {
546		if (vfsconf[slot].vfc_vfsops == NULL)
547			break;
548	}
549	if (slot == maxvfsslots) {
550		if (allocated == NULL) {
551			mount_list_unlock();
552			/* out of static slots; allocate one instead */
553			MALLOC(allocated, struct vfstable *, sizeof(struct vfstable),
554					M_TEMP, M_WAITOK);
555			goto findslot;
556		} else {
557			slotp = allocated;
558			allocated = NULL;
559		}
560	} else {
561		slotp = &vfsconf[slot];
562	}
563
564	/*
565	 * Replace the contents of the next empty slot with the contents
566	 * of the provided nvfsp.
567	 *
568	 * Note; Takes advantage of the fact that 'slot' was left
569	 * with the value of 'maxvfslots' in the allocation case.
570	 */
571	bcopy(nvfsp, slotp, sizeof(struct vfstable));
572	if (slot != 0) {
573		slotp->vfc_next = vfsconf[slot - 1].vfc_next;
574		vfsconf[slot - 1].vfc_next = slotp;
575	} else {
576		slotp->vfc_next = NULL;
577	}
578	numused_vfsslots++;
579
580	mount_list_unlock();
581
582	if (allocated != NULL) {
583		FREE(allocated, M_TEMP);
584	}
585
586	return(slotp);
587}
588
589/*
590 * Name:	vfstable_del
591 *
592 * Description:	Remove a filesystem from the vfsconf list by name.
593 *		If no such filesystem exists, return an error.
594 *
595 * Parameter:	fs_name		name of VFS to remove
596 *
597 * Returns:	0		Success
598 *		-1		Failure
599 *
600 * Notes:	Hopefully all filesystems have unique names.
601 */
602int
603vfstable_del(struct vfstable  * vtbl)
604{
605	struct vfstable **vcpp;
606	struct vfstable *vcdelp;
607
608#if DEBUG
609	lck_mtx_assert(mnt_list_mtx_lock, LCK_MTX_ASSERT_OWNED);
610#endif /* DEBUG */
611
612	/*
613	 * Traverse the list looking for vtbl; if found, *vcpp
614	 * will contain the address of the pointer to the entry to
615	 * be removed.
616	 */
617	for( vcpp = &vfsconf; *vcpp; vcpp = &(*vcpp)->vfc_next) {
618		if (*vcpp == vtbl)
619            break;
620        }
621
622	if (*vcpp == NULL)
623	   return(ESRCH);	/* vtbl not on vfsconf list */
624
625	/* Unlink entry */
626	vcdelp = *vcpp;
627	*vcpp = (*vcpp)->vfc_next;
628
629	/*
630	 * Is this an entry from our static table?  We find out by
631	 * seeing if the pointer to the object to be deleted places
632	 * the object in the address space containing the table (or not).
633	 */
634	if (vcdelp >= vfsconf && vcdelp < (vfsconf + maxvfsslots)) {	/* Y */
635		/* Mark as empty for vfscon_add() */
636		bzero(vcdelp, sizeof(struct vfstable));
637		numused_vfsslots--;
638	} else {							/* N */
639		/*
640		 * This entry was dynamically allocated; we must free it;
641		 * we would prefer to have just linked the caller's
642		 * vfsconf onto our list, but it may not be persistent
643		 * because of the previous (copying) implementation.
644		 */
645		mount_list_unlock();
646		FREE(vcdelp, M_TEMP);
647		mount_list_lock();
648	}
649
650#if DEBUG
651	lck_mtx_assert(mnt_list_mtx_lock, LCK_MTX_ASSERT_OWNED);
652#endif /* DEBUG */
653
654	return(0);
655}
656
657void
658SPECHASH_LOCK(void)
659{
660	lck_mtx_lock(spechash_mtx_lock);
661}
662
663void
664SPECHASH_UNLOCK(void)
665{
666	lck_mtx_unlock(spechash_mtx_lock);
667}
668
669