The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/hfs/hfs_vfsops.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    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
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   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.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /*
   26  * Copyright (c) 1991, 1993, 1994
   27  *      The Regents of the University of California.  All rights reserved.
   28  * (c) UNIX System Laboratories, Inc.
   29  * All or some portions of this file are derived from material licensed
   30  * to the University of California by American Telephone and Telegraph
   31  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   32  * the permission of UNIX System Laboratories, Inc.
   33  *
   34  * Redistribution and use in source and binary forms, with or without
   35  * modification, are permitted provided that the following conditions
   36  * are met:
   37  * 1. Redistributions of source code must retain the above copyright
   38  *    notice, this list of conditions and the following disclaimer.
   39  * 2. Redistributions in binary form must reproduce the above copyright
   40  *    notice, this list of conditions and the following disclaimer in the
   41  *    documentation and/or other materials provided with the distribution.
   42  * 3. All advertising materials mentioning features or use of this software
   43  *    must display the following acknowledgement:
   44  *      This product includes software developed by the University of
   45  *      California, Berkeley and its contributors.
   46  * 4. Neither the name of the University nor the names of its contributors
   47  *    may be used to endorse or promote products derived from this software
   48  *    without specific prior written permission.
   49  *
   50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   60  * SUCH DAMAGE.
   61  *
   62  *      hfs_vfsops.c
   63  *  derived from        @(#)ufs_vfsops.c        8.8 (Berkeley) 5/20/95
   64  *
   65  *      (c) Copyright 1997-2002 Apple Computer, Inc. All rights reserved.
   66  *
   67  *      hfs_vfsops.c -- VFS layer for loadable HFS file system.
   68  *
   69  */
   70 #include <sys/param.h>
   71 #include <sys/systm.h>
   72 
   73 #include <sys/ubc.h>
   74 #include <sys/namei.h>
   75 #include <sys/vnode.h>
   76 #include <sys/mount.h>
   77 #include <sys/sysctl.h>
   78 #include <sys/malloc.h>
   79 #include <sys/stat.h>
   80 #include <sys/lock.h>
   81 #include <sys/quota.h>
   82 #include <sys/disk.h>
   83 #include <sys/paths.h>
   84 #include <sys/utfconv.h>
   85 
   86 // XXXdbg
   87 #include <vfs/vfs_journal.h>
   88 
   89 #include <miscfs/specfs/specdev.h>
   90 #include <hfs/hfs_mount.h>
   91 
   92 #include "hfs.h"
   93 #include "hfs_catalog.h"
   94 #include "hfs_cnode.h"
   95 #include "hfs_dbg.h"
   96 #include "hfs_endian.h"
   97 #include "hfs_quota.h"
   98 
   99 #include "hfscommon/headers/FileMgrInternal.h"
  100 #include "hfscommon/headers/BTreesInternal.h"
  101 
  102 
  103 #if     HFS_DIAGNOSTIC
  104 int hfs_dbg_all = 0;
  105 int hfs_dbg_err = 0;
  106 #endif
  107 
  108 
  109 extern struct vnodeopv_desc hfs_vnodeop_opv_desc;
  110 
  111 extern void hfs_converterinit(void);
  112 
  113 extern void inittodr( time_t base);
  114 
  115 
  116 static int hfs_changefs __P((struct mount *mp, struct hfs_mount_args *args,
  117                 struct proc *p));
  118 static int hfs_reload __P((struct mount *mp, struct ucred *cred, struct proc *p));
  119 
  120 static int hfs_mountfs __P((struct vnode *devvp, struct mount *mp, struct proc *p,
  121                 struct hfs_mount_args *args));
  122 static int hfs_statfs __P((struct mount *mp, register struct statfs *sbp,
  123                 struct proc *p));
  124 static int hfs_flushfiles __P((struct mount *, int, struct proc *));
  125 
  126 static int hfs_extendfs __P((struct mount *, u_int64_t, struct proc *));
  127 
  128 /*
  129  * Called by vfs_mountroot when mounting HFS Plus as root.
  130  */
  131 __private_extern__
  132 int
  133 hfs_mountroot()
  134 {
  135         extern struct vnode *rootvp;
  136         struct mount *mp;
  137         struct proc *p = current_proc();        /* XXX */
  138         struct hfsmount *hfsmp;
  139         ExtendedVCB *vcb;
  140         int error;
  141         
  142         /*
  143          * Get vnode for rootdev.
  144          */
  145         if ((error = bdevvp(rootdev, &rootvp))) {
  146                 printf("hfs_mountroot: can't setup bdevvp");
  147                 return (error);
  148         }
  149         if ((error = vfs_rootmountalloc("hfs", "root_device", &mp))) {
  150                 vrele(rootvp); /* release the reference from bdevvp() */
  151                 return (error);
  152         }
  153         if ((error = hfs_mountfs(rootvp, mp, p, NULL))) {
  154                 mp->mnt_vfc->vfc_refcount--;
  155 
  156                 if (mp->mnt_kern_flag & MNTK_IO_XINFO)
  157                         FREE(mp->mnt_xinfo_ptr, M_TEMP);
  158                 vfs_unbusy(mp, p);
  159 
  160                 vrele(rootvp); /* release the reference from bdevvp() */
  161                 FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
  162                 return (error);
  163         }
  164         simple_lock(&mountlist_slock);
  165         CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
  166         simple_unlock(&mountlist_slock);
  167         
  168         /* Init hfsmp */
  169         hfsmp = VFSTOHFS(mp);
  170 
  171         hfsmp->hfs_uid = UNKNOWNUID;
  172         hfsmp->hfs_gid = UNKNOWNGID;
  173         hfsmp->hfs_dir_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */
  174         hfsmp->hfs_file_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */
  175 
  176         /* Establish the free block reserve. */
  177         vcb = HFSTOVCB(hfsmp);
  178         vcb->reserveBlocks = ((u_int64_t)vcb->totalBlocks * HFS_MINFREE) / 100;
  179         vcb->reserveBlocks = MIN(vcb->reserveBlocks, HFS_MAXRESERVE / vcb->blockSize);
  180 
  181         (void)hfs_statfs(mp, &mp->mnt_stat, p);
  182         
  183         vfs_unbusy(mp, p);
  184         inittodr(HFSTOVCB(hfsmp)->vcbLsMod);
  185         return (0);
  186 }
  187 
  188 
  189 /*
  190  * VFS Operations.
  191  *
  192  * mount system call
  193  */
  194 
  195 static int
  196 hfs_mount(mp, path, data, ndp, p)
  197         register struct mount *mp;
  198         char *path;
  199         caddr_t data;
  200         struct nameidata *ndp;
  201         struct proc *p;
  202 {
  203         struct hfsmount *hfsmp = NULL;
  204         struct vnode *devvp;
  205         struct hfs_mount_args args;
  206         size_t size;
  207         int retval = E_NONE;
  208         int flags;
  209         mode_t accessmode;
  210 
  211         if ((retval = copyin(data, (caddr_t)&args, sizeof(args))))
  212                 goto error_exit;
  213 
  214         /*
  215          * If updating, check whether changing from read-only to
  216          * read/write; if there is no device name, that's all we do.
  217          */
  218         if (mp->mnt_flag & MNT_UPDATE) {
  219                 
  220                 hfsmp = VFSTOHFS(mp);
  221                 if (((hfsmp->hfs_flags & HFS_READ_ONLY) == 0) &&
  222                     (mp->mnt_flag & MNT_RDONLY)) {
  223                 
  224                         /* use VFS_SYNC to push out System (btree) files */
  225                         retval = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p);
  226                         if (retval && ((mp->mnt_flag & MNT_FORCE) == 0))
  227                                 goto error_exit;
  228                 
  229                         flags = WRITECLOSE;
  230                         if (mp->mnt_flag & MNT_FORCE)
  231                                 flags |= FORCECLOSE;
  232                                 
  233                         if ((retval = hfs_flushfiles(mp, flags, p)))
  234                                 goto error_exit;
  235                         hfsmp->hfs_flags |= HFS_READ_ONLY;
  236                         retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
  237 
  238                         /* also get the volume bitmap blocks */
  239                         if (!retval)
  240                                 retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p);
  241 
  242                         if (retval) {
  243                                 hfsmp->hfs_flags &= ~HFS_READ_ONLY;
  244                                 goto error_exit;
  245                         }
  246 
  247                         if (hfsmp->jnl) {
  248                             hfs_global_exclusive_lock_acquire(hfsmp);
  249 
  250                             journal_close(hfsmp->jnl);
  251                             hfsmp->jnl = NULL;
  252 
  253                             // Note: we explicitly don't want to shutdown
  254                             //       access to the jvp because we may need
  255                             //       it later if we go back to being read-write.
  256 
  257                             hfs_global_exclusive_lock_release(hfsmp);
  258                         }
  259                 }
  260 
  261                 if ((mp->mnt_flag & MNT_RELOAD) &&
  262                         (retval = hfs_reload(mp, ndp->ni_cnd.cn_cred, p)))
  263                         goto error_exit;
  264 
  265                 if ((hfsmp->hfs_flags & HFS_READ_ONLY) &&
  266                     (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
  267                         /*
  268                          * If upgrade to read-write by non-root, then verify
  269                          * that user has necessary permissions on the device.
  270                          */
  271                         if (p->p_ucred->cr_uid != 0) {
  272                                 devvp = hfsmp->hfs_devvp;
  273                                 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
  274                                 if ((retval = VOP_ACCESS(devvp, VREAD | VWRITE, p->p_ucred, p))) {
  275                                         VOP_UNLOCK(devvp, 0, p);
  276                                         goto error_exit;
  277                                 }
  278                                 VOP_UNLOCK(devvp, 0, p);
  279                         }
  280                         retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
  281         
  282                         if (retval != E_NONE)
  283                                 goto error_exit;
  284 
  285                         // If the journal was shut-down previously because we were
  286                         // asked to be read-only, let's start it back up again now
  287                         
  288                         if (   (HFSTOVCB(hfsmp)->vcbAtrb & kHFSVolumeJournaledMask)
  289                             && hfsmp->jnl == NULL
  290                             && hfsmp->jvp != NULL) {
  291                             int flags;
  292 
  293                             if (hfsmp->hfs_flags & HFS_NEED_JNL_RESET) {
  294                                 flags = JOURNAL_RESET;
  295                             } else {
  296                                 flags = 0;
  297                             }
  298                             
  299                             hfs_global_exclusive_lock_acquire(hfsmp);
  300 
  301                             hfsmp->jnl = journal_open(hfsmp->jvp,
  302                                                       (hfsmp->jnl_start * HFSTOVCB(hfsmp)->blockSize) + (off_t)HFSTOVCB(hfsmp)->hfsPlusIOPosOffset,
  303                                                       hfsmp->jnl_size,
  304                                                       hfsmp->hfs_devvp,
  305                                                       hfsmp->hfs_phys_block_size,
  306                                                       flags,
  307                                                       0,
  308                                                       hfs_sync_metadata, hfsmp->hfs_mp);
  309 
  310                             hfs_global_exclusive_lock_release(hfsmp);
  311 
  312                             if (hfsmp->jnl == NULL) {
  313                                 retval = EINVAL;
  314                                 goto error_exit;
  315                             } else {
  316                                 hfsmp->hfs_flags &= ~HFS_NEED_JNL_RESET;
  317                             }
  318 
  319                         }
  320 
  321                         /* Only clear HFS_READ_ONLY after a successfull write */
  322                         hfsmp->hfs_flags &= ~HFS_READ_ONLY;
  323                 }
  324 
  325                 if (((hfsmp->hfs_flags & HFS_READ_ONLY) == 0) &&
  326                     (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)) {
  327                         /* setup private/hidden directory for unlinked files */
  328                         FindMetaDataDirectory(HFSTOVCB(hfsmp));
  329                         if (hfsmp->jnl)
  330                                 hfs_remove_orphans(hfsmp);
  331                         
  332                         /*
  333                          * Allow hot file clustering if conditions allow.
  334                          */
  335                         if ((hfsmp->hfs_flags & HFS_METADATA_ZONE) &&
  336                             (mp->mnt_flag & MNT_RDONLY) &&
  337                             (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
  338                                 (void) hfs_recording_init(hfsmp, p);
  339                         }
  340                 }
  341 
  342                 if (args.fspec == 0) {
  343                         /*
  344                          * Process export requests.
  345                          */
  346                         return vfs_export(mp, &hfsmp->hfs_export, &args.export);
  347                 }
  348         }
  349 
  350         /*
  351          * Not an update, or updating the name: look up the name
  352          * and verify that it refers to a sensible block device.
  353          */
  354         NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
  355         retval = namei(ndp);
  356         if (retval != E_NONE) {
  357                 DBG_ERR(("hfs_mount: CAN'T GET DEVICE: %s, %x\n", args.fspec, ndp->ni_vp->v_rdev));
  358                 goto error_exit;
  359         }
  360 
  361         devvp = ndp->ni_vp;
  362 
  363         if (devvp->v_type != VBLK) {
  364                 vrele(devvp);
  365                 retval = ENOTBLK;
  366                 goto error_exit;
  367         }
  368         if (major(devvp->v_rdev) >= nblkdev) {
  369                 vrele(devvp);
  370                 retval = ENXIO;
  371                 goto error_exit;
  372         }
  373 
  374         /*
  375          * If mount by non-root, then verify that user has necessary
  376          * permissions on the device.
  377          */
  378         if (p->p_ucred->cr_uid != 0) {
  379                 accessmode = VREAD;
  380                 if ((mp->mnt_flag & MNT_RDONLY) == 0)
  381                         accessmode |= VWRITE;
  382                 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
  383                 if ((retval = VOP_ACCESS(devvp, accessmode, p->p_ucred, p))) {
  384                         vput(devvp);
  385                         goto error_exit;
  386                 }
  387                 VOP_UNLOCK(devvp, 0, p);
  388         }
  389 
  390         if ((mp->mnt_flag & MNT_UPDATE) == 0) {
  391                 retval = hfs_mountfs(devvp, mp, p, &args);
  392                 if (retval != E_NONE)
  393                         vrele(devvp);
  394         } else {
  395                 if (devvp != hfsmp->hfs_devvp)
  396                         retval = EINVAL;        /* needs translation */
  397                 else
  398                         retval = hfs_changefs(mp, &args, p);
  399                 vrele(devvp);
  400         }
  401 
  402         if (retval != E_NONE) {
  403                 goto error_exit;
  404         }
  405 
  406         /* Set the mount flag to indicate that we support volfs  */
  407         mp->mnt_flag |= MNT_DOVOLFS;
  408     if (VFSTOVCB(mp)->vcbSigWord == kHFSSigWord) {
  409         /* HFS volumes only want roman-encoded names: */
  410         mp->mnt_flag |= MNT_FIXEDSCRIPTENCODING;
  411     }
  412         (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN-1, &size);
  413 
  414         bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
  415         (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
  416         bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
  417         (void)hfs_statfs(mp, &mp->mnt_stat, p);
  418         return (E_NONE);
  419 
  420 error_exit:
  421 
  422         return (retval);
  423 }
  424 
  425 
  426 /* Change fs mount parameters */
  427 static int
  428 hfs_changefs(mp, args, p)
  429         struct mount *mp;
  430         struct hfs_mount_args *args;
  431         struct proc *p;
  432 {
  433         int retval = 0;
  434         int namefix, permfix, permswitch;
  435         struct hfsmount *hfsmp;
  436         struct cnode *cp;
  437         ExtendedVCB *vcb;
  438         register struct vnode *vp, *nvp;
  439         hfs_to_unicode_func_t   get_unicode_func;
  440         unicode_to_hfs_func_t   get_hfsname_func;
  441         struct cat_desc cndesc;
  442         struct cat_attr cnattr;
  443         u_long old_encoding;
  444 
  445         hfsmp = VFSTOHFS(mp);
  446         vcb = HFSTOVCB(hfsmp);
  447         permswitch = (((hfsmp->hfs_flags & HFS_UNKNOWN_PERMS) &&
  448                        ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) == 0)) ||
  449                       (((hfsmp->hfs_flags & HFS_UNKNOWN_PERMS) == 0) &&
  450                        (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS)));
  451 
  452         /* The root filesystem must operate with actual permissions: */
  453         if (permswitch && (mp->mnt_flag & MNT_ROOTFS) && (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS)) {
  454                 mp->mnt_flag &= ~MNT_UNKNOWNPERMISSIONS;        /* Just say "No". */
  455                 return EINVAL;
  456         }
  457         if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS)
  458                 hfsmp->hfs_flags |= HFS_UNKNOWN_PERMS;
  459         else
  460                 hfsmp->hfs_flags &= ~HFS_UNKNOWN_PERMS;
  461 
  462         namefix = permfix = 0;
  463 
  464         /* Change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */
  465         if (args->hfs_timezone.tz_minuteswest != VNOVAL) {
  466                 gTimeZone = args->hfs_timezone;
  467         }
  468 
  469         /* Change the default uid, gid and/or mask */
  470         if ((args->hfs_uid != (uid_t)VNOVAL) && (hfsmp->hfs_uid != args->hfs_uid)) {
  471                 hfsmp->hfs_uid = args->hfs_uid;
  472                 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
  473                         ++permfix;
  474         }
  475         if ((args->hfs_gid != (gid_t)VNOVAL) && (hfsmp->hfs_gid != args->hfs_gid)) {
  476                 hfsmp->hfs_gid = args->hfs_gid;
  477                 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
  478                         ++permfix;
  479         }
  480         if (args->hfs_mask != (mode_t)VNOVAL) {
  481                 if (hfsmp->hfs_dir_mask != (args->hfs_mask & ALLPERMS)) {
  482                         hfsmp->hfs_dir_mask = args->hfs_mask & ALLPERMS;
  483                         hfsmp->hfs_file_mask = args->hfs_mask & ALLPERMS;
  484                         if ((args->flags != VNOVAL) && (args->flags & HFSFSMNT_NOXONFILES))
  485                                 hfsmp->hfs_file_mask = (args->hfs_mask & DEFFILEMODE);
  486                         if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
  487                                 ++permfix;
  488                 }
  489         }
  490         
  491         /* Change the hfs encoding value (hfs only) */
  492         if ((HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord)        &&
  493             (args->hfs_encoding != (u_long)VNOVAL)              &&
  494             (hfsmp->hfs_encoding != args->hfs_encoding)) {
  495 
  496                 retval = hfs_getconverter(args->hfs_encoding, &get_unicode_func, &get_hfsname_func);
  497                 if (retval)
  498                         goto exit;
  499 
  500                 /*
  501                  * Connect the new hfs_get_unicode converter but leave
  502                  * the old hfs_get_hfsname converter in place so that
  503                  * we can lookup existing vnodes to get their correctly
  504                  * encoded names.
  505                  *
  506                  * When we're all finished, we can then connect the new
  507                  * hfs_get_hfsname converter and release our interest
  508                  * in the old converters.
  509                  */
  510                 hfsmp->hfs_get_unicode = get_unicode_func;
  511                 old_encoding = hfsmp->hfs_encoding;
  512                 hfsmp->hfs_encoding = args->hfs_encoding;
  513                 ++namefix;
  514         }
  515 
  516         if (!(namefix || permfix || permswitch))
  517                 goto exit;
  518 
  519         /*
  520          * For each active vnode fix things that changed
  521          *
  522          * Note that we can visit a vnode more than once
  523          * and we can race with fsync.
  524          */
  525         simple_lock(&mntvnode_slock);
  526 loop:
  527         for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
  528                 /*
  529                  * If the vnode that we are about to fix is no longer
  530                  * associated with this mount point, start over.
  531                  */
  532                 if (vp->v_mount != mp)
  533                     goto loop;
  534          
  535                 simple_lock(&vp->v_interlock);
  536                 nvp = vp->v_mntvnodes.le_next;
  537                 if (vp->v_flag & VSYSTEM) {
  538                         simple_unlock(&vp->v_interlock);
  539                         continue;
  540                 }
  541                 simple_unlock(&mntvnode_slock);
  542                 retval = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
  543                 if (retval) {
  544                     simple_lock(&mntvnode_slock);
  545                     if (retval == ENOENT)
  546                         goto loop;
  547                     continue;
  548                 }
  549         
  550                 cp = VTOC(vp);
  551 
  552                 retval = cat_lookup(hfsmp, &cp->c_desc, 0, &cndesc, &cnattr, NULL);
  553                 /* If we couldn't find this guy skip to the next one */
  554                 if (retval) {
  555                         if (namefix)
  556                                 cache_purge(vp);
  557                         vput(vp);
  558                         simple_lock(&mntvnode_slock);
  559                         continue;
  560                 }
  561 
  562                 /* Get the real uid/gid and perm mask from disk. */
  563                 if (permswitch || permfix) {
  564                         cp->c_uid = cnattr.ca_uid;
  565                         cp->c_gid = cnattr.ca_gid;
  566                         cp->c_mode = cnattr.ca_mode;
  567                 }
  568                 
  569                 /*
  570                  * If we're switching name converters then...
  571                  *   Remove the existing entry from the namei cache.
  572                  *   Update name to one based on new encoder.
  573                  */
  574                 if (namefix) {
  575                         cache_purge(vp);
  576                         replace_desc(cp, &cndesc);
  577 
  578                         if (cndesc.cd_cnid == kHFSRootFolderID) {
  579                                 strncpy(vcb->vcbVN, cp->c_desc.cd_nameptr, NAME_MAX);
  580                                 cp->c_desc.cd_encoding = hfsmp->hfs_encoding;
  581                         }
  582                 } else {
  583                         cat_releasedesc(&cndesc);
  584                 }
  585                 vput(vp);
  586                 simple_lock(&mntvnode_slock);
  587 
  588         } /* end for (vp...) */
  589         simple_unlock(&mntvnode_slock);
  590         /*
  591          * If we're switching name converters we can now
  592          * connect the new hfs_get_hfsname converter and
  593          * release our interest in the old converters.
  594          */
  595         if (namefix) {
  596                 hfsmp->hfs_get_hfsname = get_hfsname_func;
  597                 vcb->volumeNameEncodingHint = args->hfs_encoding;
  598                 (void) hfs_relconverter(old_encoding);
  599         }
  600 exit:
  601         return (retval);
  602 }
  603 
  604 
  605 /*
  606  * Reload all incore data for a filesystem (used after running fsck on
  607  * the root filesystem and finding things to fix). The filesystem must
  608  * be mounted read-only.
  609  *
  610  * Things to do to update the mount:
  611  *      invalidate all cached meta-data.
  612  *      invalidate all inactive vnodes.
  613  *      invalidate all cached file data.
  614  *      re-read volume header from disk.
  615  *      re-load meta-file info (extents, file size).
  616  *      re-load B-tree header data.
  617  *      re-read cnode data for all active vnodes.
  618  */
  619 static int
  620 hfs_reload(mountp, cred, p)
  621         register struct mount *mountp;
  622         struct ucred *cred;
  623         struct proc *p;
  624 {
  625         register struct vnode *vp, *nvp, *devvp;
  626         struct cnode *cp;
  627         struct buf *bp;
  628         int sectorsize;
  629         int error, i;
  630         struct hfsmount *hfsmp;
  631         struct HFSPlusVolumeHeader *vhp;
  632         ExtendedVCB *vcb;
  633         struct filefork *forkp;
  634         struct cat_desc cndesc;
  635 
  636         if ((mountp->mnt_flag & MNT_RDONLY) == 0)
  637                 return (EINVAL);
  638 
  639         hfsmp = VFSTOHFS(mountp);
  640         vcb = HFSTOVCB(hfsmp);
  641 
  642         if (vcb->vcbSigWord == kHFSSigWord)
  643                 return (EINVAL);        /* rooting from HFS is not supported! */
  644 
  645         /*
  646          * Invalidate all cached meta-data.
  647          */
  648         devvp = hfsmp->hfs_devvp;
  649         if (vinvalbuf(devvp, 0, cred, p, 0, 0))
  650                 panic("hfs_reload: dirty1");
  651         InvalidateCatalogCache(vcb);
  652 
  653 loop:
  654         simple_lock(&mntvnode_slock);
  655         for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
  656                 if (vp->v_mount != mountp) {
  657                         simple_unlock(&mntvnode_slock);
  658                         goto loop;
  659                 }
  660                 nvp = vp->v_mntvnodes.le_next;
  661 
  662                 /*
  663                  * Invalidate all inactive vnodes.
  664                  */
  665                 if (vrecycle(vp, &mntvnode_slock, p))
  666                         goto loop;
  667 
  668                 /*
  669                  * Invalidate all cached file data.
  670                  */
  671                 simple_lock(&vp->v_interlock);
  672                 simple_unlock(&mntvnode_slock);
  673                 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) {
  674                         goto loop;
  675                 }
  676                 if (vinvalbuf(vp, 0, cred, p, 0, 0))
  677                         panic("hfs_reload: dirty2");
  678 
  679                 /*
  680                  * Re-read cnode data for all active vnodes (non-metadata files).
  681                  */
  682                 cp = VTOC(vp);
  683                 if ((vp->v_flag & VSYSTEM) == 0 && !VNODE_IS_RSRC(vp)) {
  684                         struct cat_fork *datafork;
  685                         struct cat_desc desc;
  686 
  687                         datafork = cp->c_datafork ? &cp->c_datafork->ff_data : NULL;
  688 
  689                         /* lookup by fileID since name could have changed */
  690                         if ((error = cat_idlookup(hfsmp, cp->c_fileid, &desc, &cp->c_attr, datafork))) {
  691                                 vput(vp);
  692                                 return (error);
  693                         }
  694 
  695                         /* update cnode's catalog descriptor */
  696                         (void) replace_desc(cp, &desc);
  697                 }
  698                 vput(vp);
  699                 simple_lock(&mntvnode_slock);
  700         }
  701         simple_unlock(&mntvnode_slock);
  702 
  703         /*
  704          * Re-read VolumeHeader from disk.
  705          */
  706         sectorsize = hfsmp->hfs_phys_block_size;
  707 
  708         error = meta_bread(hfsmp->hfs_devvp,
  709                         (vcb->hfsPlusIOPosOffset / sectorsize) + HFS_PRI_SECTOR(sectorsize),
  710                         sectorsize, NOCRED, &bp);
  711         if (error) {
  712                 if (bp != NULL)
  713                         brelse(bp);
  714                 return (error);
  715         }
  716 
  717         vhp = (HFSPlusVolumeHeader *) (bp->b_data + HFS_PRI_OFFSET(sectorsize));
  718 
  719         /* Do a quick sanity check */
  720         if ((SWAP_BE16(vhp->signature) != kHFSPlusSigWord &&
  721              SWAP_BE16(vhp->signature) != kHFSXSigWord) ||
  722             (SWAP_BE16(vhp->version) != kHFSPlusVersion &&
  723              SWAP_BE16(vhp->version) != kHFSXVersion) ||
  724             SWAP_BE32(vhp->blockSize) != vcb->blockSize) {
  725                 brelse(bp);
  726                 return (EIO);
  727         }
  728 
  729         vcb->vcbLsMod           = to_bsd_time(SWAP_BE32(vhp->modifyDate));
  730         vcb->vcbAtrb            = (UInt16) SWAP_BE32 (vhp->attributes); /* VCB only uses lower 16 bits */
  731         vcb->vcbJinfoBlock  = SWAP_BE32(vhp->journalInfoBlock);
  732         vcb->vcbClpSiz          = SWAP_BE32 (vhp->rsrcClumpSize);
  733         vcb->vcbNxtCNID         = SWAP_BE32 (vhp->nextCatalogID);
  734         vcb->vcbVolBkUp         = to_bsd_time(SWAP_BE32(vhp->backupDate));
  735         vcb->vcbWrCnt           = SWAP_BE32 (vhp->writeCount);
  736         vcb->vcbFilCnt          = SWAP_BE32 (vhp->fileCount);
  737         vcb->vcbDirCnt          = SWAP_BE32 (vhp->folderCount);
  738         vcb->nextAllocation     = SWAP_BE32 (vhp->nextAllocation);
  739         vcb->totalBlocks        = SWAP_BE32 (vhp->totalBlocks);
  740         vcb->freeBlocks         = SWAP_BE32 (vhp->freeBlocks);
  741         vcb->encodingsBitmap    = SWAP_BE64 (vhp->encodingsBitmap);
  742         bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo));    
  743         vcb->localCreateDate    = SWAP_BE32 (vhp->createDate); /* hfs+ create date is in local time */ 
  744 
  745         /*
  746          * Re-load meta-file vnode data (extent info, file size, etc).
  747          */
  748         forkp = VTOF((struct vnode *)vcb->extentsRefNum);
  749         for (i = 0; i < kHFSPlusExtentDensity; i++) {
  750                 forkp->ff_extents[i].startBlock =
  751                         SWAP_BE32 (vhp->extentsFile.extents[i].startBlock);
  752                 forkp->ff_extents[i].blockCount =
  753                         SWAP_BE32 (vhp->extentsFile.extents[i].blockCount);
  754         }
  755         forkp->ff_size      = SWAP_BE64 (vhp->extentsFile.logicalSize);
  756         forkp->ff_blocks    = SWAP_BE32 (vhp->extentsFile.totalBlocks);
  757         forkp->ff_clumpsize = SWAP_BE32 (vhp->extentsFile.clumpSize);
  758 
  759 
  760         forkp = VTOF((struct vnode *)vcb->catalogRefNum);
  761         for (i = 0; i < kHFSPlusExtentDensity; i++) {
  762                 forkp->ff_extents[i].startBlock =
  763                         SWAP_BE32 (vhp->catalogFile.extents[i].startBlock);
  764                 forkp->ff_extents[i].blockCount =
  765                         SWAP_BE32 (vhp->catalogFile.extents[i].blockCount);
  766         }
  767         forkp->ff_size      = SWAP_BE64 (vhp->catalogFile.logicalSize);
  768         forkp->ff_blocks    = SWAP_BE32 (vhp->catalogFile.totalBlocks);
  769         forkp->ff_clumpsize = SWAP_BE32 (vhp->catalogFile.clumpSize);
  770 
  771 
  772         forkp = VTOF((struct vnode *)vcb->allocationsRefNum);
  773         for (i = 0; i < kHFSPlusExtentDensity; i++) {
  774                 forkp->ff_extents[i].startBlock =
  775                         SWAP_BE32 (vhp->allocationFile.extents[i].startBlock);
  776                 forkp->ff_extents[i].blockCount =
  777                         SWAP_BE32 (vhp->allocationFile.extents[i].blockCount);
  778         }
  779         forkp->ff_size      = SWAP_BE64 (vhp->allocationFile.logicalSize);
  780         forkp->ff_blocks    = SWAP_BE32 (vhp->allocationFile.totalBlocks);
  781         forkp->ff_clumpsize = SWAP_BE32 (vhp->allocationFile.clumpSize);
  782 
  783         brelse(bp);
  784         vhp = NULL;
  785 
  786         /*
  787          * Re-load B-tree header data
  788          */
  789         forkp = VTOF((struct vnode *)vcb->extentsRefNum);
  790         if (error = MacToVFSError( BTReloadData((FCB*)forkp) ))
  791                 return (error);
  792 
  793         forkp = VTOF((struct vnode *)vcb->catalogRefNum);
  794         if (error = MacToVFSError( BTReloadData((FCB*)forkp) ))
  795                 return (error);
  796 
  797         /* Reload the volume name */
  798         if ((error = cat_idlookup(hfsmp, kHFSRootFolderID, &cndesc, NULL, NULL)))
  799                 return (error);
  800         vcb->volumeNameEncodingHint = cndesc.cd_encoding;
  801         bcopy(cndesc.cd_nameptr, vcb->vcbVN, min(255, cndesc.cd_namelen));
  802         cat_releasedesc(&cndesc);
  803 
  804         /* Re-establish private/hidden directory for unlinked files */
  805         FindMetaDataDirectory(vcb);
  806 
  807         /* In case any volume information changed to trigger a notification */
  808         hfs_generate_volume_notifications(hfsmp);
  809     
  810         return (0);
  811 }
  812 
  813 
  814 static int
  815 get_raw_device(char *fspec, int is_user, int ronly, struct vnode **rvp, struct ucred *cred, struct proc *p)
  816 {
  817         char            *rawbuf;
  818         char            *dp;
  819         size_t           namelen;
  820         struct nameidata nd;
  821         int               retval;
  822 
  823         *rvp = NULL;
  824 
  825         MALLOC(rawbuf, char *, MAXPATHLEN, M_HFSMNT, M_WAITOK);
  826         if (rawbuf == NULL) {
  827                 retval = ENOMEM;
  828                 goto error_exit;
  829         }
  830 
  831         if (is_user) {
  832                 retval = copyinstr(fspec, rawbuf, MAXPATHLEN - 1, &namelen);
  833                 if (retval != E_NONE) {
  834                         FREE(rawbuf, M_HFSMNT);
  835                         goto error_exit;
  836                 }
  837         } else {
  838                 strcpy(rawbuf, fspec);
  839                 namelen = strlen(rawbuf);
  840         }
  841 
  842         /* make sure it's null terminated */
  843         rawbuf[MAXPATHLEN-1] = '\0';   
  844 
  845         dp = &rawbuf[namelen-1];
  846         while(dp >= rawbuf && *dp != '/') {
  847                 dp--;
  848         }
  849                         
  850         if (dp != NULL) {
  851                 dp++;
  852         } else {
  853                 dp = rawbuf;
  854         }
  855                         
  856         /* make room for and insert the 'r' for the raw device */
  857         memmove(dp+1, dp, strlen(dp)+1);
  858         *dp = 'r';
  859 
  860         NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, rawbuf, p);
  861         retval = namei(&nd);
  862         if (retval != E_NONE) {
  863                 DBG_ERR(("hfs_mountfs: can't open raw device for journal: %s, %x\n", rawbuf, nd.ni_vp->v_rdev));
  864                 FREE(rawbuf, M_HFSMNT);
  865                 goto error_exit;
  866         }
  867 
  868         *rvp = nd.ni_vp;
  869         if ((retval = VOP_OPEN(*rvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))) {
  870                 *rvp = NULL;
  871                 goto error_exit;
  872         }
  873 
  874         // don't need this any more
  875         FREE(rawbuf, M_HFSMNT);
  876 
  877         return 0;
  878 
  879   error_exit:
  880         if (*rvp) {
  881             (void)VOP_CLOSE(*rvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
  882         }
  883 
  884         if (rawbuf) {
  885                 FREE(rawbuf, M_HFSMNT);
  886         }
  887         return retval;
  888 }
  889 
  890 
  891 
  892 /*
  893  * Common code for mount and mountroot
  894  */
  895 static int
  896 hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p,
  897         struct hfs_mount_args *args)
  898 {
  899         int retval = E_NONE;
  900         struct hfsmount *hfsmp;
  901         struct buf *bp;
  902         dev_t dev;
  903         HFSMasterDirectoryBlock *mdbp;
  904         int ronly;
  905         int i;
  906         int mntwrapper;
  907         struct ucred *cred;
  908         u_int64_t disksize;
  909         u_int64_t blkcnt;
  910         u_int32_t blksize;
  911         u_int32_t minblksize;
  912         u_int32_t iswritable;
  913         daddr_t   mdb_offset;
  914 
  915         dev = devvp->v_rdev;
  916         cred = p ? p->p_ucred : NOCRED;
  917         mntwrapper = 0;
  918     /*
  919      * Disallow multiple mounts of the same device.
  920      * Disallow mounting of a device that is currently in use
  921      * (except for root, which might share swap device for miniroot).
  922      * Flush out any old buffers remaining from a previous use.
  923      */
  924     if ((retval = vfs_mountedon(devvp)))
  925         return (retval);
  926     if ((vcount(devvp) > 1) && (devvp != rootvp))
  927                 return (EBUSY);
  928     if ((retval = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)))
  929         return (retval);
  930 
  931     ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
  932     if ((retval = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)))
  933         return (retval);
  934 
  935         bp = NULL;
  936         hfsmp = NULL;
  937         mdbp = NULL;
  938         minblksize = kHFSBlockSize;
  939 
  940         /* Get the real physical block size. */
  941         if (VOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, (caddr_t)&blksize, 0, cred, p)) {
  942                 retval = ENXIO;
  943                 goto error_exit;
  944         }
  945         /* Switch to 512 byte sectors (temporarily) */
  946         if (blksize > 512) {
  947                 u_int32_t size512 = 512;
  948 
  949                 if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&size512, FWRITE, cred, p)) {
  950                         retval = ENXIO;
  951                         goto error_exit;
  952                 }
  953         }
  954         /* Get the number of 512 byte physical blocks. */
  955         if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
  956                 retval = ENXIO;
  957                 goto error_exit;
  958         }
  959         /* Compute an accurate disk size (i.e. within 512 bytes) */
  960         disksize = blkcnt * (u_int64_t)512;
  961 
  962         /*
  963          * There are only 31 bits worth of block count in
  964          * the buffer cache.  So for large volumes a 4K
  965          * physical block size is needed.
  966          */
  967         if (blkcnt > (u_int64_t)0x000000007fffffff) {
  968                 minblksize = blksize = 4096;
  969         }
  970         /* Now switch to our prefered physical block size. */
  971         if (blksize > 512) {
  972                 if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, cred, p)) {
  973                         retval = ENXIO;
  974                         goto error_exit;
  975                 }
  976                 /* Get the count of physical blocks. */
  977                 if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
  978                         retval = ENXIO;
  979                         goto error_exit;
  980                 }
  981         }
  982 
  983         /*
  984          * At this point:
  985          *   minblksize is the minimum physical block size
  986          *   blksize has our prefered physical block size
  987          *   blkcnt has the total number of physical blocks
  988          */
  989         devvp->v_specsize = blksize;
  990 
  991         /* cache the IO attributes */
  992         if ((retval = vfs_init_io_attributes(devvp, mp))) {
  993                 printf("hfs_mountfs: vfs_init_io_attributes returned %d\n",
  994                         retval);
  995                 return (retval);
  996         }
  997 
  998         mdb_offset = HFS_PRI_SECTOR(blksize);
  999         if ((retval = meta_bread(devvp, HFS_PRI_SECTOR(blksize), blksize, cred, &bp))) {
 1000                 goto error_exit;
 1001         }
 1002         MALLOC(mdbp, HFSMasterDirectoryBlock *, kMDBSize, M_TEMP, M_WAITOK);
 1003         bcopy(bp->b_data + HFS_PRI_OFFSET(blksize), mdbp, kMDBSize);
 1004         brelse(bp);
 1005         bp = NULL;
 1006 
 1007         MALLOC(hfsmp, struct hfsmount *, sizeof(struct hfsmount), M_HFSMNT, M_WAITOK);
 1008         bzero(hfsmp, sizeof(struct hfsmount));
 1009         
 1010         /*
 1011         *  Init the volume information structure
 1012         */
 1013         mp->mnt_data = (qaddr_t)hfsmp;
 1014         hfsmp->hfs_mp = mp;                     /* Make VFSTOHFS work */
 1015         hfsmp->hfs_vcb.vcb_hfsmp = hfsmp;       /* Make VCBTOHFS work */
 1016         hfsmp->hfs_raw_dev = devvp->v_rdev;
 1017         hfsmp->hfs_devvp = devvp;
 1018         hfsmp->hfs_phys_block_size = blksize;
 1019         hfsmp->hfs_phys_block_count = blkcnt;
 1020         hfsmp->hfs_flags |= HFS_WRITEABLE_MEDIA;
 1021         if (ronly)
 1022                 hfsmp->hfs_flags |= HFS_READ_ONLY;
 1023         if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS)
 1024                 hfsmp->hfs_flags |= HFS_UNKNOWN_PERMS;
 1025         for (i = 0; i < MAXQUOTAS; i++)
 1026                 hfsmp->hfs_qfiles[i].qf_vp = NULLVP;
 1027 
 1028         if (args) {
 1029                 hfsmp->hfs_uid = (args->hfs_uid == (uid_t)VNOVAL) ? UNKNOWNUID : args->hfs_uid;
 1030                 if (hfsmp->hfs_uid == 0xfffffffd) hfsmp->hfs_uid = UNKNOWNUID;
 1031                 hfsmp->hfs_gid = (args->hfs_gid == (gid_t)VNOVAL) ? UNKNOWNGID : args->hfs_gid;
 1032                 if (hfsmp->hfs_gid == 0xfffffffd) hfsmp->hfs_gid = UNKNOWNGID;
 1033                 if (args->hfs_mask != (mode_t)VNOVAL) {
 1034                         hfsmp->hfs_dir_mask = args->hfs_mask & ALLPERMS;
 1035                         if (args->flags & HFSFSMNT_NOXONFILES) {
 1036                                 hfsmp->hfs_file_mask = (args->hfs_mask & DEFFILEMODE);
 1037                         } else {
 1038                                 hfsmp->hfs_file_mask = args->hfs_mask & ALLPERMS;
 1039                         }
 1040                 } else {
 1041                         hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS;            /* 0777: rwx---rwx */
 1042                         hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE;        /* 0666: no --x by default? */
 1043                 }
 1044                 if ((args->flags != (int)VNOVAL) && (args->flags & HFSFSMNT_WRAPPER))
 1045                         mntwrapper = 1;
 1046         } else {
 1047                 /* Even w/o explicit mount arguments, MNT_UNKNOWNPERMISSIONS requires setting up uid, gid, and mask: */
 1048                 if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
 1049                         hfsmp->hfs_uid = UNKNOWNUID;
 1050                         hfsmp->hfs_gid = UNKNOWNGID;
 1051                         hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS;            /* 0777: rwx---rwx */
 1052                         hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE;        /* 0666: no --x by default? */
 1053                 }
 1054         }
 1055 
 1056         /* Find out if disk media is writable. */
 1057         if (VOP_IOCTL(devvp, DKIOCISWRITABLE, (caddr_t)&iswritable, 0, cred, p) == 0) {
 1058                 if (iswritable)
 1059                         hfsmp->hfs_flags |= HFS_WRITEABLE_MEDIA;
 1060                 else
 1061                         hfsmp->hfs_flags &= ~HFS_WRITEABLE_MEDIA;
 1062         }
 1063 
 1064         /* Mount a standard HFS disk */
 1065         if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) &&
 1066             (mntwrapper || (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord))) {
 1067                 if (devvp == rootvp) {
 1068                         retval = EINVAL;  /* Cannot root from HFS standard disks */
 1069                         goto error_exit;
 1070                 }
 1071                 /* HFS disks can only use 512 byte physical blocks */
 1072                 if (blksize > kHFSBlockSize) {
 1073                         blksize = kHFSBlockSize;
 1074                         if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, cred, p)) {
 1075                                 retval = ENXIO;
 1076                                 goto error_exit;
 1077                         }
 1078                         if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
 1079                                 retval = ENXIO;
 1080                                 goto error_exit;
 1081                         }
 1082                         devvp->v_specsize = blksize;
 1083                         hfsmp->hfs_phys_block_size = blksize;
 1084                         hfsmp->hfs_phys_block_count = blkcnt;
 1085                 }
 1086                 if (args) {
 1087                         hfsmp->hfs_encoding = args->hfs_encoding;
 1088                         HFSTOVCB(hfsmp)->volumeNameEncodingHint = args->hfs_encoding;
 1089 
 1090                         /* establish the timezone */
 1091                         gTimeZone = args->hfs_timezone;
 1092                 }
 1093 
 1094                 retval = hfs_getconverter(hfsmp->hfs_encoding, &hfsmp->hfs_get_unicode,
 1095                                         &hfsmp->hfs_get_hfsname);
 1096                 if (retval)
 1097                         goto error_exit;
 1098 
 1099                 retval = hfs_MountHFSVolume(hfsmp, mdbp, p);
 1100                 if (retval)
 1101                         (void) hfs_relconverter(hfsmp->hfs_encoding);
 1102 
 1103         } else /* Mount an HFS Plus disk */ {
 1104                 HFSPlusVolumeHeader *vhp;
 1105                 off_t embeddedOffset;
 1106                 int   jnl_disable = 0;
 1107         
 1108                 /* Get the embedded Volume Header */
 1109                 if (SWAP_BE16(mdbp->drEmbedSigWord) == kHFSPlusSigWord) {
 1110                         embeddedOffset = SWAP_BE16(mdbp->drAlBlSt) * kHFSBlockSize;
 1111                         embeddedOffset += (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.startBlock) *
 1112                                           (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
 1113 
 1114                         /*
 1115                          * If the embedded volume doesn't start on a block
 1116                          * boundary, then switch the device to a 512-byte
 1117                          * block size so everything will line up on a block
 1118                          * boundary.
 1119                          */
 1120                         if ((embeddedOffset % blksize) != 0) {
 1121                                 printf("HFS Mount: embedded volume offset not"
 1122                                     " a multiple of physical block size (%d);"
 1123                                     " switching to 512\n", blksize);
 1124                                 blksize = 512;
 1125                                 if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
 1126                                     (caddr_t)&blksize, FWRITE, cred, p)) {
 1127                                         retval = ENXIO;
 1128                                         goto error_exit;
 1129                                 }
 1130                                 if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT,
 1131                                     (caddr_t)&blkcnt, 0, cred, p)) {
 1132                                         retval = ENXIO;
 1133                                         goto error_exit;
 1134                                 }
 1135                                 /* XXX do we need to call vfs_init_io_attributes again? */
 1136                                 devvp->v_specsize = blksize;
 1137                                 /* Note: relative block count adjustment */
 1138                                 hfsmp->hfs_phys_block_count *=
 1139                                     hfsmp->hfs_phys_block_size / blksize;
 1140                                 hfsmp->hfs_phys_block_size = blksize;
 1141                         }
 1142 
 1143                         disksize = (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.blockCount) *
 1144                                    (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
 1145 
 1146                         hfsmp->hfs_phys_block_count = disksize / blksize;
 1147         
 1148                         mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize);
 1149                         retval = meta_bread(devvp, mdb_offset, blksize, cred, &bp);
 1150                         if (retval)
 1151                                 goto error_exit;
 1152                         bcopy(bp->b_data + HFS_PRI_OFFSET(blksize), mdbp, 512);
 1153                         brelse(bp);
 1154                         bp = NULL;
 1155                         vhp = (HFSPlusVolumeHeader*) mdbp;
 1156 
 1157                 } else /* pure HFS+ */ {
 1158                         embeddedOffset = 0;
 1159                         vhp = (HFSPlusVolumeHeader*) mdbp;
 1160                 }
 1161 
 1162                 // XXXdbg
 1163                 //
 1164                 hfsmp->jnl = NULL;
 1165                 hfsmp->jvp = NULL;
 1166                 if (args != NULL && (args->flags & HFSFSMNT_EXTENDED_ARGS) && args->journal_disable) {
 1167                     jnl_disable = 1;
 1168                 }
 1169                                 
 1170                 //
 1171                 // We only initialize the journal here if the last person
 1172                 // to mount this volume was journaling aware.  Otherwise
 1173                 // we delay journal initialization until later at the end
 1174                 // of hfs_MountHFSPlusVolume() because the last person who
 1175                 // mounted it could have messed things up behind our back
 1176                 // (so we need to go find the .journal file, make sure it's
 1177                 // the right size, re-sync up if it was moved, etc).
 1178                 //
 1179                 if (   (SWAP_BE32(vhp->lastMountedVersion) == kHFSJMountVersion)
 1180                         && (SWAP_BE32(vhp->attributes) & kHFSVolumeJournaledMask)
 1181                         && !jnl_disable) {
 1182                         
 1183                         // if we're able to init the journal, mark the mount
 1184                         // point as journaled.
 1185                         //
 1186                         if (hfs_early_journal_init(hfsmp, vhp, args, embeddedOffset, mdb_offset, mdbp, cred) == 0) {
 1187                                 mp->mnt_flag |= MNT_JOURNALED;
 1188                         } else {
 1189                                 // if the journal failed to open, then set the lastMountedVersion
 1190                                 // to be "FSK!" which fsck_hfs will see and force the fsck instead
 1191                                 // of just bailing out because the volume is journaled.
 1192                                 if (ronly != 0 || devvp == rootvp) {
 1193                                     HFSPlusVolumeHeader *vhp;
 1194 
 1195                                     hfsmp->hfs_flags |= HFS_NEED_JNL_RESET;
 1196                                     
 1197                                     if (mdb_offset == 0) {
 1198                                         mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize);
 1199                                     }
 1200 
 1201                                     bp = NULL;
 1202                                     retval = meta_bread(devvp, mdb_offset, blksize, cred, &bp);
 1203                                     if (retval == 0) {
 1204                                         vhp = (HFSPlusVolumeHeader *)(bp->b_data + HFS_PRI_OFFSET(blksize));
 1205                                             
 1206                                         if (SWAP_BE16(vhp->signature) == kHFSPlusSigWord || SWAP_BE16(vhp->signature) == kHFSXSigWord) {
 1207                                             vhp->lastMountedVersion = SWAP_BE32('FSK!');
 1208                                             bwrite(bp);
 1209                                         } else {
 1210                                             brelse(bp);
 1211                                         }
 1212                                         bp = NULL;
 1213                                     } else if (bp) {
 1214                                         brelse(bp);
 1215                                     }
 1216                                 }
 1217 
 1218                                 // if this isn't the root device just bail out.
 1219                                 // if it is the root device we just continue on
 1220                                 // in the hopes that fsck_hfs will be able to
 1221                                 // fix any damage that exists on the volume.
 1222                                 if (devvp != rootvp) {
 1223                                     retval = EINVAL;
 1224                                     goto error_exit;
 1225                                 }
 1226                         }
 1227                 }
 1228                 // XXXdbg
 1229         
 1230                 (void) hfs_getconverter(0, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
 1231 
 1232                 retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embeddedOffset, disksize, p, args);
 1233                 /*
 1234                  * If the backend didn't like our physical blocksize
 1235                  * then retry with physical blocksize of 512.
 1236                  */
 1237                 if ((retval == ENXIO) && (blksize > 512) && (blksize != minblksize)) {
 1238                         printf("HFS Mount: could not use physical block size "
 1239                                 "(%d) switching to 512\n", blksize);
 1240                         blksize = 512;
 1241                         if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, cred, p)) {
 1242                                 retval = ENXIO;
 1243                                 goto error_exit;
 1244                         }
 1245                         if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
 1246                                 retval = ENXIO;
 1247                                 goto error_exit;
 1248                         }
 1249                         devvp->v_specsize = blksize;
 1250                         /* Note: relative block count adjustment (in case this is an embedded volume). */
 1251                         hfsmp->hfs_phys_block_count *= hfsmp->hfs_phys_block_size / blksize;
 1252                         hfsmp->hfs_phys_block_size = blksize;
 1253  
 1254                         if (hfsmp->jnl) {
 1255                             // close and re-open this with the new block size
 1256                             journal_close(hfsmp->jnl);
 1257                             hfsmp->jnl = NULL;
 1258                             if (hfs_early_journal_init(hfsmp, vhp, args, embeddedOffset, mdb_offset, mdbp, cred) == 0) {
 1259                                 mp->mnt_flag |= MNT_JOURNALED;
 1260                             }
 1261                         }
 1262 
 1263                         /* Try again with a smaller block size... */
 1264                         retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embeddedOffset, disksize, p, args);
 1265                 }
 1266                 if (retval)
 1267                         (void) hfs_relconverter(0);
 1268         }
 1269 
 1270         if ( retval ) {
 1271                 goto error_exit;
 1272         }
 1273 
 1274         mp->mnt_stat.f_fsid.val[0] = (long)dev;
 1275         mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
 1276         mp->mnt_maxsymlinklen = 0;
 1277         devvp->v_specflags |= SI_MOUNTEDON;
 1278 
 1279         if (args) {
 1280                 /*
 1281                  * Set the free space warning levels for a non-root volume:
 1282                  *
 1283                  * Set the lower freespace limit (the level that will trigger a warning)
 1284                  * to 5% of the volume size or 250MB, whichever is less, and the desired
 1285                  * level (which will cancel the alert request) to 1/2 above that limit.
 1286                  * Start looking for free space to drop below this level and generate a
 1287                  * warning immediately if needed:
 1288                  */
 1289                 hfsmp->hfs_freespace_notify_warninglimit =
 1290                         MIN(HFS_LOWDISKTRIGGERLEVEL / HFSTOVCB(hfsmp)->blockSize,
 1291                                 (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_LOWDISKTRIGGERFRACTION);
 1292                 hfsmp->hfs_freespace_notify_desiredlevel =
 1293                         MIN(HFS_LOWDISKSHUTOFFLEVEL / HFSTOVCB(hfsmp)->blockSize,
 1294                                 (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_LOWDISKSHUTOFFFRACTION);
 1295         } else {
 1296                 /*
 1297                  * Set the free space warning levels for the root volume:
 1298                  *
 1299                  * Set the lower freespace limit (the level that will trigger a warning)
 1300                  * to 1% of the volume size or 50MB, whichever is less, and the desired
 1301                  * level (which will cancel the alert request) to 2% or 75MB, whichever is less.
 1302                  */
 1303                 hfsmp->hfs_freespace_notify_warninglimit =
 1304                         MIN(HFS_ROOTLOWDISKTRIGGERLEVEL / HFSTOVCB(hfsmp)->blockSize,
 1305                                 (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_ROOTLOWDISKTRIGGERFRACTION);
 1306                 hfsmp->hfs_freespace_notify_desiredlevel =
 1307                         MIN(HFS_ROOTLOWDISKSHUTOFFLEVEL / HFSTOVCB(hfsmp)->blockSize,
 1308                                 (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_ROOTLOWDISKSHUTOFFFRACTION);
 1309         };
 1310         
 1311         /*
 1312          * Start looking for free space to drop below this level and generate a
 1313          * warning immediately if needed:
 1314          */
 1315         hfsmp->hfs_notification_conditions = 0;
 1316         hfs_generate_volume_notifications(hfsmp);
 1317         
 1318         if (ronly == 0) {
 1319                 (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
 1320         }
 1321         FREE(mdbp, M_TEMP);
 1322         return (0);
 1323 
 1324 error_exit:
 1325         if (bp)
 1326                 brelse(bp);
 1327         if (mdbp)
 1328                 FREE(mdbp, M_TEMP);
 1329         (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
 1330         if (hfsmp && hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) {
 1331             (void)VOP_CLOSE(hfsmp->jvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
 1332                 hfsmp->jvp = NULL;
 1333         }
 1334         if (hfsmp) {
 1335                 FREE(hfsmp, M_HFSMNT);
 1336                 mp->mnt_data = (qaddr_t)0;
 1337         }
 1338         return (retval);
 1339 }
 1340 
 1341 
 1342 /*
 1343  * Make a filesystem operational.
 1344  * Nothing to do at the moment.
 1345  */
 1346 /* ARGSUSED */
 1347 static int
 1348 hfs_start(mp, flags, p)
 1349         struct mount *mp;
 1350         int flags;
 1351         struct proc *p;
 1352 {
 1353         return (0);
 1354 }
 1355 
 1356 
 1357 /*
 1358  * unmount system call
 1359  */
 1360 static int
 1361 hfs_unmount(mp, mntflags, p)
 1362         struct mount *mp;
 1363         int mntflags;
 1364         struct proc *p;
 1365 {
 1366         struct hfsmount *hfsmp = VFSTOHFS(mp);
 1367         int retval = E_NONE;
 1368         int flags;
 1369         int force;
 1370         int started_tr = 0, grabbed_lock = 0;
 1371 
 1372         flags = 0;
 1373         force = 0;
 1374         if (mntflags & MNT_FORCE) {
 1375                 flags |= FORCECLOSE;
 1376                 force = 1;
 1377         }
 1378 
 1379         if ((retval = hfs_flushfiles(mp, flags, p)) && !force)
 1380                 return (retval);
 1381 
 1382         if (hfsmp->hfs_flags & HFS_METADATA_ZONE)
 1383                 (void) hfs_recording_suspend(hfsmp, p);
 1384 
 1385         /*
 1386          * Flush out the b-trees, volume bitmap and Volume Header
 1387          */
 1388         if ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0) {
 1389                 hfs_global_shared_lock_acquire(hfsmp);
 1390                 grabbed_lock = 1;
 1391                 if (hfsmp->jnl) {
 1392                         journal_start_transaction(hfsmp->jnl);
 1393                         started_tr = 1;
 1394                 }
 1395                 
 1396                 retval = VOP_FSYNC(HFSTOVCB(hfsmp)->catalogRefNum, NOCRED, MNT_WAIT, p);
 1397                 if (retval && !force)
 1398                         goto err_exit;
 1399                 
 1400                 retval = VOP_FSYNC(HFSTOVCB(hfsmp)->extentsRefNum, NOCRED, MNT_WAIT, p);
 1401                 if (retval && !force)
 1402                         goto err_exit;
 1403                         
 1404                 // if we have an allocation file, sync it too so we don't leave dirty
 1405                 // blocks around
 1406                 if (HFSTOVCB(hfsmp)->allocationsRefNum) {
 1407                     if (retval = VOP_FSYNC(HFSTOVCB(hfsmp)->allocationsRefNum, NOCRED, MNT_WAIT, p)) {
 1408                         if (!force)
 1409                             goto err_exit;
 1410                     }
 1411                 }
 1412 
 1413                 if (hfsmp->hfc_filevp && (hfsmp->hfc_filevp->v_flag & VSYSTEM)) {
 1414                         retval = VOP_FSYNC(hfsmp->hfc_filevp, NOCRED, MNT_WAIT, p);
 1415                         if (retval && !force)
 1416                                 goto err_exit;
 1417                 }
 1418 
 1419                 if (retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p)) {
 1420                         if (!force)
 1421                                 goto err_exit;
 1422                 }
 1423 
 1424 #if 0           
 1425                 /* See if this volume is damaged, is so do not unmount cleanly */
 1426                 if (HFSTOVCB(hfsmp)->vcbFlags & kHFS_DamagedVolume) {
 1427                         HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
 1428                 } else {
 1429                         HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask;
 1430                 }
 1431 #else
 1432                 HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask;
 1433 #endif
 1434                 retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
 1435                 if (retval) {
 1436                         HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
 1437                         if (!force)
 1438                                 goto err_exit;  /* could not flush everything */
 1439                 }
 1440 
 1441                 if (hfsmp->jnl) {
 1442                         journal_end_transaction(hfsmp->jnl);
 1443                         started_tr = 0;
 1444                 }
 1445                 if (grabbed_lock) {
 1446                         hfs_global_shared_lock_release(hfsmp);
 1447                         grabbed_lock = 0;
 1448                 }
 1449         }
 1450 
 1451         if (hfsmp->jnl) {
 1452                 journal_flush(hfsmp->jnl);
 1453         }
 1454         
 1455         /*
 1456          *      Invalidate our caches and release metadata vnodes
 1457          */
 1458         (void) hfsUnmount(hfsmp, p);
 1459 
 1460         /*
 1461          * Last chance to dump unreferenced system files.
 1462          */
 1463         (void) vflush(mp, NULLVP, FORCECLOSE);
 1464 
 1465         if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord)
 1466                 (void) hfs_relconverter(hfsmp->hfs_encoding);
 1467 
 1468         // XXXdbg
 1469         if (hfsmp->jnl) {
 1470             journal_close(hfsmp->jnl);
 1471             hfsmp->jnl = NULL;
 1472         }
 1473 
 1474         if (hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) {
 1475             retval = VOP_CLOSE(hfsmp->jvp,
 1476                                hfsmp->hfs_flags & HFS_READ_ONLY ? FREAD : FREAD|FWRITE,
 1477                                NOCRED, p);
 1478             vrele(hfsmp->jvp);
 1479             hfsmp->jvp = NULL;
 1480         }
 1481         // XXXdbg
 1482 
 1483 #ifdef HFS_SPARSE_DEV
 1484         /* Drop our reference on the backing fs (if any). */
 1485         if ((hfsmp->hfs_flags & HFS_HAS_SPARSE_DEVICE) && hfsmp->hfs_backingfs_rootvp) {
 1486                 struct vnode * tmpvp;
 1487 
 1488                 hfsmp->hfs_flags &= ~HFS_HAS_SPARSE_DEVICE;
 1489                 tmpvp = hfsmp->hfs_backingfs_rootvp;
 1490                 hfsmp->hfs_backingfs_rootvp = NULLVP;
 1491                 vrele(tmpvp);
 1492         }
 1493 #endif /* HFS_SPARSE_DEV */
 1494 
 1495         hfsmp->hfs_devvp->v_specflags &= ~SI_MOUNTEDON;
 1496         retval = VOP_CLOSE(hfsmp->hfs_devvp,
 1497                            hfsmp->hfs_flags & HFS_READ_ONLY ? FREAD : FREAD|FWRITE,
 1498                            NOCRED, p);
 1499         if (retval && !force)
 1500                 return(retval);
 1501 
 1502         vrele(hfsmp->hfs_devvp);
 1503         FREE(hfsmp, M_HFSMNT);
 1504         mp->mnt_data = (qaddr_t)0;
 1505         return (0);
 1506 
 1507   err_exit:
 1508         if (hfsmp->jnl && started_tr) {
 1509                 journal_end_transaction(hfsmp->jnl);
 1510         }
 1511         if (grabbed_lock) {
 1512                 hfs_global_shared_lock_release(hfsmp);
 1513         }
 1514         return retval;
 1515 }
 1516 
 1517 
 1518 /*
 1519  * Return the root of a filesystem.
 1520  *
 1521  *              OUT - vpp, should be locked and vget()'d (to increment usecount and lock)
 1522  */
 1523 static int
 1524 hfs_root(mp, vpp)
 1525         struct mount *mp;
 1526         struct vnode **vpp;
 1527 {
 1528         struct vnode *nvp;
 1529         int retval;
 1530         UInt32 rootObjID = kRootDirID;
 1531 
 1532         if ((retval = VFS_VGET(mp, &rootObjID, &nvp)))
 1533                 return (retval);
 1534 
 1535         *vpp = nvp;
 1536         return (0);
 1537 }
 1538 
 1539 
 1540 /*
 1541  * Do operations associated with quotas
 1542  */
 1543 int
 1544 hfs_quotactl(mp, cmds, uid, arg, p)
 1545         struct mount *mp;
 1546         int cmds;
 1547         uid_t uid;
 1548         caddr_t arg;
 1549         struct proc *p;
 1550 {
 1551         int cmd, type, error;
 1552 
 1553 #if !QUOTA
 1554         return (EOPNOTSUPP);
 1555 #else
 1556         if (uid == -1)
 1557                 uid = p->p_cred->p_ruid;
 1558         cmd = cmds >> SUBCMDSHIFT;
 1559 
 1560         switch (cmd) {
 1561         case Q_SYNC:
 1562         case Q_QUOTASTAT:
 1563                 break;
 1564         case Q_GETQUOTA:
 1565                 if (uid == p->p_cred->p_ruid)
 1566                         break;
 1567                 /* fall through */
 1568         default:
 1569                 if (error = suser(p->p_ucred, &p->p_acflag))
 1570                         return (error);
 1571         }
 1572 
 1573         type = cmds & SUBCMDMASK;
 1574         if ((u_int)type >= MAXQUOTAS)
 1575                 return (EINVAL);
 1576         if (vfs_busy(mp, LK_NOWAIT, 0, p))
 1577                 return (0);
 1578 
 1579         switch (cmd) {
 1580 
 1581         case Q_QUOTAON:
 1582                 error = hfs_quotaon(p, mp, type, arg, UIO_USERSPACE);
 1583                 break;
 1584 
 1585         case Q_QUOTAOFF:
 1586                 error = hfs_quotaoff(p, mp, type);
 1587                 break;
 1588 
 1589         case Q_SETQUOTA:
 1590                 error = hfs_setquota(mp, uid, type, arg);
 1591                 break;
 1592 
 1593         case Q_SETUSE:
 1594                 error = hfs_setuse(mp, uid, type, arg);
 1595                 break;
 1596 
 1597         case Q_GETQUOTA:
 1598                 error = hfs_getquota(mp, uid, type, arg);
 1599                 break;
 1600 
 1601         case Q_SYNC:
 1602                 error = hfs_qsync(mp);
 1603                 break;
 1604 
 1605         case Q_QUOTASTAT:
 1606                 error = hfs_quotastat(mp, type, arg);
 1607                 break;
 1608 
 1609         default:
 1610                 error = EINVAL;
 1611                 break;
 1612         }
 1613         vfs_unbusy(mp, p);
 1614         return (error);
 1615 #endif /* QUOTA */
 1616 }
 1617 
 1618 
 1619 
 1620 
 1621 /*
 1622  * Get file system statistics.
 1623  */
 1624 static int
 1625 hfs_statfs(mp, sbp, p)
 1626         struct mount *mp;
 1627         register struct statfs *sbp;
 1628         struct proc *p;
 1629 {
 1630         ExtendedVCB *vcb = VFSTOVCB(mp);
 1631         struct hfsmount *hfsmp = VFSTOHFS(mp);
 1632         u_long freeCNIDs;
 1633 
 1634         freeCNIDs = (u_long)0xFFFFFFFF - (u_long)vcb->vcbNxtCNID;
 1635 
 1636         sbp->f_bsize = vcb->blockSize;
 1637         sbp->f_iosize = hfsmp->hfs_logBlockSize;
 1638         sbp->f_blocks = vcb->totalBlocks;
 1639         sbp->f_bfree = hfs_freeblks(hfsmp, 0);
 1640         sbp->f_bavail = hfs_freeblks(hfsmp, 1);
 1641         sbp->f_files = vcb->totalBlocks - 2;  /* max files is constrained by total blocks */
 1642         sbp->f_ffree = MIN(freeCNIDs, sbp->f_bavail);
 1643         
 1644         sbp->f_type = 0;
 1645         if (sbp != &mp->mnt_stat) {
 1646                 sbp->f_type = mp->mnt_vfc->vfc_typenum;
 1647                 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
 1648                         (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
 1649                 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
 1650                         (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
 1651         }
 1652         return (0);
 1653 }
 1654 
 1655 
 1656 //
 1657 // XXXdbg -- this is a callback to be used by the journal to
 1658 //           get meta data blocks flushed out to disk.
 1659 //
 1660 // XXXdbg -- be smarter and don't flush *every* block on each
 1661 //           call.  try to only flush some so we don't wind up
 1662 //           being too synchronous.
 1663 //
 1664 __private_extern__
 1665 void
 1666 hfs_sync_metadata(void *arg)
 1667 {
 1668         struct mount *mp = (struct mount *)arg;
 1669         struct cnode *cp;
 1670         struct hfsmount *hfsmp;
 1671         ExtendedVCB *vcb;
 1672         struct vnode *meta_vp[3];
 1673         struct buf *bp;
 1674         int i, sectorsize, priIDSector, altIDSector, retval;
 1675         int error, allerror = 0;
 1676 
 1677         hfsmp = VFSTOHFS(mp);
 1678         vcb = HFSTOVCB(hfsmp);
 1679 
 1680         bflushq(BQ_META, mp);
 1681 
 1682 
 1683 #if 1     // XXXdbg - I do not believe this is necessary...
 1684           //          but if I pull it out, then the journal
 1685               //          does not seem to get flushed properly
 1686               //          when it is closed....
 1687         
 1688         // now make sure the super block is flushed
 1689         sectorsize = hfsmp->hfs_phys_block_size;
 1690         priIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
 1691                   HFS_PRI_SECTOR(sectorsize);
 1692         retval = meta_bread(hfsmp->hfs_devvp, priIDSector, sectorsize, NOCRED, &bp);
 1693         if (retval != 0) {
 1694                 panic("hfs: sync_metadata: can't read super-block?! (retval 0x%x, priIDSector)\n",
 1695                           retval, priIDSector);
 1696         }
 1697 
 1698         if (retval == 0 && (bp->b_flags & B_DELWRI) && (bp->b_flags & B_LOCKED) == 0) {
 1699             bwrite(bp);
 1700         } else if (bp) {
 1701             brelse(bp);
 1702         }
 1703 
 1704         // the alternate super block...
 1705         // XXXdbg - we probably don't need to do this each and every time.
 1706         //          hfs_btreeio.c:FlushAlternate() should flag when it was
 1707         //          written...
 1708         altIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
 1709                         HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
 1710         retval = meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &bp);
 1711         if (retval == 0 && (bp->b_flags & B_DELWRI) && (bp->b_flags & B_LOCKED) == 0) {
 1712             bwrite(bp);
 1713         } else if (bp) {
 1714             brelse(bp);
 1715         }
 1716 #endif
 1717         
 1718 }
 1719 
 1720 /*
 1721  * Go through the disk queues to initiate sandbagged IO;
 1722  * go through the inodes to write those that have been modified;
 1723  * initiate the writing of the super block if it has been modified.
 1724  *
 1725  * Note: we are always called with the filesystem marked `MPBUSY'.
 1726  */
 1727 static int
 1728 hfs_sync(mp, waitfor, cred, p)
 1729         struct mount *mp;
 1730         int waitfor;
 1731         struct ucred *cred;
 1732         struct proc *p;
 1733 {
 1734         struct vnode *nvp, *vp;
 1735         struct cnode *cp;
 1736         struct hfsmount *hfsmp;
 1737         ExtendedVCB *vcb;
 1738         struct vnode *meta_vp[3];
 1739         int i;
 1740         int error, allerror = 0;
 1741 
 1742         /*
 1743          * During MNT_UPDATE hfs_changefs might be manipulating
 1744          * vnodes so back off
 1745          */
 1746         if (mp->mnt_flag & MNT_UPDATE)
 1747                 return (0);
 1748 
 1749         hfsmp = VFSTOHFS(mp);
 1750         if (hfsmp->hfs_flags & HFS_READ_ONLY)
 1751                 return (EROFS);
 1752 
 1753 #if 0
 1754         // XXXdbg first go through and flush out any modified
 1755         //        meta data blocks so they go out in order...
 1756         bflushq(BQ_META, mp);
 1757         bflushq(BQ_LRU,  mp);
 1758         // only flush locked blocks if we're not doing journaling
 1759         if (hfsmp->jnl == NULL) {
 1760             bflushq(BQ_LOCKED, mp);
 1761         }
 1762 #endif
 1763 
 1764         /*
 1765          * Write back each 'modified' vnode
 1766          */
 1767 
 1768 loop:
 1769         simple_lock(&mntvnode_slock);
 1770         for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
 1771                  int didhold;
 1772                 /*
 1773                  * If the vnode that we are about to sync is no longer
 1774                  * associated with this mount point, start over.
 1775                  */
 1776                 if (vp->v_mount != mp) {
 1777                         simple_unlock(&mntvnode_slock);
 1778                         goto loop;
 1779                 }
 1780 
 1781                 simple_lock(&vp->v_interlock);
 1782                 nvp = vp->v_mntvnodes.le_next;
 1783 
 1784                 cp = VTOC(vp);
 1785 
 1786                 // restart our whole search if this guy is locked
 1787                 // or being reclaimed.
 1788                 if (vp->v_tag != VT_HFS || cp == NULL || vp->v_flag & (VXLOCK|VORECLAIM)) {
 1789                         simple_unlock(&vp->v_interlock);
 1790                         continue;
 1791                 }
 1792 
 1793                 if ((vp->v_flag & VSYSTEM) || (vp->v_type == VNON) ||
 1794                     (((cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) == 0) &&
 1795                     (vp->v_dirtyblkhd.lh_first == NULL) && !(vp->v_flag & VHASDIRTY))) {
 1796                         simple_unlock(&vp->v_interlock);
 1797                         simple_unlock(&mntvnode_slock);
 1798                         simple_lock(&mntvnode_slock);
 1799                         continue;
 1800                 }
 1801 
 1802                 simple_unlock(&mntvnode_slock);
 1803                 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
 1804                 if (error) {
 1805                         if (error == ENOENT)
 1806                                 goto loop;
 1807                         simple_lock(&mntvnode_slock);
 1808                         continue;
 1809                 }
 1810                 
 1811                 didhold = ubc_hold(vp);
 1812 
 1813                 // mark the cnode so that fsync won't flush
 1814                 // the journal since we're going to do that...
 1815                 cp->c_flag |= C_FROMSYNC;
 1816                 if ((error = VOP_FSYNC(vp, cred, waitfor, p))) {
 1817                         allerror = error;
 1818                 };
 1819                 cp->c_flag &= ~C_FROMSYNC;
 1820 
 1821                 VOP_UNLOCK(vp, 0, p);
 1822                 if (didhold)
 1823                         ubc_rele(vp);
 1824                 vrele(vp);
 1825                 simple_lock(&mntvnode_slock);
 1826         };
 1827 
 1828         vcb = HFSTOVCB(hfsmp);
 1829 
 1830         meta_vp[0] = vcb->extentsRefNum;
 1831         meta_vp[1] = vcb->catalogRefNum;
 1832         meta_vp[2] = vcb->allocationsRefNum;  /* This is NULL for standard HFS */
 1833 
 1834         /* Now sync our three metadata files */
 1835         for (i = 0; i < 3; ++i) {
 1836                 struct vnode *btvp;
 1837 
 1838                 btvp = btvp = meta_vp[i];;
 1839                 if ((btvp==0) || (btvp->v_type == VNON) || (btvp->v_mount != mp))
 1840                         continue;
 1841 
 1842                 simple_lock(&btvp->v_interlock);
 1843                 cp = VTOC(btvp);
 1844                 if (((cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) == 0) &&
 1845                     (btvp->v_dirtyblkhd.lh_first == NULL) && !(btvp->v_flag & VHASDIRTY)) {
 1846                         simple_unlock(&btvp->v_interlock);
 1847                         continue;
 1848                 }
 1849                 simple_unlock(&mntvnode_slock);
 1850                 error = vget(btvp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
 1851                 if (error) {
 1852                         simple_lock(&mntvnode_slock);
 1853                         continue;
 1854                 }
 1855                 if ((error = VOP_FSYNC(btvp, cred, waitfor, p)))
 1856                         allerror = error;
 1857                 VOP_UNLOCK(btvp, 0, p);
 1858                 vrele(btvp);
 1859                 simple_lock(&mntvnode_slock);
 1860         };
 1861 
 1862         simple_unlock(&mntvnode_slock);
 1863 
 1864         /*
 1865          * Force stale file system control information to be flushed.
 1866          */
 1867         if (vcb->vcbSigWord == kHFSSigWord) {
 1868                 if ((error = VOP_FSYNC(hfsmp->hfs_devvp, cred, waitfor, p)))
 1869                         allerror = error;
 1870         }
 1871 #if QUOTA
 1872         hfs_qsync(mp);
 1873 #endif /* QUOTA */
 1874 
 1875         hfs_hotfilesync(hfsmp, p);
 1876         /*
 1877          * Write back modified superblock.
 1878          */
 1879 
 1880         if (IsVCBDirty(vcb)) {
 1881                 // XXXdbg - debugging, remove
 1882                 if (hfsmp->jnl) {
 1883                         //printf("hfs: sync: strange, a journaled volume w/dirty VCB? jnl 0x%x hfsmp 0x%x\n",
 1884                         //        hfsmp->jnl, hfsmp);
 1885                 }
 1886 
 1887                 error = hfs_flushvolumeheader(hfsmp, waitfor, 0);
 1888                 if (error)
 1889                         allerror = error;
 1890         }
 1891 
 1892         if (hfsmp->jnl) {
 1893             journal_flush(hfsmp->jnl);
 1894         }
 1895         
 1896   err_exit:
 1897         return (allerror);
 1898 }
 1899 
 1900 
 1901 /*
 1902  * File handle to vnode
 1903  *
 1904  * Have to be really careful about stale file handles:
 1905  * - check that the cnode id is valid
 1906  * - call hfs_vget() to get the locked cnode
 1907  * - check for an unallocated cnode (i_mode == 0)
 1908  * - check that the given client host has export rights and return
 1909  *   those rights via. exflagsp and credanonp
 1910  */
 1911 static int
 1912 hfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
 1913         register struct mount *mp;
 1914         struct fid *fhp;
 1915         struct mbuf *nam;
 1916         struct vnode **vpp;
 1917         int *exflagsp;
 1918         struct ucred **credanonp;
 1919 {
 1920         struct hfsfid *hfsfhp;
 1921         struct vnode *nvp;
 1922         int result;
 1923         struct netcred *np;
 1924 
 1925         *vpp = NULL;
 1926         hfsfhp = (struct hfsfid *)fhp;
 1927 
 1928         /*
 1929          * Get the export permission structure for this <mp, client> tuple.
 1930          */
 1931         np = vfs_export_lookup(mp, &VFSTOHFS(mp)->hfs_export, nam);
 1932         if (nam && (np == NULL)) {
 1933                 return EACCES;
 1934         };
 1935 
 1936         result = VFS_VGET(mp, &hfsfhp->hfsfid_cnid, &nvp);
 1937         if (result) return result;
 1938         if (nvp == NULL) return ESTALE;
 1939         
 1940         /* The createtime can be changed by hfs_setattr or hfs_setattrlist.
 1941          * For NFS, we are assuming that only if the createtime was moved
 1942          * forward would it mean the fileID got reused in that session by
 1943          * wrapping. We don't have a volume ID or other unique identifier to
 1944          * to use here for a generation ID across reboots, crashes where 
 1945          * metadata noting lastFileID didn't make it to disk but client has
 1946          * it, or volume erasures where fileIDs start over again. Lastly,
 1947          * with HFS allowing "wraps" of fileIDs now, this becomes more
 1948          * error prone. Future, would be change the "wrap bit" to a unique
 1949          * wrap number and use that for generation number. For now do this.
 1950          */  
 1951         if ((hfsfhp->hfsfid_gen < VTOC(nvp)->c_itime)) {
 1952                 vput(nvp);
 1953                 return (ESTALE);
 1954         };
 1955         
 1956         if (VNAME(nvp) == NULL) {
 1957             struct cnode *cp = VTOC(nvp);
 1958             
 1959             if (nvp == cp->c_rsrc_vp) {
 1960                 // the +1/-2 thing is to skip the leading "/" on the rsrc fork spec
 1961                 // and to not count the trailing null byte at the end of the string.
 1962                 VNAME(nvp) = add_name(_PATH_RSRCFORKSPEC+1, sizeof(_PATH_RSRCFORKSPEC)-2, 0, 0);
 1963             } else {
 1964                 VNAME(nvp) = add_name(cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen, 0, 0);
 1965             }
 1966         }
 1967 
 1968         *vpp = nvp;
 1969         if (np) {
 1970                 *exflagsp = np->netc_exflags;
 1971                 *credanonp = &np->netc_anon;
 1972         }
 1973         
 1974         return (0);
 1975 }
 1976 
 1977 
 1978 /*
 1979  * Vnode pointer to File handle
 1980  */
 1981 /* ARGSUSED */
 1982 static int
 1983 hfs_vptofh(vp, fhp)
 1984         struct vnode *vp;
 1985         struct fid *fhp;
 1986 {
 1987         struct cnode *cp;
 1988         struct hfsfid *hfsfhp;
 1989 
 1990         if (ISHFS(VTOVCB(vp)))
 1991                 return (EOPNOTSUPP);    /* hfs standard is not exportable */
 1992 
 1993         cp = VTOC(vp);
 1994         hfsfhp = (struct hfsfid *)fhp;
 1995         hfsfhp->hfsfid_len = sizeof(struct hfsfid);
 1996         hfsfhp->hfsfid_pad = 0;
 1997         hfsfhp->hfsfid_cnid = cp->c_fileid;
 1998         hfsfhp->hfsfid_gen = cp->c_itime;
 1999         
 2000         return (0);
 2001 }
 2002 
 2003 
 2004 /*
 2005  * Initial HFS filesystems, done only once.
 2006  */
 2007 static int
 2008 hfs_init(vfsp)
 2009         struct vfsconf *vfsp;
 2010 {
 2011         static int done = 0;
 2012 
 2013         if (done)
 2014                 return (0);
 2015         done = 1;
 2016         hfs_chashinit();
 2017         hfs_converterinit();
 2018 #if QUOTA
 2019         dqinit();
 2020 #endif /* QUOTA */
 2021 
 2022         BTReserveSetup();
 2023 
 2024         /*
 2025          * Allocate Catalog Iterator cache...
 2026          */
 2027         (void) InitCatalogCache();
 2028 
 2029         return (0);
 2030 }
 2031 
 2032 static int
 2033 hfs_getmountpoint(vp, hfsmpp)
 2034         struct vnode *vp;
 2035         struct hfsmount **hfsmpp;
 2036 {
 2037         struct hfsmount * hfsmp;
 2038 
 2039         if (vp == NULL)
 2040                 return (EINVAL);
 2041         
 2042         if ((vp->v_flag & VROOT) == 0)
 2043                 return (EINVAL);
 2044 
 2045         if (strcmp(vp->v_mount->mnt_stat.f_fstypename, "hfs") != 0)
 2046                 return (EINVAL);
 2047 
 2048         hfsmp = VTOHFS(vp);
 2049 
 2050         if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord)
 2051                 return (EINVAL);
 2052 
 2053         *hfsmpp = hfsmp;
 2054 
 2055         return (0);
 2056 }
 2057 
 2058 // XXXdbg
 2059 #include <sys/filedesc.h>
 2060 
 2061 
 2062 /*
 2063  * HFS filesystem related variables.
 2064  */
 2065 static int
 2066 hfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
 2067         int *name;
 2068         u_int namelen;
 2069         void *oldp;
 2070         size_t *oldlenp;
 2071         void *newp;
 2072         size_t newlen;
 2073         struct proc *p;
 2074 {
 2075         extern u_int32_t  hfs_getencodingbias(void);
 2076         extern void  hfs_setencodingbias(u_int32_t);
 2077 
 2078         int error;
 2079         struct sysctl_req *req;
 2080         struct vfsidctl vc;
 2081         struct mount *mp;
 2082         struct hfsmount *hfsmp;
 2083         struct vfsquery vq;
 2084 
 2085         /* all sysctl names at this level are terminal */
 2086 
 2087         if (name[0] == HFS_ENCODINGBIAS) {
 2088                 u_int32_t bias;
 2089 
 2090                 bias = hfs_getencodingbias();
 2091                 error = sysctl_int(oldp, oldlenp, newp, newlen, &bias);
 2092                 if (error == 0 && newp)
 2093                         hfs_setencodingbias(bias);
 2094                 return (error);
 2095 
 2096         } else if (name[0] == HFS_EXTEND_FS) {
 2097                 u_int64_t  newsize;
 2098                 
 2099                 if (newp == NULL)
 2100                         return (EINVAL);
 2101                 if ((error = hfs_getmountpoint(p->p_fd->fd_cdir, &hfsmp)))
 2102                         return (error);
 2103                 error = sysctl_quad(oldp, oldlenp, newp, newlen, &newsize);
 2104                 if (error)
 2105                         return (error);
 2106         
 2107                 error = hfs_extendfs(HFSTOVFS(hfsmp), newsize, p);              
 2108                 return (error);
 2109 
 2110         } else if (name[0] == HFS_ENCODINGHINT) {
 2111                 size_t bufsize;
 2112                 size_t bytes;
 2113                 u_int32_t hint;
 2114                 u_int16_t *unicode_name;
 2115                 char *filename;
 2116 
 2117                 bufsize = MAX(newlen * 3, MAXPATHLEN);
 2118                 MALLOC(filename, char *, newlen, M_TEMP, M_WAITOK);
 2119                 MALLOC(unicode_name, u_int16_t *, bufsize, M_TEMP, M_WAITOK);
 2120 
 2121                 error = copyin(newp, (caddr_t)filename, newlen);
 2122                 if (error == 0) {
 2123                         error = utf8_decodestr(filename, newlen - 1, unicode_name,
 2124                                                &bytes, bufsize, 0, UTF_DECOMPOSED);
 2125                         if (error == 0) {
 2126                                 hint = hfs_pickencoding(unicode_name, bytes / 2);
 2127                                 error = sysctl_int(oldp, oldlenp, NULL, NULL, &hint);
 2128                         }
 2129                 }
 2130                 FREE(unicode_name, M_TEMP);
 2131                 FREE(filename, M_TEMP);
 2132                 return (error);
 2133 
 2134         } else if (name[0] == HFS_ENABLE_JOURNALING) {
 2135                 // make the file system journaled...
 2136                 struct vnode *vp = p->p_fd->fd_cdir, *jvp;
 2137                 ExtendedVCB *vcb;
 2138                 int retval;
 2139                 struct cat_attr jnl_attr, jinfo_attr;
 2140                 struct cat_fork jnl_fork, jinfo_fork;
 2141                 void *jnl = NULL;
 2142 
 2143                 /* Only root can enable journaling */
 2144                 if (current_proc()->p_ucred->cr_uid != 0) {
 2145                         return (EPERM);
 2146                 }
 2147 
 2148                 hfsmp = VTOHFS(vp);
 2149                 if (hfsmp->hfs_flags & HFS_READ_ONLY) {
 2150                         return EROFS;
 2151                 }
 2152                 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) {
 2153                         printf("hfs: can't make a plain hfs volume journaled.\n");
 2154                         return EINVAL;
 2155                 }
 2156 
 2157                 if (hfsmp->jnl) {
 2158                     printf("hfs: volume @ mp 0x%x is already journaled!\n", vp->v_mount);
 2159                     return EAGAIN;
 2160                 }
 2161 
 2162                 vcb = HFSTOVCB(hfsmp);
 2163                 if (BTHasContiguousNodes(VTOF(vcb->catalogRefNum)) == 0 ||
 2164                         BTHasContiguousNodes(VTOF(vcb->extentsRefNum)) == 0) {
 2165 
 2166                         printf("hfs: volume has a btree w/non-contiguous nodes.  can not enable journaling.\n");
 2167                         return EINVAL;
 2168                 }
 2169 
 2170                 // make sure these both exist!
 2171                 if (   GetFileInfo(vcb, kRootDirID, ".journal_info_block", &jinfo_attr, &jinfo_fork) == 0
 2172                         || GetFileInfo(vcb, kRootDirID, ".journal", &jnl_attr, &jnl_fork) == 0) {
 2173 
 2174                         return EINVAL;
 2175                 }
 2176 
 2177                 hfs_sync(hfsmp->hfs_mp, MNT_WAIT, FSCRED, p);
 2178                 bflushq(BQ_META);
 2179 
 2180                 printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n",
 2181                            (off_t)name[2], (off_t)name[3]);
 2182 
 2183                 jvp = hfsmp->hfs_devvp;
 2184                 jnl = journal_create(jvp,
 2185                                                          (off_t)name[2] * (off_t)HFSTOVCB(hfsmp)->blockSize
 2186                                                          + HFSTOVCB(hfsmp)->hfsPlusIOPosOffset,
 2187                                                          (off_t)((unsigned)name[3]),
 2188                                                          hfsmp->hfs_devvp,
 2189                                                          hfsmp->hfs_phys_block_size,
 2190                                                          0,
 2191                                                          0,
 2192                                                          hfs_sync_metadata, hfsmp->hfs_mp);
 2193 
 2194                 if (jnl == NULL) {
 2195                         printf("hfs: FAILED to create the journal!\n");
 2196                         if (jvp && jvp != hfsmp->hfs_devvp) {
 2197                                 VOP_CLOSE(jvp, hfsmp->hfs_flags & HFS_READ_ONLY ? FREAD : FREAD|FWRITE, FSCRED, p);
 2198                         }
 2199                         jvp = NULL;
 2200 
 2201                         return EINVAL;
 2202                 } 
 2203 
 2204                 hfs_global_exclusive_lock_acquire(hfsmp);
 2205                 
 2206                 HFSTOVCB(hfsmp)->vcbJinfoBlock = name[1];
 2207                 HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeJournaledMask;
 2208                 hfsmp->jvp = jvp;
 2209                 hfsmp->jnl = jnl;
 2210 
 2211                 // save this off for the hack-y check in hfs_remove()
 2212                 hfsmp->jnl_start        = (u_int32_t)name[2];
 2213                 hfsmp->jnl_size         = (off_t)((unsigned)name[3]);
 2214                 hfsmp->hfs_jnlinfoblkid = jinfo_attr.ca_fileid;
 2215                 hfsmp->hfs_jnlfileid    = jnl_attr.ca_fileid;
 2216 
 2217                 hfsmp->hfs_mp->mnt_flag |= MNT_JOURNALED;
 2218 
 2219                 hfs_global_exclusive_lock_release(hfsmp);
 2220                 hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
 2221 
 2222                 return 0;
 2223         } else if (name[0] == HFS_DISABLE_JOURNALING) {
 2224                 // clear the journaling bit 
 2225                 struct vnode *vp = p->p_fd->fd_cdir;
 2226                 void *jnl;
 2227                 int retval;
 2228                 
 2229                 /* Only root can disable journaling */
 2230                 if (current_proc()->p_ucred->cr_uid != 0) {
 2231                         return (EPERM);
 2232                 }
 2233 
 2234                 hfsmp = VTOHFS(vp);
 2235 
 2236                 printf("hfs: disabling journaling for mount @ 0x%x\n", vp->v_mount);
 2237 
 2238                 jnl = hfsmp->jnl;
 2239                 
 2240                 hfs_global_exclusive_lock_acquire(hfsmp);
 2241 
 2242                 // Lights out for you buddy!
 2243                 hfsmp->jnl = NULL;
 2244                 journal_close(jnl);
 2245 
 2246                 if (hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) {
 2247                         VOP_CLOSE(hfsmp->jvp, hfsmp->hfs_flags & HFS_READ_ONLY ? FREAD : FREAD|FWRITE, FSCRED, p);
 2248                 }
 2249                 hfsmp->jnl = NULL;
 2250                 hfsmp->jvp = NULL;
 2251                 hfsmp->hfs_mp->mnt_flag &= ~MNT_JOURNALED;
 2252                 hfsmp->jnl_start        = 0;
 2253                 hfsmp->hfs_jnlinfoblkid = 0;
 2254                 hfsmp->hfs_jnlfileid    = 0;
 2255                 
 2256                 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeJournaledMask;
 2257                 
 2258                 hfs_global_exclusive_lock_release(hfsmp);
 2259                 hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
 2260 
 2261                 return 0;
 2262         } else if (name[0] == HFS_GET_JOURNAL_INFO) {
 2263                 struct vnode *vp = p->p_fd->fd_cdir;
 2264                 off_t jnl_start, jnl_size;
 2265 
 2266                 hfsmp = VTOHFS(vp);
 2267             if (hfsmp->jnl == NULL) {
 2268                         jnl_start = 0;
 2269                         jnl_size  = 0;
 2270             } else {
 2271                         jnl_start = (off_t)(hfsmp->jnl_start * HFSTOVCB(hfsmp)->blockSize) + (off_t)HFSTOVCB(hfsmp)->hfsPlusIOPosOffset;
 2272                         jnl_size  = (off_t)hfsmp->jnl_size;
 2273             }
 2274 
 2275             if ((error = copyout((caddr_t)&jnl_start, (void *)name[1], sizeof(off_t))) != 0) {
 2276                         return error;
 2277                 }
 2278             if ((error = copyout((caddr_t)&jnl_size, (void *)name[2], sizeof(off_t))) != 0) {
 2279                         return error;
 2280                 }
 2281 
 2282                 return 0;
 2283         } else if (name[0] == HFS_SET_PKG_EXTENSIONS) {
 2284 
 2285             return set_package_extensions_table((void *)name[1], name[2], name[3]);
 2286             
 2287         } else if (name[0] == VFS_CTL_QUERY) {
 2288                 req = oldp;     /* we're new style vfs sysctl. */
 2289         
 2290                 error = SYSCTL_IN(req, &vc, sizeof(vc));
 2291                 if (error) return (error);
 2292         
 2293                 mp = vfs_getvfs(&vc.vc_fsid);
 2294                 if (mp == NULL) return (ENOENT);
 2295         
 2296                 hfsmp = VFSTOHFS(mp);
 2297                 bzero(&vq, sizeof(vq));
 2298                 vq.vq_flags = hfsmp->hfs_notification_conditions;
 2299                 return SYSCTL_OUT(req, &vq, sizeof(vq));;
 2300         };
 2301 
 2302         return (EOPNOTSUPP);
 2303 }
 2304 
 2305 
 2306 /*      This will return a vnode of either a directory or a data vnode based on an object id. If
 2307  *  it is a file id, its data fork will be returned.
 2308  */
 2309 static int
 2310 hfs_vget(mp, ino, vpp)
 2311         struct mount *mp;
 2312         void *ino;
 2313         struct vnode **vpp;
 2314 {
 2315         cnid_t cnid = *(cnid_t *)ino;
 2316         
 2317         /* Check for cnids that should't be exported. */
 2318         if ((cnid < kHFSFirstUserCatalogNodeID)
 2319         &&  (cnid != kHFSRootFolderID && cnid != kHFSRootParentID))
 2320                 return (ENOENT);
 2321         /* Don't export HFS Private Data dir. */
 2322         if (cnid == VFSTOHFS(mp)->hfs_privdir_desc.cd_cnid)
 2323                 return (ENOENT);
 2324 
 2325         return (hfs_getcnode(VFSTOHFS(mp), cnid, NULL, 0, NULL, NULL, vpp));
 2326 }
 2327 
 2328 /*
 2329  * Check to see if a given vnode is only referenced for events:
 2330  * [ entered with vp->v_interlock locked ]
 2331  */
 2332 static int
 2333 hfs_evtonly(struct vnode *vp)
 2334 {
 2335     int ubc_refcount;
 2336 
 2337     ubc_refcount = UBCINFOEXISTS(vp) ? 1 : 0;
 2338     return (vp->v_usecount == (ubc_refcount + EVTONLYREFS(vp)));
 2339 }
 2340 
 2341 /*
 2342  * Check to see if all non-system vnodes for a given mountpoint are events-only
 2343  */
 2344 static int
 2345 hfs_flush_evtonly(struct mount *mp, int flags, int dispose, struct proc *p)
 2346 {
 2347         struct vnode *vp, *nvp;
 2348         int busy = 0;
 2349     
 2350         simple_lock(&mntvnode_slock);
 2351 loop:
 2352         for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) {
 2353                 if (vp->v_mount != mp) goto loop;
 2354                 nvp = vp->v_mntvnodes.le_next;
 2355         
 2356                 simple_lock(&vp->v_interlock);
 2357         /*
 2358          * Skip over a vnodes marked VSYSTEM or VNOFLUSH.
 2359          */
 2360         if ((flags & SKIPSYSTEM) && ((vp->v_flag & VSYSTEM) || (vp->v_flag & VNOFLUSH))) {
 2361             simple_unlock(&vp->v_interlock);
 2362             continue;
 2363         };
 2364                 /*
 2365                  * Skip over a vnodes marked VSWAP.
 2366                  */
 2367                 if ((flags & SKIPSWAP) && (vp->v_flag & VSWAP)) {
 2368                         simple_unlock(&vp->v_interlock);
 2369                         continue;
 2370                 }
 2371         if (hfs_evtonly(vp)) {
 2372             if (dispose) {
 2373                 /* "dispose" implies "forcibly", a la "FORCECLOSE": */
 2374                 simple_unlock(&mntvnode_slock);
 2375                 vgonel(vp, p);
 2376                 simple_lock(&mntvnode_slock);
 2377             } else {
 2378                 simple_unlock(&vp->v_interlock);
 2379             };
 2380             continue;
 2381         };
 2382         
 2383         simple_unlock(&vp->v_interlock);
 2384         ++busy;
 2385         /* If asked to dispose, keep trying.  If only checking, the answer is now known. */
 2386         if (dispose) {
 2387             continue;
 2388         } else {
 2389             break;
 2390         };
 2391     }
 2392         simple_unlock(&mntvnode_slock);
 2393     
 2394     return (busy == 0);
 2395 }
 2396 
 2397 /*
 2398  * Flush out all the files in a filesystem.
 2399  */
 2400 static int
 2401 hfs_flushfiles(struct mount *mp, int flags, struct proc *p)
 2402 {
 2403         struct hfsmount *hfsmp;
 2404         struct vnode *skipvp = NULLVP;
 2405         struct vnode *rsrcvp;
 2406         int quotafilecnt;
 2407         int i;
 2408         int error;
 2409 
 2410         hfsmp = VFSTOHFS(mp);
 2411 
 2412 #if QUOTA
 2413         /*
 2414          * The open quota files have an indirect reference on
 2415          * the root directory vnode.  We must account for this
 2416          * extra reference when doing the intial vflush.
 2417          */
 2418         quotafilecnt = 0;
 2419         if (mp->mnt_flag & MNT_QUOTA) {
 2420 
 2421                 /* Find out how many quota files we have open. */
 2422                 for (i = 0; i < MAXQUOTAS; i++) {
 2423                         if (hfsmp->hfs_qfiles[i].qf_vp != NULLVP)
 2424                                 ++quotafilecnt;
 2425                 }
 2426 
 2427                 /* Obtain the root vnode so we can skip over it. */
 2428                 if (hfs_chashget(hfsmp->hfs_raw_dev, kRootDirID, 0,
 2429                                  &skipvp, &rsrcvp) == NULL) {
 2430                         skipvp = NULLVP;
 2431                 }
 2432         }
 2433 #endif /* QUOTA */
 2434 
 2435         error = vflush(mp, skipvp, SKIPSYSTEM | SKIPSWAP | flags);
 2436         /*
 2437          * If the vflush() call failed solely because there are
 2438          * some event-only vnodes in the list, then forcibly get
 2439          * rid of those vnodes before the final vflush() pass.
 2440          */
 2441         if ((error == EBUSY) && hfs_flush_evtonly(mp, SKIPSYSTEM | SKIPSWAP, 0, p)) {
 2442                 (void) hfs_flush_evtonly(mp, SKIPSYSTEM | SKIPSWAP, 1, p);
 2443         };
 2444         error = vflush(mp, skipvp, SKIPSYSTEM | flags);
 2445 
 2446 #if QUOTA
 2447         if (mp->mnt_flag & MNT_QUOTA) {
 2448                 if (skipvp) {
 2449                         /*
 2450                          * See if there are additional references on the
 2451                          * root vp besides the ones obtained from the open
 2452                          * quota files and the hfs_chashget call above.
 2453                          */
 2454                         if ((error == 0) &&
 2455                             (skipvp->v_usecount > (1 + quotafilecnt))) {
 2456                                 error = EBUSY;  /* root directory is still open */
 2457                         }
 2458                         vput(skipvp);
 2459                 }
 2460                 if (error && (flags & FORCECLOSE) == 0)
 2461                         return (error);
 2462 
 2463                 for (i = 0; i < MAXQUOTAS; i++) {
 2464                         if (hfsmp->hfs_qfiles[i].qf_vp == NULLVP)
 2465                                 continue;
 2466                         hfs_quotaoff(p, mp, i);
 2467                 }
 2468                 error = vflush(mp, NULLVP, SKIPSYSTEM | flags);
 2469         }
 2470 #endif /* QUOTA */
 2471 
 2472         return (error);
 2473 }
 2474 
 2475 /*
 2476  * Update volume encoding bitmap (HFS Plus only)
 2477  */
 2478 __private_extern__
 2479 void
 2480 hfs_setencodingbits(struct hfsmount *hfsmp, u_int32_t encoding)
 2481 {
 2482 #define  kIndexMacUkrainian     48  /* MacUkrainian encoding is 152 */
 2483 #define  kIndexMacFarsi         49  /* MacFarsi encoding is 140 */
 2484 
 2485         UInt32  index;
 2486 
 2487         switch (encoding) {
 2488         case kTextEncodingMacUkrainian:
 2489                 index = kIndexMacUkrainian;
 2490                 break;
 2491         case kTextEncodingMacFarsi:
 2492                 index = kIndexMacFarsi;
 2493                 break;
 2494         default:
 2495                 index = encoding;
 2496                 break;
 2497         }
 2498 
 2499         if (index < 64) {
 2500                 HFSTOVCB(hfsmp)->encodingsBitmap |= (u_int64_t)(1ULL << index);
 2501                 HFSTOVCB(hfsmp)->vcbFlags |= 0xFF00;
 2502         }
 2503 }
 2504 
 2505 /*
 2506  * Update volume stats
 2507  */
 2508 __private_extern__
 2509 int
 2510 hfs_volupdate(struct hfsmount *hfsmp, enum volop op, int inroot)
 2511 {
 2512         ExtendedVCB *vcb;
 2513 
 2514         vcb = HFSTOVCB(hfsmp);
 2515         vcb->vcbFlags |= 0xFF00;
 2516         vcb->vcbLsMod = time.tv_sec;
 2517 
 2518         switch (op) {
 2519         case VOL_UPDATE:
 2520                 break;
 2521         case VOL_MKDIR:
 2522                 if (vcb->vcbDirCnt != 0xFFFFFFFF)
 2523                         ++vcb->vcbDirCnt;
 2524                 if (inroot && vcb->vcbNmRtDirs != 0xFFFF)
 2525                         ++vcb->vcbNmRtDirs;
 2526                 break;
 2527         case VOL_RMDIR:
 2528                 if (vcb->vcbDirCnt != 0)
 2529                         --vcb->vcbDirCnt;
 2530                 if (inroot && vcb->vcbNmRtDirs != 0xFFFF)
 2531                         --vcb->vcbNmRtDirs;
 2532                 break;
 2533         case VOL_MKFILE:
 2534                 if (vcb->vcbFilCnt != 0xFFFFFFFF)
 2535                         ++vcb->vcbFilCnt;
 2536                 if (inroot && vcb->vcbNmFls != 0xFFFF)
 2537                         ++vcb->vcbNmFls;
 2538                 break;
 2539         case VOL_RMFILE:
 2540                 if (vcb->vcbFilCnt != 0)
 2541                         --vcb->vcbFilCnt;
 2542                 if (inroot && vcb->vcbNmFls != 0xFFFF)
 2543                         --vcb->vcbNmFls;
 2544                 break;
 2545         }
 2546 
 2547         if (hfsmp->jnl) {
 2548                 hfs_flushvolumeheader(hfsmp, 0, 0);
 2549         }
 2550 
 2551         return (0);
 2552 }
 2553 
 2554 
 2555 static int
 2556 hfs_flushMDB(struct hfsmount *hfsmp, int waitfor, int altflush)
 2557 {
 2558         ExtendedVCB *vcb = HFSTOVCB(hfsmp);
 2559         struct filefork *fp;
 2560         HFSMasterDirectoryBlock *mdb;
 2561         struct buf *bp = NULL;
 2562         int retval;
 2563         int sectorsize;
 2564         ByteCount namelen;
 2565 
 2566         sectorsize = hfsmp->hfs_phys_block_size;
 2567         retval = bread(hfsmp->hfs_devvp, HFS_PRI_SECTOR(sectorsize), sectorsize, NOCRED, &bp);
 2568         if (retval) {
 2569                 if (bp)
 2570                         brelse(bp);
 2571                 return retval;
 2572         }
 2573 
 2574         DBG_ASSERT(bp != NULL);
 2575         DBG_ASSERT(bp->b_data != NULL);
 2576         DBG_ASSERT(bp->b_bcount == size);
 2577 
 2578         if (hfsmp->jnl) {
 2579                 panic("hfs: standard hfs volumes should not be journaled!\n");
 2580         }
 2581 
 2582         mdb = (HFSMasterDirectoryBlock *)(bp->b_data + HFS_PRI_OFFSET(sectorsize));
 2583     
 2584         mdb->drCrDate   = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbCrDate)));
 2585         mdb->drLsMod    = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbLsMod)));
 2586         mdb->drAtrb     = SWAP_BE16 (vcb->vcbAtrb);
 2587         mdb->drNmFls    = SWAP_BE16 (vcb->vcbNmFls);
 2588         mdb->drAllocPtr = SWAP_BE16 (vcb->nextAllocation);
 2589         mdb->drClpSiz   = SWAP_BE32 (vcb->vcbClpSiz);
 2590         mdb->drNxtCNID  = SWAP_BE32 (vcb->vcbNxtCNID);
 2591         mdb->drFreeBks  = SWAP_BE16 (vcb->freeBlocks);
 2592 
 2593         namelen = strlen(vcb->vcbVN);
 2594         retval = utf8_to_hfs(vcb, namelen, vcb->vcbVN, mdb->drVN);
 2595         /* Retry with MacRoman in case that's how it was exported. */
 2596         if (retval)
 2597                 retval = utf8_to_mac_roman(namelen, vcb->vcbVN, mdb->drVN);
 2598         
 2599         mdb->drVolBkUp  = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbVolBkUp)));
 2600         mdb->drWrCnt    = SWAP_BE32 (vcb->vcbWrCnt);
 2601         mdb->drNmRtDirs = SWAP_BE16 (vcb->vcbNmRtDirs);
 2602         mdb->drFilCnt   = SWAP_BE32 (vcb->vcbFilCnt);
 2603         mdb->drDirCnt   = SWAP_BE32 (vcb->vcbDirCnt);
 2604         
 2605         bcopy(vcb->vcbFndrInfo, mdb->drFndrInfo, sizeof(mdb->drFndrInfo));
 2606 
 2607         fp = VTOF(vcb->extentsRefNum);
 2608         mdb->drXTExtRec[0].startBlock = SWAP_BE16 (fp->ff_extents[0].startBlock);
 2609         mdb->drXTExtRec[0].blockCount = SWAP_BE16 (fp->ff_extents[0].blockCount);
 2610         mdb->drXTExtRec[1].startBlock = SWAP_BE16 (fp->ff_extents[1].startBlock);
 2611         mdb->drXTExtRec[1].blockCount = SWAP_BE16 (fp->ff_extents[1].blockCount);
 2612         mdb->drXTExtRec[2].startBlock = SWAP_BE16 (fp->ff_extents[2].startBlock);
 2613         mdb->drXTExtRec[2].blockCount = SWAP_BE16 (fp->ff_extents[2].blockCount);
 2614         mdb->drXTFlSize = SWAP_BE32 (fp->ff_blocks * vcb->blockSize);
 2615         mdb->drXTClpSiz = SWAP_BE32 (fp->ff_clumpsize);
 2616         
 2617         fp = VTOF(vcb->catalogRefNum);
 2618         mdb->drCTExtRec[0].startBlock = SWAP_BE16 (fp->ff_extents[0].startBlock);
 2619         mdb->drCTExtRec[0].blockCount = SWAP_BE16 (fp->ff_extents[0].blockCount);
 2620         mdb->drCTExtRec[1].startBlock = SWAP_BE16 (fp->ff_extents[1].startBlock);
 2621         mdb->drCTExtRec[1].blockCount = SWAP_BE16 (fp->ff_extents[1].blockCount);
 2622         mdb->drCTExtRec[2].startBlock = SWAP_BE16 (fp->ff_extents[2].startBlock);
 2623         mdb->drCTExtRec[2].blockCount = SWAP_BE16 (fp->ff_extents[2].blockCount);
 2624         mdb->drCTFlSize = SWAP_BE32 (fp->ff_blocks * vcb->blockSize);
 2625         mdb->drCTClpSiz = SWAP_BE32 (fp->ff_clumpsize);
 2626 
 2627         /* If requested, flush out the alternate MDB */
 2628         if (altflush) {
 2629                 struct buf *alt_bp = NULL;
 2630                 u_long altIDSector;
 2631 
 2632                 altIDSector = HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
 2633 
 2634                 if (meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &alt_bp) == 0) {
 2635                         bcopy(mdb, alt_bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize);
 2636 
 2637                         (void) VOP_BWRITE(alt_bp);
 2638                 } else if (alt_bp)
 2639                         brelse(alt_bp);
 2640         }
 2641 
 2642         if (waitfor != MNT_WAIT)
 2643                 bawrite(bp);
 2644         else 
 2645                 retval = VOP_BWRITE(bp);
 2646  
 2647         MarkVCBClean( vcb );
 2648 
 2649         return (retval);
 2650 }
 2651 
 2652 /*
 2653  *  Flush any dirty in-memory mount data to the on-disk
 2654  *  volume header.
 2655  *
 2656  *  Note: the on-disk volume signature is intentionally
 2657  *  not flushed since the on-disk "H+" and "HX" signatures
 2658  *  are always stored in-memory as "H+".
 2659  */
 2660 __private_extern__
 2661 int
 2662 hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor, int altflush)
 2663 {
 2664         ExtendedVCB *vcb = HFSTOVCB(hfsmp);
 2665         struct filefork *fp;
 2666         HFSPlusVolumeHeader *volumeHeader;
 2667         int retval;
 2668         struct buf *bp;
 2669         int i;
 2670         int sectorsize;
 2671         int priIDSector;
 2672         int critical = 0;
 2673         u_int16_t  signature;
 2674         u_int16_t  version;
 2675 
 2676         if (hfsmp->hfs_flags & HFS_READ_ONLY) {
 2677                 return(0);
 2678         }
 2679         if (vcb->vcbSigWord == kHFSSigWord)
 2680                 return hfs_flushMDB(hfsmp, waitfor, altflush);
 2681 
 2682         if (altflush)
 2683                 critical = 1;
 2684         sectorsize = hfsmp->hfs_phys_block_size;
 2685         priIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
 2686                         HFS_PRI_SECTOR(sectorsize);
 2687 
 2688         // XXXdbg
 2689         hfs_global_shared_lock_acquire(hfsmp);
 2690         if (hfsmp->jnl) {
 2691                 if (journal_start_transaction(hfsmp->jnl) != 0) {
 2692                         hfs_global_shared_lock_release(hfsmp);
 2693                     return EINVAL;
 2694             }
 2695         }
 2696 
 2697         retval = meta_bread(hfsmp->hfs_devvp, priIDSector, sectorsize, NOCRED, &bp);
 2698         if (retval) {
 2699                 if (bp)
 2700                         brelse(bp);
 2701 
 2702                 if (hfsmp->jnl) {
 2703                         journal_end_transaction(hfsmp->jnl);
 2704                 }
 2705                 hfs_global_shared_lock_release(hfsmp);
 2706 
 2707                 printf("HFS: err %d reading VH blk (%s)\n", retval, vcb->vcbVN);
 2708                 return (retval);
 2709         }
 2710 
 2711         if (hfsmp->jnl) {
 2712                 journal_modify_block_start(hfsmp->jnl, bp);
 2713         }
 2714 
 2715         volumeHeader = (HFSPlusVolumeHeader *)((char *)bp->b_data + HFS_PRI_OFFSET(sectorsize));
 2716 
 2717         /*
 2718          * Sanity check what we just read.
 2719          */
 2720         signature = SWAP_BE16 (volumeHeader->signature);
 2721         version   = SWAP_BE16 (volumeHeader->version);
 2722         if ((signature != kHFSPlusSigWord && signature != kHFSXSigWord) ||
 2723             (version < kHFSPlusVersion) || (version > 100) ||
 2724             (SWAP_BE32 (volumeHeader->blockSize) != vcb->blockSize)) {
 2725 #if 1
 2726                 panic("HFS: corrupt VH on %s, sig 0x%04x, ver %d, blksize %d",
 2727                       vcb->vcbVN, signature, version,
 2728                       SWAP_BE32 (volumeHeader->blockSize));
 2729 #endif
 2730                 printf("HFS: corrupt VH blk (%s)\n", vcb->vcbVN);
 2731                 brelse(bp);
 2732                 return (EIO);
 2733         }
 2734 
 2735         /*
 2736          * For embedded HFS+ volumes, update create date if it changed
 2737          * (ie from a setattrlist call)
 2738          */
 2739         if ((vcb->hfsPlusIOPosOffset != 0) &&
 2740             (SWAP_BE32 (volumeHeader->createDate) != vcb->localCreateDate)) {
 2741                 struct buf *bp2;
 2742                 HFSMasterDirectoryBlock *mdb;
 2743 
 2744                 retval = meta_bread(hfsmp->hfs_devvp, HFS_PRI_SECTOR(sectorsize),
 2745                                 sectorsize, NOCRED, &bp2);
 2746                 if (retval) {
 2747                         if (bp2)
 2748                                 brelse(bp2);
 2749                         retval = 0;
 2750                 } else {
 2751                         mdb = (HFSMasterDirectoryBlock *)(bp2->b_data +
 2752                                 HFS_PRI_OFFSET(sectorsize));
 2753 
 2754                         if ( SWAP_BE32 (mdb->drCrDate) != vcb->localCreateDate )
 2755                           {
 2756                                 // XXXdbg
 2757                                 if (hfsmp->jnl) {
 2758                                     journal_modify_block_start(hfsmp->jnl, bp2);
 2759                                 }
 2760 
 2761                                 mdb->drCrDate = SWAP_BE32 (vcb->localCreateDate);       /* pick up the new create date */
 2762 
 2763                                 // XXXdbg
 2764                                 if (hfsmp->jnl) {
 2765                                         journal_modify_block_end(hfsmp->jnl, bp2);
 2766                                 } else {
 2767                                         (void) VOP_BWRITE(bp2);         /* write out the changes */
 2768                                 }
 2769                           }
 2770                         else
 2771                           {
 2772                                 brelse(bp2);                                            /* just release it */
 2773                           }
 2774                   }     
 2775         }
 2776 
 2777         /* Note: only update the lower 16 bits worth of attributes */
 2778         volumeHeader->attributes        = SWAP_BE32 ((SWAP_BE32 (volumeHeader->attributes) & 0xFFFF0000) + (UInt16) vcb->vcbAtrb);
 2779         volumeHeader->journalInfoBlock = SWAP_BE32(vcb->vcbJinfoBlock);
 2780         if (hfsmp->jnl) {
 2781                 volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSJMountVersion);
 2782         } else {
 2783                 volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSPlusMountVersion);
 2784         }
 2785         volumeHeader->createDate        = SWAP_BE32 (vcb->localCreateDate);  /* volume create date is in local time */
 2786         volumeHeader->modifyDate        = SWAP_BE32 (to_hfs_time(vcb->vcbLsMod));
 2787         volumeHeader->backupDate        = SWAP_BE32 (to_hfs_time(vcb->vcbVolBkUp));
 2788         volumeHeader->fileCount         = SWAP_BE32 (vcb->vcbFilCnt);
 2789         volumeHeader->folderCount       = SWAP_BE32 (vcb->vcbDirCnt);
 2790         volumeHeader->freeBlocks        = SWAP_BE32 (vcb->freeBlocks);
 2791         volumeHeader->nextAllocation    = SWAP_BE32 (vcb->nextAllocation);
 2792         volumeHeader->rsrcClumpSize     = SWAP_BE32 (vcb->vcbClpSiz);
 2793         volumeHeader->dataClumpSize     = SWAP_BE32 (vcb->vcbClpSiz);
 2794         volumeHeader->nextCatalogID     = SWAP_BE32 (vcb->vcbNxtCNID);
 2795         volumeHeader->writeCount        = SWAP_BE32 (vcb->vcbWrCnt);
 2796         volumeHeader->encodingsBitmap   = SWAP_BE64 (vcb->encodingsBitmap);
 2797 
 2798         if (bcmp(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo)) != 0)
 2799                 critical = 1;
 2800         bcopy(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo));
 2801 
 2802         /* Sync Extents over-flow file meta data */
 2803         fp = VTOF(vcb->extentsRefNum);
 2804         for (i = 0; i < kHFSPlusExtentDensity; i++) {
 2805                 volumeHeader->extentsFile.extents[i].startBlock =
 2806                         SWAP_BE32 (fp->ff_extents[i].startBlock);
 2807                 volumeHeader->extentsFile.extents[i].blockCount =
 2808                         SWAP_BE32 (fp->ff_extents[i].blockCount);
 2809         }
 2810         FTOC(fp)->c_flag &= ~C_MODIFIED;
 2811         volumeHeader->extentsFile.logicalSize = SWAP_BE64 (fp->ff_size);
 2812         volumeHeader->extentsFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
 2813         volumeHeader->extentsFile.clumpSize   = SWAP_BE32 (fp->ff_clumpsize);
 2814 
 2815         /* Sync Catalog file meta data */
 2816         fp = VTOF(vcb->catalogRefNum);
 2817         for (i = 0; i < kHFSPlusExtentDensity; i++) {
 2818                 volumeHeader->catalogFile.extents[i].startBlock =
 2819                         SWAP_BE32 (fp->ff_extents[i].startBlock);
 2820                 volumeHeader->catalogFile.extents[i].blockCount =
 2821                         SWAP_BE32 (fp->ff_extents[i].blockCount);
 2822         }
 2823         FTOC(fp)->c_flag &= ~C_MODIFIED;
 2824         volumeHeader->catalogFile.logicalSize = SWAP_BE64 (fp->ff_size);
 2825         volumeHeader->catalogFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
 2826         volumeHeader->catalogFile.clumpSize   = SWAP_BE32 (fp->ff_clumpsize);
 2827 
 2828         /* Sync Allocation file meta data */
 2829         fp = VTOF(vcb->allocationsRefNum);
 2830         for (i = 0; i < kHFSPlusExtentDensity; i++) {
 2831                 volumeHeader->allocationFile.extents[i].startBlock =
 2832                         SWAP_BE32 (fp->ff_extents[i].startBlock);
 2833                 volumeHeader->allocationFile.extents[i].blockCount =
 2834                         SWAP_BE32 (fp->ff_extents[i].blockCount);
 2835         }
 2836         FTOC(fp)->c_flag &= ~C_MODIFIED;
 2837         volumeHeader->allocationFile.logicalSize = SWAP_BE64 (fp->ff_size);
 2838         volumeHeader->allocationFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
 2839         volumeHeader->allocationFile.clumpSize   = SWAP_BE32 (fp->ff_clumpsize);
 2840 
 2841         /* If requested, flush out the alternate volume header */
 2842         if (altflush) {
 2843                 struct buf *alt_bp = NULL;
 2844                 u_long altIDSector;
 2845 
 2846                 altIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
 2847                         HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
 2848 
 2849                 if (meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &alt_bp) == 0) {
 2850                         if (hfsmp->jnl) {
 2851                                 journal_modify_block_start(hfsmp->jnl, alt_bp);
 2852                         }
 2853 
 2854                         bcopy(volumeHeader, alt_bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize);
 2855 
 2856                         if (hfsmp->jnl) {
 2857                                 journal_modify_block_end(hfsmp->jnl, alt_bp);
 2858                         } else {
 2859                                 (void) VOP_BWRITE(alt_bp);
 2860                         }
 2861                 } else if (alt_bp)
 2862                         brelse(alt_bp);
 2863         }
 2864 
 2865         // XXXdbg
 2866         if (hfsmp->jnl) {
 2867                 journal_modify_block_end(hfsmp->jnl, bp);
 2868                 journal_end_transaction(hfsmp->jnl);
 2869         } else {
 2870                 if (waitfor != MNT_WAIT)
 2871                         bawrite(bp);
 2872                 else {
 2873                     retval = VOP_BWRITE(bp);
 2874                     /* When critical data changes, flush the device cache */
 2875                     if (critical && (retval == 0)) {
 2876                         (void) VOP_IOCTL(hfsmp->hfs_devvp, DKIOCSYNCHRONIZECACHE,
 2877                                          NULL, FWRITE, NOCRED, current_proc());
 2878                     }
 2879                 }
 2880         }
 2881         hfs_global_shared_lock_release(hfsmp);
 2882  
 2883         vcb->vcbFlags &= 0x00FF;
 2884         return (retval);
 2885 }
 2886 
 2887 
 2888 /*
 2889  * Extend a file system.
 2890  */
 2891 static int
 2892 hfs_extendfs(struct mount *mp, u_int64_t newsize, struct proc *p)
 2893 {
 2894         struct  vnode *vp;
 2895         struct  vnode *devvp;
 2896         struct  buf *bp;
 2897         struct  hfsmount *hfsmp;
 2898         struct  filefork *fp = NULL;
 2899         ExtendedVCB  *vcb;
 2900         struct  cat_fork forkdata;
 2901         u_int64_t  oldsize;
 2902         u_int64_t  newblkcnt;
 2903         u_int32_t  addblks;
 2904         u_int64_t  sectorcnt;
 2905         u_int32_t  sectorsize;
 2906         daddr_t  prev_alt_sector;
 2907         daddr_t  bitmapblks;
 2908         int  error;
 2909 
 2910         hfsmp = VFSTOHFS(mp);
 2911         devvp = hfsmp->hfs_devvp;
 2912         vcb = HFSTOVCB(hfsmp);
 2913 
 2914         /*
 2915          * - HFS Plus file systems only. 
 2916          * - Journaling must be enabled.
 2917          * - No embedded volumes.
 2918          */
 2919         if ((vcb->vcbSigWord == kHFSSigWord) ||
 2920              (hfsmp->jnl == NULL) ||
 2921              (vcb->hfsPlusIOPosOffset != 0)) {
 2922                 return (EPERM);
 2923         }
 2924         /*
 2925          * If extending file system by non-root, then verify
 2926          * ownership and check permissions.
 2927          */
 2928         if (p->p_ucred->cr_uid != 0) {
 2929                 error = hfs_root(mp, &vp);
 2930                 if (error)
 2931                         return (error);
 2932                 error = hfs_owner_rights(hfsmp, VTOC(vp)->c_uid, p->p_ucred, p, 0);
 2933                 if (error == 0) {
 2934                         error = hfs_write_access(vp, p->p_ucred, p, false);
 2935                 }
 2936                 vput(vp);
 2937                 if (error)
 2938                         return (error);
 2939 
 2940                 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
 2941                 error = VOP_ACCESS(devvp, VREAD | VWRITE, p->p_ucred, p);
 2942                 VOP_UNLOCK(devvp, 0, p);
 2943                 if (error)
 2944                         return (error);
 2945         }
 2946         if (VOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, (caddr_t)&sectorsize, 0, FSCRED, p)) {
 2947                 return (ENXIO);
 2948         }
 2949         if (sectorsize != hfsmp->hfs_phys_block_size) {
 2950                 return (ENXIO);
 2951         }
 2952         if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&sectorcnt, 0, FSCRED, p)) {
 2953                 return (ENXIO);
 2954         }
 2955         if ((sectorsize * sectorcnt) < newsize) {
 2956                 printf("hfs_extendfs: not enough space on device\n");
 2957                 return (ENOSPC);
 2958         }
 2959         oldsize = (u_int64_t)hfsmp->hfs_phys_block_count *
 2960                   (u_int64_t)hfsmp->hfs_phys_block_size;
 2961 
 2962         /*
 2963          * Validate new size.
 2964          */
 2965         if ((newsize <= oldsize) || (newsize % vcb->blockSize)) {
 2966                 printf("hfs_extendfs: invalid size\n");
 2967                 return (EINVAL);
 2968         }
 2969         newblkcnt = newsize / vcb->blockSize;
 2970         if (newblkcnt > (u_int64_t)0xFFFFFFFF)
 2971                 return (EOVERFLOW);
 2972 
 2973         addblks = newblkcnt - vcb->totalBlocks;
 2974 
 2975         printf("hfs_extendfs: growing %s by %d blocks\n", vcb->vcbVN, addblks);
 2976         /*
 2977          * Enclose changes inside a transaction.
 2978          */
 2979         hfs_global_shared_lock_acquire(hfsmp);
 2980         if (journal_start_transaction(hfsmp->jnl) != 0) {
 2981                 hfs_global_shared_lock_release(hfsmp);
 2982                 return (EINVAL);
 2983         }
 2984 
 2985         /*
 2986          * Remember the location of existing alternate VH.
 2987          */
 2988         prev_alt_sector = (vcb->hfsPlusIOPosOffset / sectorsize) +
 2989                            HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
 2990 
 2991         vp = vcb->allocationsRefNum;
 2992         error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
 2993         if (error) {
 2994                 goto out2;
 2995         }
 2996         fp = VTOF(vp);
 2997         bcopy(&fp->ff_data, &forkdata, sizeof(forkdata));
 2998 
 2999         /*
 3000          * Calculate additional space required (if any) by allocation bitmap.
 3001          */
 3002         bitmapblks = roundup(newblkcnt / 8, vcb->vcbVBMIOSize) / vcb->blockSize;
 3003         if (bitmapblks > fp->ff_blocks)
 3004                 bitmapblks -= fp->ff_blocks;
 3005         else
 3006                 bitmapblks = 0;
 3007 
 3008         if (bitmapblks > 0) {
 3009                 daddr_t blkno;
 3010                 daddr_t blkcnt;
 3011 
 3012                 /*
 3013                  * Add a new extent to the allocation bitmap file.
 3014                  */
 3015                 error = AddFileExtent(vcb, fp, vcb->totalBlocks, bitmapblks);
 3016                 if (error) {
 3017                         printf("hfs_extendfs: error %d adding extents\n", error);
 3018                         goto out;
 3019                 }
 3020                 blkcnt = bitmapblks;
 3021                 blkno = fp->ff_blocks;
 3022                 fp->ff_blocks += bitmapblks;
 3023                 fp->ff_size += (u_int64_t)bitmapblks * (u_int64_t)vcb->blockSize;
 3024                 VTOC(vp)->c_blocks = fp->ff_blocks;
 3025                 /*
 3026                  * Zero out the new bitmap blocks.
 3027                  */
 3028                 {
 3029         
 3030                         bp = NULL;
 3031                         while (blkcnt > 0) {
 3032                                 error = meta_bread(vp, blkno, vcb->blockSize, NOCRED, &bp);
 3033                                 if (error) {
 3034                                         if (bp) {
 3035                                                 brelse(bp);
 3036                                         }
 3037                                         break;
 3038                                 }
 3039                                 bzero((char *)bp->b_data, vcb->blockSize);
 3040                                 bp->b_flags |= B_AGE;
 3041                                 error = bwrite(bp);
 3042                                 if (error)
 3043                                         break;
 3044                                 --blkcnt;
 3045                                 ++blkno;
 3046                         }
 3047                 }
 3048                 if (error) {
 3049                         printf("hfs_extendfs: error %d  clearing blocks\n", error);
 3050                         goto out;
 3051                 }
 3052                 /*
 3053                  * Mark the new bitmap space as allocated.
 3054                  */
 3055                 error = BlockMarkAllocated(vcb, vcb->totalBlocks, bitmapblks);
 3056                 if (error) {
 3057                         printf("hfs_extendfs: error %d setting bitmap\n", error);
 3058                         goto out;
 3059                 }
 3060         }
 3061         /*
 3062          * Mark the new alternate VH as allocated.
 3063          */
 3064         if (vcb->blockSize == 512)
 3065                 error = BlockMarkAllocated(vcb, vcb->totalBlocks + addblks - 2, 2);
 3066         else
 3067                 error = BlockMarkAllocated(vcb, vcb->totalBlocks + addblks - 1, 1);
 3068         if (error) {
 3069                 printf("hfs_extendfs: error %d setting bitmap (VH)\n", error);
 3070                 goto out;
 3071         }
 3072         /*
 3073          * Mark the old alternate VH as free.
 3074          */
 3075         if (vcb->blockSize == 512)
 3076                 (void) BlockMarkFree(vcb, vcb->totalBlocks - 2, 2);
 3077         else 
 3078                 (void) BlockMarkFree(vcb, vcb->totalBlocks - 1, 1);
 3079 
 3080         /*
 3081          * Adjust file system variables for new space.
 3082          */
 3083         vcb->totalBlocks += addblks;
 3084         vcb->freeBlocks += addblks - bitmapblks;
 3085         hfsmp->hfs_phys_block_count = newsize / sectorsize;
 3086 
 3087         MarkVCBDirty(vcb);
 3088         error = hfs_flushvolumeheader(hfsmp, MNT_WAIT, HFS_ALTFLUSH);
 3089         if (error) {
 3090                 printf("hfs_extendfs: couldn't flush volume headers (%d)", error);
 3091                 /*
 3092                  * Restore to old state.
 3093                  */
 3094                 fp->ff_size -= (u_int64_t)bitmapblks * (u_int64_t)vcb->blockSize;
 3095                 vcb->totalBlocks -= addblks;
 3096                 vcb->freeBlocks -= addblks - bitmapblks;
 3097                 hfsmp->hfs_phys_block_count = oldsize / sectorsize;
 3098                 MarkVCBDirty(vcb);
 3099                 if (vcb->blockSize == 512)
 3100                         (void) BlockMarkAllocated(vcb, vcb->totalBlocks - 2, 2);
 3101                 else
 3102                         (void) BlockMarkAllocated(vcb, vcb->totalBlocks - 1, 1);
 3103                 goto out;
 3104         }
 3105         /*
 3106          * Invalidate the old alternate volume header.
 3107          */
 3108         bp = NULL;
 3109         if (meta_bread(hfsmp->hfs_devvp, prev_alt_sector, sectorsize,
 3110                        NOCRED, &bp) == 0) {
 3111                 journal_modify_block_start(hfsmp->jnl, bp);
 3112                 bzero(bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize);
 3113                 journal_modify_block_end(hfsmp->jnl, bp);
 3114         } else if (bp) {
 3115                 brelse(bp);
 3116         }
 3117 out:
 3118         if (error && fp) {
 3119                 /* Restore allocation fork. */
 3120                 bcopy(&forkdata, &fp->ff_data, sizeof(forkdata));
 3121                 VTOC(vp)->c_blocks = fp->ff_blocks;
 3122 
 3123         }
 3124         VOP_UNLOCK(vp, 0, p);
 3125 out2:
 3126         journal_end_transaction(hfsmp->jnl);
 3127         hfs_global_shared_lock_release(hfsmp);
 3128 
 3129         return (error);
 3130 }
 3131 
 3132 
 3133 /*
 3134  * hfs vfs operations.
 3135  */
 3136 struct vfsops hfs_vfsops = {
 3137         hfs_mount,
 3138         hfs_start,
 3139         hfs_unmount,
 3140         hfs_root,
 3141         hfs_quotactl,
 3142         hfs_statfs,
 3143         hfs_sync,
 3144         hfs_vget,
 3145         hfs_fhtovp,
 3146         hfs_vptofh,
 3147         hfs_init,
 3148         hfs_sysctl
 3149 };

Cache object: c641a7a8b0846ccdd9e64ffd049b7f1f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.