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/fs/msdosfs/msdosfs_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 /* $FreeBSD$ */
    2 /*      $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws Exp $   */
    3 
    4 /*-
    5  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
    6  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
    7  * All rights reserved.
    8  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by TooLs GmbH.
   21  * 4. The name of TooLs GmbH may not be used to endorse or promote products
   22  *    derived from this software without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
   25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   27  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   29  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   30  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   31  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   32  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   33  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   34  */
   35 /*-
   36  * Written by Paul Popelka (paulp@uts.amdahl.com)
   37  *
   38  * You can do anything you want with this software, just don't say you wrote
   39  * it, and don't remove this notice.
   40  *
   41  * This software is provided "as is".
   42  *
   43  * The author supplies this software to be publicly redistributed on the
   44  * understanding that the author is not responsible for the correct
   45  * functioning of this software in any circumstances and is not liable for
   46  * any damages caused by this software.
   47  *
   48  * October 1992
   49  */
   50 
   51 #include <sys/param.h>
   52 #include <sys/systm.h>
   53 #include <sys/conf.h>
   54 #include <sys/namei.h>
   55 #include <sys/proc.h>
   56 #include <sys/kernel.h>
   57 #include <sys/vnode.h>
   58 #include <sys/mount.h>
   59 #include <sys/bio.h>
   60 #include <sys/buf.h>
   61 #include <sys/fcntl.h>
   62 #include <sys/malloc.h>
   63 #include <sys/stat.h>                           /* defines ALLPERMS */
   64 #include <sys/iconv.h>
   65 #include <sys/mutex.h>
   66 
   67 #include <fs/msdosfs/bpb.h>
   68 #include <fs/msdosfs/bootsect.h>
   69 #include <fs/msdosfs/msdosfsmount.h>
   70 #include <fs/msdosfs/direntry.h>
   71 #include <fs/msdosfs/denode.h>
   72 #include <fs/msdosfs/fat.h>
   73 
   74 #include "opt_msdosfs.h"
   75 
   76 #define MSDOSFS_DFLTBSIZE       4096
   77 
   78 #if 1 /*def PC98*/
   79 /*
   80  * XXX - The boot signature formatted by NEC PC-98 DOS looks like a
   81  *       garbage or a random value :-{
   82  *       If you want to use that broken-signatured media, define the
   83  *       following symbol even though PC/AT.
   84  *       (ex. mount PC-98 DOS formatted FD on PC/AT)
   85  */
   86 #define MSDOSFS_NOCHECKSIG
   87 #endif
   88 
   89 MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure");
   90 static MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table");
   91 
   92 struct iconv_functions *msdosfs_iconv = NULL;
   93 
   94 static int      update_mp(struct mount *mp, struct msdosfs_args *argp,
   95                     struct thread *td);
   96 static int      mountmsdosfs(struct vnode *devvp, struct mount *mp,
   97                     struct thread *td, struct msdosfs_args *argp);
   98 static vfs_fhtovp_t     msdosfs_fhtovp;
   99 static vfs_omount_t     msdosfs_omount;
  100 static vfs_root_t       msdosfs_root;
  101 static vfs_statfs_t     msdosfs_statfs;
  102 static vfs_sync_t       msdosfs_sync;
  103 static vfs_unmount_t    msdosfs_unmount;
  104 static vfs_vptofh_t     msdosfs_vptofh;
  105 
  106 /* Maximum length of a character set name (arbitrary). */
  107 #define MAXCSLEN        64
  108 
  109 static int
  110 update_mp(mp, argp, td)
  111         struct mount *mp;
  112         struct msdosfs_args *argp;
  113         struct thread *td;
  114 {
  115         struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
  116         char *dos, *win, *local;
  117         int error;
  118 
  119         if (argp->flags & MSDOSFSMNT_KICONV) {
  120                 if (msdosfs_iconv) {
  121                         win = malloc(MAXCSLEN, M_TEMP, M_WAITOK);
  122                         local = malloc(MAXCSLEN, M_TEMP, M_WAITOK);
  123                         dos = malloc(MAXCSLEN, M_TEMP, M_WAITOK);
  124                         if ((error = copyinstr(argp->cs_win, win, MAXCSLEN,
  125                             NULL)) != 0)
  126                                 goto iconvdone;
  127                         if ((error = copyinstr(argp->cs_local, local, MAXCSLEN,
  128                             NULL)) != 0)
  129                                 goto iconvdone;
  130                         if ((error = copyinstr(argp->cs_dos, dos, MAXCSLEN,
  131                             NULL)) != 0)
  132                                 goto iconvdone;
  133                         msdosfs_iconv->open(win, local, &pmp->pm_u2w);
  134                         msdosfs_iconv->open(local, win, &pmp->pm_w2u);
  135                         msdosfs_iconv->open(dos, local, &pmp->pm_u2d);
  136                         msdosfs_iconv->open(local, dos, &pmp->pm_d2u);
  137 iconvdone:              free(win, M_TEMP);
  138                         free(local, M_TEMP);
  139                         free(dos, M_TEMP);
  140                         if (error != 0)
  141                                 return (error);
  142                 } else {
  143                         pmp->pm_w2u = NULL;
  144                         pmp->pm_u2w = NULL;
  145                         pmp->pm_d2u = NULL;
  146                         pmp->pm_u2d = NULL;
  147                 }
  148         }
  149 
  150         pmp->pm_gid = argp->gid;
  151         pmp->pm_uid = argp->uid;
  152         pmp->pm_mask = argp->mask & ALLPERMS;
  153         pmp->pm_dirmask = argp->dirmask & ALLPERMS;
  154         pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT;
  155 
  156         if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
  157                 pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
  158         else if (!(pmp->pm_flags &
  159             (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) {
  160                 struct vnode *rootvp;
  161 
  162                 /*
  163                  * Try to divine whether to support Win'95 long filenames
  164                  */
  165                 if (FAT32(pmp))
  166                         pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
  167                 else {
  168                         if ((error = msdosfs_root(mp, &rootvp, td)) != 0)
  169                                 return error;
  170                         pmp->pm_flags |= findwin95(VTODE(rootvp))
  171                                 ? MSDOSFSMNT_LONGNAME
  172                                         : MSDOSFSMNT_SHORTNAME;
  173                         vput(rootvp);
  174                 }
  175         }
  176         return 0;
  177 }
  178 
  179 /*
  180  * mp - path - addr in user space of mount point (ie /usr or whatever)
  181  * data - addr in user space of mount params including the name of the block
  182  * special file to treat as a filesystem.
  183  */
  184 static int
  185 msdosfs_omount(mp, path, data, td)
  186         struct mount *mp;
  187         char *path;
  188         caddr_t data;
  189         struct thread *td;
  190 {
  191         struct vnode *devvp;      /* vnode for blk device to mount */
  192         struct msdosfs_args args; /* will hold data from mount request */
  193         /* msdosfs specific mount control block */
  194         struct msdosfsmount *pmp = NULL;
  195         struct nameidata ndp;
  196         size_t size;
  197         int error, flags;
  198         mode_t accessmode;
  199 
  200         error = copyin(data, (caddr_t)&args, sizeof(struct msdosfs_args));
  201         if (error)
  202                 return (error);
  203         if (args.magic != MSDOSFS_ARGSMAGIC)
  204                 args.flags = 0;
  205         /*
  206          * If updating, check whether changing from read-only to
  207          * read/write; if there is no device name, that's all we do.
  208          */
  209         if (mp->mnt_flag & MNT_UPDATE) {
  210                 pmp = VFSTOMSDOSFS(mp);
  211                 error = 0;
  212                 if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) {
  213                         error = VFS_SYNC(mp, MNT_WAIT, td->td_ucred, td);
  214                         if (error)
  215                                 return (error);
  216                         flags = WRITECLOSE;
  217                         if (mp->mnt_flag & MNT_FORCE)
  218                                 flags |= FORCECLOSE;
  219                         error = vflush(mp, 0, flags, td);
  220                 }
  221                 if (!error && (mp->mnt_flag & MNT_RELOAD))
  222                         /* not yet implemented */
  223                         error = EOPNOTSUPP;
  224                 if (error)
  225                         return (error);
  226                 if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
  227                         /*
  228                          * If upgrade to read-write by non-root, then verify
  229                          * that user has necessary permissions on the device.
  230                          */
  231                         if (suser(td)) {
  232                                 devvp = pmp->pm_devvp;
  233                                 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
  234                                 error = VOP_ACCESS(devvp, VREAD | VWRITE,
  235                                                    td->td_ucred, td);
  236                                 if (error) {
  237                                         VOP_UNLOCK(devvp, 0, td);
  238                                         return (error);
  239                                 }
  240                                 VOP_UNLOCK(devvp, 0, td);
  241                         }
  242                         pmp->pm_flags &= ~MSDOSFSMNT_RONLY;
  243 
  244                         /* Now that the volume is modifiable, mark it dirty. */
  245                         error = markvoldirty(pmp, 1);
  246                         if (error)
  247                                 return (error);
  248                 }
  249                 if (args.fspec == 0) {
  250 #ifdef  __notyet__      /* doesn't work correctly with current mountd   XXX */
  251                         if (args.flags & MSDOSFSMNT_MNTOPT) {
  252                                 pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT;
  253                                 pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT;
  254                                 if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
  255                                         pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
  256                         }
  257 #endif
  258                         /*
  259                          * Process export requests.
  260                          */
  261                         if ((args.export.ex_flags & MNT_EXPORTED) != 0 &&
  262                             (pmp->pm_flags & MSDOSFS_LARGEFS) != 0)
  263                                 return (EOPNOTSUPP);
  264                         return (vfs_export(mp, &args.export));
  265                 }
  266         }
  267         /*
  268          * Not an update, or updating the name: look up the name
  269          * and verify that it refers to a sensible disk device.
  270          */
  271         NDINIT(&ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td);
  272         error = namei(&ndp);
  273         if (error)
  274                 return (error);
  275         devvp = ndp.ni_vp;
  276         NDFREE(&ndp, NDF_ONLY_PNBUF);
  277 
  278         if (!vn_isdisk(devvp, &error)) {
  279                 vrele(devvp);
  280                 return (error);
  281         }
  282         /*
  283          * If mount by non-root, then verify that user has necessary
  284          * permissions on the device.
  285          */
  286         if (suser(td)) {
  287                 accessmode = VREAD;
  288                 if ((mp->mnt_flag & MNT_RDONLY) == 0)
  289                         accessmode |= VWRITE;
  290                 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
  291                 error = VOP_ACCESS(devvp, accessmode, td->td_ucred, td);
  292                 if (error) {
  293                         vput(devvp);
  294                         return (error);
  295                 }
  296                 VOP_UNLOCK(devvp, 0, td);
  297         }
  298         if ((mp->mnt_flag & MNT_UPDATE) == 0) {
  299                 error = mountmsdosfs(devvp, mp, td, &args);
  300 #ifdef MSDOSFS_DEBUG            /* only needed for the printf below */
  301                 pmp = VFSTOMSDOSFS(mp);
  302 #endif
  303         } else {
  304                 if (devvp != pmp->pm_devvp)
  305                         error = EINVAL; /* XXX needs translation */
  306                 else
  307                         vrele(devvp);
  308         }
  309         if (error) {
  310                 vrele(devvp);
  311                 return (error);
  312         }
  313 
  314         error = update_mp(mp, &args, td);
  315         if (error) {
  316                 if ((mp->mnt_flag & MNT_UPDATE) == 0)
  317                         msdosfs_unmount(mp, MNT_FORCE, td);
  318                 return error;
  319         }
  320         (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
  321             &size);
  322         bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
  323         (void) msdosfs_statfs(mp, &mp->mnt_stat, td);
  324 #ifdef MSDOSFS_DEBUG
  325         printf("msdosfs_omount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap);
  326 #endif
  327         return (0);
  328 }
  329 
  330 static int
  331 mountmsdosfs(devvp, mp, td, argp)
  332         struct vnode *devvp;
  333         struct mount *mp;
  334         struct thread *td;
  335         struct msdosfs_args *argp;
  336 {
  337         struct msdosfsmount *pmp;
  338         struct buf *bp;
  339         struct cdev *dev = devvp->v_rdev;
  340         union bootsector *bsp;
  341         struct byte_bpb33 *b33;
  342         struct byte_bpb50 *b50;
  343         struct byte_bpb710 *b710;
  344         u_int8_t SecPerClust;
  345         u_long clusters;
  346         int     ronly, error;
  347 
  348         /*
  349          * Disallow multiple mounts of the same device.
  350          * Disallow mounting of a device that is currently in use
  351          * (except for root, which might share swap device for miniroot).
  352          * Flush out any old buffers remaining from a previous use.
  353          */
  354         error = vfs_mountedon(devvp);
  355         if (error)
  356                 return (error);
  357         if (vcount(devvp) > 1)
  358                 return (EBUSY);
  359         vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
  360         error = vinvalbuf(devvp, V_SAVE, td->td_ucred, td, 0, 0);
  361         if (error) {
  362                 VOP_UNLOCK(devvp, 0, td);
  363                 return (error);
  364         }
  365 
  366         ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
  367         /*
  368          * XXX: open the device with read and write access even if only
  369          * read access is needed now.  Write access is needed if the
  370          * filesystem is ever mounted read/write, and we don't change the
  371          * access mode for remounts.
  372          */
  373 #ifdef notyet
  374         error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, td, -1);
  375 #else
  376         error = VOP_OPEN(devvp, FREAD | FWRITE, FSCRED, td, -1);
  377 #endif
  378         VOP_UNLOCK(devvp, 0, td);
  379         if (error)
  380                 return (error);
  381 
  382         bp  = NULL; /* both used in error_exit */
  383         pmp = NULL;
  384 
  385         /*
  386          * Read the boot sector of the filesystem, and then check the
  387          * boot signature.  If not a dos boot sector then error out.
  388          *
  389          * NOTE: 2048 is a maximum sector size in current...
  390          */
  391         error = bread(devvp, 0, 2048, NOCRED, &bp);
  392         if (error)
  393                 goto error_exit;
  394         bp->b_flags |= B_AGE;
  395         bsp = (union bootsector *)bp->b_data;
  396         b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
  397         b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
  398         b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;
  399 
  400 #ifndef MSDOSFS_NOCHECKSIG
  401         if (bsp->bs50.bsBootSectSig0 != BOOTSIG0
  402             || bsp->bs50.bsBootSectSig1 != BOOTSIG1) {
  403                 error = EINVAL;
  404                 goto error_exit;
  405         }
  406 #endif
  407 
  408         pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO);
  409         pmp->pm_mountp = mp;
  410 
  411         /*
  412          * Compute several useful quantities from the bpb in the
  413          * bootsector.  Copy in the dos 5 variant of the bpb then fix up
  414          * the fields that are different between dos 5 and dos 3.3.
  415          */
  416         SecPerClust = b50->bpbSecPerClust;
  417         pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
  418         if (pmp->pm_BytesPerSec < DEV_BSIZE) {
  419                 error = EINVAL;
  420                 goto error_exit;
  421         }
  422         pmp->pm_ResSectors = getushort(b50->bpbResSectors);
  423         pmp->pm_FATs = b50->bpbFATs;
  424         pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
  425         pmp->pm_Sectors = getushort(b50->bpbSectors);
  426         pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
  427         pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
  428         pmp->pm_Heads = getushort(b50->bpbHeads);
  429         pmp->pm_Media = b50->bpbMedia;
  430 
  431         /* calculate the ratio of sector size to DEV_BSIZE */
  432         pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE;
  433 
  434         /* XXX - We should probably check more values here */
  435         if (!pmp->pm_BytesPerSec || !SecPerClust
  436                 || !pmp->pm_Heads
  437 #ifdef PC98
  438                 || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) {
  439 #else
  440                 || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) {
  441 #endif
  442                 error = EINVAL;
  443                 goto error_exit;
  444         }
  445 
  446         if (pmp->pm_Sectors == 0) {
  447                 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
  448                 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
  449         } else {
  450                 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
  451                 pmp->pm_HugeSectors = pmp->pm_Sectors;
  452         }
  453 #ifndef MSDOSFS_LARGE
  454         if (pmp->pm_HugeSectors > 0xffffffff / 
  455             (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) {
  456                 /*
  457                  * We cannot deal currently with this size of disk
  458                  * due to fileid limitations (see msdosfs_getattr and
  459                  * msdosfs_readdir)
  460                  */
  461                 error = EINVAL;
  462                 printf("mountmsdosfs(): disk too big, sorry\n");
  463                 goto error_exit;
  464         }
  465 #endif  /* !MSDOSFS_LARGE */
  466 
  467         if (pmp->pm_RootDirEnts == 0) {
  468                 if (bsp->bs710.bsBootSectSig2 != BOOTSIG2
  469                     || bsp->bs710.bsBootSectSig3 != BOOTSIG3
  470                     || pmp->pm_Sectors
  471                     || pmp->pm_FATsecs
  472                     || getushort(b710->bpbFSVers)) {
  473                         error = EINVAL;
  474                         printf("mountmsdosfs(): bad FAT32 filesystem\n");
  475                         goto error_exit;
  476                 }
  477                 pmp->pm_fatmask = FAT32_MASK;
  478                 pmp->pm_fatmult = 4;
  479                 pmp->pm_fatdiv = 1;
  480                 pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
  481                 if (getushort(b710->bpbExtFlags) & FATMIRROR)
  482                         pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
  483                 else
  484                         pmp->pm_flags |= MSDOSFS_FATMIRROR;
  485         } else
  486                 pmp->pm_flags |= MSDOSFS_FATMIRROR;
  487 
  488         /*
  489          * Check a few values (could do some more):
  490          * - logical sector size: power of 2, >= block size
  491          * - sectors per cluster: power of 2, >= 1
  492          * - number of sectors:   >= 1, <= size of partition
  493          * - number of FAT sectors: >= 1
  494          */
  495         if ( (SecPerClust == 0)
  496           || (SecPerClust & (SecPerClust - 1))
  497           || (pmp->pm_BytesPerSec < DEV_BSIZE)
  498           || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1))
  499           || (pmp->pm_HugeSectors == 0)
  500           || (pmp->pm_FATsecs == 0)
  501         ) {
  502                 error = EINVAL;
  503                 goto error_exit;
  504         }
  505 
  506         pmp->pm_HugeSectors *= pmp->pm_BlkPerSec;
  507         pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; /* XXX not used? */
  508         pmp->pm_FATsecs     *= pmp->pm_BlkPerSec;
  509         SecPerClust         *= pmp->pm_BlkPerSec;
  510 
  511         pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec;
  512 
  513         if (FAT32(pmp)) {
  514                 pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
  515                 pmp->pm_firstcluster = pmp->pm_fatblk
  516                         + (pmp->pm_FATs * pmp->pm_FATsecs);
  517                 pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec;
  518         } else {
  519                 pmp->pm_rootdirblk = pmp->pm_fatblk +
  520                         (pmp->pm_FATs * pmp->pm_FATsecs);
  521                 pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
  522                                        + DEV_BSIZE - 1)
  523                         / DEV_BSIZE; /* in blocks */
  524                 pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
  525         }
  526 
  527         pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
  528             SecPerClust + 1;
  529         pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; /* XXX not used? */
  530 
  531         if (pmp->pm_fatmask == 0) {
  532                 if (pmp->pm_maxcluster
  533                     <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
  534                         /*
  535                          * This will usually be a floppy disk. This size makes
  536                          * sure that one fat entry will not be split across
  537                          * multiple blocks.
  538                          */
  539                         pmp->pm_fatmask = FAT12_MASK;
  540                         pmp->pm_fatmult = 3;
  541                         pmp->pm_fatdiv = 2;
  542                 } else {
  543                         pmp->pm_fatmask = FAT16_MASK;
  544                         pmp->pm_fatmult = 2;
  545                         pmp->pm_fatdiv = 1;
  546                 }
  547         }
  548 
  549         clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv;
  550         if (pmp->pm_maxcluster >= clusters) {
  551                 printf("Warning: number of clusters (%ld) exceeds FAT "
  552                     "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters);
  553                 pmp->pm_maxcluster = clusters - 1;
  554         }
  555 
  556 
  557         if (FAT12(pmp))
  558                 pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
  559         else
  560                 pmp->pm_fatblocksize = MSDOSFS_DFLTBSIZE;
  561 
  562         pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE;
  563         pmp->pm_bnshift = ffs(DEV_BSIZE) - 1;
  564 
  565         /*
  566          * Compute mask and shift value for isolating cluster relative byte
  567          * offsets and cluster numbers from a file offset.
  568          */
  569         pmp->pm_bpcluster = SecPerClust * DEV_BSIZE;
  570         pmp->pm_crbomask = pmp->pm_bpcluster - 1;
  571         pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
  572 
  573         /*
  574          * Check for valid cluster size
  575          * must be a power of 2
  576          */
  577         if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
  578                 error = EINVAL;
  579                 goto error_exit;
  580         }
  581 
  582         /*
  583          * Release the bootsector buffer.
  584          */
  585         brelse(bp);
  586         bp = NULL;
  587 
  588         /*
  589          * Check FSInfo.
  590          */
  591         if (pmp->pm_fsinfo) {
  592                 struct fsinfo *fp;
  593 
  594                 if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp),
  595                     NOCRED, &bp)) != 0)
  596                         goto error_exit;
  597                 fp = (struct fsinfo *)bp->b_data;
  598                 if (!bcmp(fp->fsisig1, "RRaA", 4)
  599                     && !bcmp(fp->fsisig2, "rrAa", 4)
  600                     && !bcmp(fp->fsisig3, "\0\0\125\252", 4)
  601                     && !bcmp(fp->fsisig4, "\0\0\125\252", 4)) {
  602                         pmp->pm_nxtfree = getulong(fp->fsinxtfree);
  603                         if (pmp->pm_nxtfree == 0xffffffff)
  604                                 pmp->pm_nxtfree = CLUST_FIRST;
  605                 } else
  606                         pmp->pm_fsinfo = 0;
  607                 brelse(bp);
  608                 bp = NULL;
  609         }
  610 
  611         /*
  612          * Check and validate (or perhaps invalidate?) the fsinfo structure?
  613          */
  614         if (pmp->pm_fsinfo && pmp->pm_nxtfree > pmp->pm_maxcluster) {
  615                 printf(
  616                 "Next free cluster in FSInfo (%lu) exceeds maxcluster (%lu)\n",
  617                     pmp->pm_nxtfree, pmp->pm_maxcluster);
  618                 error = EINVAL;
  619                 goto error_exit;
  620         }
  621 
  622         /*
  623          * Allocate memory for the bitmap of allocated clusters, and then
  624          * fill it in.
  625          */
  626         pmp->pm_inusemap = malloc(howmany(pmp->pm_maxcluster + 1, N_INUSEBITS)
  627                                   * sizeof(*pmp->pm_inusemap),
  628                                   M_MSDOSFSFAT, M_WAITOK);
  629 
  630         /*
  631          * fillinusemap() needs pm_devvp.
  632          */
  633         pmp->pm_dev = dev;
  634         pmp->pm_devvp = devvp;
  635 
  636         /*
  637          * Have the inuse map filled in.
  638          */
  639         if ((error = fillinusemap(pmp)) != 0)
  640                 goto error_exit;
  641 
  642         /*
  643          * If they want fat updates to be synchronous then let them suffer
  644          * the performance degradation in exchange for the on disk copy of
  645          * the fat being correct just about all the time.  I suppose this
  646          * would be a good thing to turn on if the kernel is still flakey.
  647          */
  648         if (mp->mnt_flag & MNT_SYNCHRONOUS)
  649                 pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;
  650 
  651         /*
  652          * Finish up.
  653          */
  654         if (ronly)
  655                 pmp->pm_flags |= MSDOSFSMNT_RONLY;
  656         else {
  657                 /* Mark the volume dirty while it is mounted read/write. */
  658                 if ((error = markvoldirty(pmp, 1)) != 0)
  659                         goto error_exit;
  660                 pmp->pm_fmod = 1;
  661         }
  662         mp->mnt_data = (qaddr_t) pmp;
  663         mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
  664         mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
  665         mp->mnt_flag |= MNT_LOCAL;
  666         devvp->v_rdev->si_mountpoint = mp;
  667 
  668 #ifdef MSDOSFS_LARGE
  669         msdosfs_fileno_init(mp);
  670 #endif
  671 
  672         return 0;
  673 
  674 error_exit:
  675         if (bp)
  676                 brelse(bp);
  677         /* XXX: see comment above VOP_OPEN. */
  678 #ifdef notyet
  679         (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, NOCRED, td);
  680 #else
  681         (void)VOP_CLOSE(devvp, FREAD | FWRITE, NOCRED, td);
  682 #endif
  683         if (pmp) {
  684                 if (pmp->pm_inusemap)
  685                         free(pmp->pm_inusemap, M_MSDOSFSFAT);
  686                 free(pmp, M_MSDOSFSMNT);
  687                 mp->mnt_data = (qaddr_t)0;
  688         }
  689         return (error);
  690 }
  691 
  692 /*
  693  * Unmount the filesystem described by mp.
  694  */
  695 static int
  696 msdosfs_unmount(mp, mntflags, td)
  697         struct mount *mp;
  698         int mntflags;
  699         struct thread *td;
  700 {
  701         struct msdosfsmount *pmp;
  702         int error, flags;
  703 
  704         flags = 0;
  705         if (mntflags & MNT_FORCE)
  706                 flags |= FORCECLOSE;
  707         error = vflush(mp, 0, flags, td);
  708         if (error)
  709                 return error;
  710         pmp = VFSTOMSDOSFS(mp);
  711         if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
  712                 if (pmp->pm_w2u)
  713                         msdosfs_iconv->close(pmp->pm_w2u);
  714                 if (pmp->pm_u2w)
  715                         msdosfs_iconv->close(pmp->pm_u2w);
  716                 if (pmp->pm_d2u)
  717                         msdosfs_iconv->close(pmp->pm_d2u);
  718                 if (pmp->pm_u2d)
  719                         msdosfs_iconv->close(pmp->pm_u2d);
  720         }
  721         pmp->pm_devvp->v_rdev->si_mountpoint = NULL;
  722 
  723         /* If the volume was mounted read/write, mark it clean now. */
  724         if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) {
  725                 error = markvoldirty(pmp, 0);
  726                 if (error && (flags & FORCECLOSE) == 0)
  727                         return (error);
  728         }
  729 #ifdef MSDOSFS_DEBUG
  730         {
  731                 struct vnode *vp = pmp->pm_devvp;
  732 
  733                 VI_LOCK(vp);
  734                 printf("msdosfs_umount(): just before calling VOP_CLOSE()\n");
  735                 printf("iflag %08lx, usecount %d, writecount %d, holdcnt %ld\n",
  736                     vp->vi_flag, vp->v_usecount, vp->v_writecount,
  737                     vp->v_holdcnt);
  738                 printf("id %lu, mount %p, op %p\n",
  739                     vp->v_id, vp->v_mount, vp->v_op);
  740                 printf("freef %p, freeb %p, mount %p\n",
  741                     TAILQ_NEXT(vp, v_freelist), vp->v_freelist.tqe_prev,
  742                     vp->v_mount);
  743                 printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n",
  744                     TAILQ_FIRST(&vp->v_cleanblkhd),
  745                     TAILQ_FIRST(&vp->v_dirtyblkhd),
  746                     vp->v_numoutput, vp->v_type);
  747                 printf("union %p, tag %s, data[0] %08x, data[1] %08x\n",
  748                     vp->v_socket, vp->v_tag,
  749                     ((u_int *)vp->v_data)[0],
  750                     ((u_int *)vp->v_data)[1]);
  751                 VI_UNLOCK(vp);
  752         }
  753 #endif
  754         /* XXX: see comment above VOP_OPEN. */
  755 #ifdef notyet
  756         error = VOP_CLOSE(pmp->pm_devvp,
  757             (pmp->pm_flags & MSDOSFSMNT_RONLY) ? FREAD : FREAD | FWRITE,
  758             NOCRED, td);
  759 #else
  760         error = VOP_CLOSE(pmp->pm_devvp, FREAD | FWRITE, NOCRED, td);
  761 #endif
  762         vrele(pmp->pm_devvp);
  763         free(pmp->pm_inusemap, M_MSDOSFSFAT);
  764 #ifdef MSDOSFS_LARGE
  765         msdosfs_fileno_free(mp);
  766 #endif
  767         free(pmp, M_MSDOSFSMNT);
  768         mp->mnt_data = (qaddr_t)0;
  769         mp->mnt_flag &= ~MNT_LOCAL;
  770         return (error);
  771 }
  772 
  773 static int
  774 msdosfs_root(mp, vpp, td)
  775         struct mount *mp;
  776         struct vnode **vpp;
  777         struct thread *td;
  778 {
  779         struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
  780         struct denode *ndep;
  781         int error;
  782 
  783 #ifdef MSDOSFS_DEBUG
  784         printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp);
  785 #endif
  786         error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep);
  787         if (error)
  788                 return (error);
  789         *vpp = DETOV(ndep);
  790         return (0);
  791 }
  792 
  793 static int
  794 msdosfs_statfs(mp, sbp, td)
  795         struct mount *mp;
  796         struct statfs *sbp;
  797         struct thread *td;
  798 {
  799         struct msdosfsmount *pmp;
  800 
  801         pmp = VFSTOMSDOSFS(mp);
  802         sbp->f_bsize = pmp->pm_bpcluster;
  803         sbp->f_iosize = pmp->pm_bpcluster;
  804         sbp->f_blocks = pmp->pm_maxcluster + 1;
  805         sbp->f_bfree = pmp->pm_freeclustercount;
  806         sbp->f_bavail = pmp->pm_freeclustercount;
  807         sbp->f_files = pmp->pm_RootDirEnts;                     /* XXX */
  808         sbp->f_ffree = 0;       /* what to put in here? */
  809         if (sbp != &mp->mnt_stat) {
  810                 sbp->f_type = mp->mnt_vfc->vfc_typenum;
  811                 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
  812                 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
  813         }
  814         strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
  815         return (0);
  816 }
  817 
  818 static int
  819 msdosfs_sync(mp, waitfor, cred, td)
  820         struct mount *mp;
  821         int waitfor;
  822         struct ucred *cred;
  823         struct thread *td;
  824 {
  825         struct vnode *vp, *nvp;
  826         struct denode *dep;
  827         struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
  828         int error, allerror = 0;
  829 
  830         /*
  831          * If we ever switch to not updating all of the fats all the time,
  832          * this would be the place to update them from the first one.
  833          */
  834         if (pmp->pm_fmod != 0) {
  835                 if (pmp->pm_flags & MSDOSFSMNT_RONLY)
  836                         panic("msdosfs_sync: rofs mod");
  837                 else {
  838                         /* update fats here */
  839                 }
  840         }
  841         /*
  842          * Write back each (modified) denode.
  843          */
  844         MNT_ILOCK(mp);
  845 loop:
  846         MNT_VNODE_FOREACH(vp, mp, nvp) {
  847                 VI_LOCK(vp);
  848                 if (vp->v_iflag & VI_XLOCK) {
  849                         VI_UNLOCK(vp);
  850                         continue;
  851                 }
  852                 MNT_IUNLOCK(mp);
  853                 dep = VTODE(vp);
  854                 if (vp->v_type == VNON ||
  855                     ((dep->de_flag &
  856                     (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 &&
  857                     (TAILQ_EMPTY(&vp->v_dirtyblkhd) || waitfor == MNT_LAZY))) {
  858                         VI_UNLOCK(vp);
  859                         MNT_ILOCK(mp);
  860                         continue;
  861                 }
  862                 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, td);
  863                 if (error) {
  864                         MNT_ILOCK(mp);
  865                         if (error == ENOENT)
  866                                 goto loop;
  867                         continue;
  868                 }
  869                 error = VOP_FSYNC(vp, cred, waitfor, td);
  870                 if (error)
  871                         allerror = error;
  872                 VOP_UNLOCK(vp, 0, td);
  873                 vrele(vp);
  874                 MNT_ILOCK(mp);
  875         }
  876         MNT_IUNLOCK(mp);
  877 
  878         /*
  879          * Flush filesystem control info.
  880          */
  881         if (waitfor != MNT_LAZY) {
  882                 vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY, td);
  883                 error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, td);
  884                 if (error)
  885                         allerror = error;
  886                 VOP_UNLOCK(pmp->pm_devvp, 0, td);
  887         }
  888         return (allerror);
  889 }
  890 
  891 static int
  892 msdosfs_fhtovp(mp, fhp, vpp)
  893         struct mount *mp;
  894         struct fid *fhp;
  895         struct vnode **vpp;
  896 {
  897         struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
  898         struct defid *defhp = (struct defid *) fhp;
  899         struct denode *dep;
  900         int error;
  901 
  902         error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep);
  903         if (error) {
  904                 *vpp = NULLVP;
  905                 return (error);
  906         }
  907         *vpp = DETOV(dep);
  908         return (0);
  909 }
  910 
  911 static int
  912 msdosfs_vptofh(vp, fhp)
  913         struct vnode *vp;
  914         struct fid *fhp;
  915 {
  916         struct denode *dep;
  917         struct defid *defhp;
  918 
  919         dep = VTODE(vp);
  920         defhp = (struct defid *)fhp;
  921         defhp->defid_len = sizeof(struct defid);
  922         defhp->defid_dirclust = dep->de_dirclust;
  923         defhp->defid_dirofs = dep->de_diroffset;
  924         /* defhp->defid_gen = dep->de_gen; */
  925         return (0);
  926 }
  927 
  928 static struct vfsops msdosfs_vfsops = {
  929         .vfs_fhtovp =           msdosfs_fhtovp,
  930         .vfs_init =             msdosfs_init,
  931         .vfs_omount =           msdosfs_omount,
  932         .vfs_root =             msdosfs_root,
  933         .vfs_statfs =           msdosfs_statfs,
  934         .vfs_sync =             msdosfs_sync,
  935         .vfs_uninit =           msdosfs_uninit,
  936         .vfs_unmount =          msdosfs_unmount,
  937         .vfs_vptofh =           msdosfs_vptofh,
  938 };
  939 
  940 VFS_SET(msdosfs_vfsops, msdosfs, 0);
  941 MODULE_VERSION(msdosfs, 1);

Cache object: d29d4bebe30fd9aa8dde00015d41fcc8


[ 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.