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