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/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 /*      $OpenBSD: msdosfs_vfsops.c,v 1.96 2022/08/12 14:30:52 visa Exp $        */
    2 /*      $NetBSD: msdosfs_vfsops.c,v 1.48 1997/10/18 02:54:57 briggs 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/namei.h>
   54 #include <sys/proc.h>
   55 #include <sys/kernel.h>
   56 #include <sys/vnode.h>
   57 #include <sys/lock.h>
   58 #include <sys/specdev.h> /* XXX */      /* defines v_rdev */
   59 #include <sys/mount.h>
   60 #include <sys/buf.h>
   61 #include <sys/fcntl.h>
   62 #include <sys/disklabel.h>
   63 #include <sys/ioctl.h>
   64 #include <sys/malloc.h>
   65 #include <sys/dirent.h>
   66 #include <sys/disk.h>
   67 #include <sys/dkio.h>
   68 #include <sys/stdint.h>
   69 
   70 #include <msdosfs/bpb.h>
   71 #include <msdosfs/bootsect.h>
   72 #include <msdosfs/direntry.h>
   73 #include <msdosfs/denode.h>
   74 #include <msdosfs/msdosfsmount.h>
   75 #include <msdosfs/fat.h>
   76 
   77 int msdosfs_mount(struct mount *, const char *, void *, struct nameidata *,
   78                        struct proc *);
   79 int msdosfs_start(struct mount *, int, struct proc *);
   80 int msdosfs_unmount(struct mount *, int, struct proc *);
   81 int msdosfs_root(struct mount *, struct vnode **);
   82 int msdosfs_statfs(struct mount *, struct statfs *, struct proc *);
   83 int msdosfs_sync(struct mount *, int, int, struct ucred *, struct proc *);
   84 int msdosfs_fhtovp(struct mount *, struct fid *, struct vnode **);
   85 int msdosfs_vptofh(struct vnode *, struct fid *);
   86 int msdosfs_check_export(struct mount *mp, struct mbuf *nam,
   87                               int *extflagsp, struct ucred **credanonp);
   88 
   89 int msdosfs_mountfs(struct vnode *, struct mount *, struct proc *,
   90                          struct msdosfs_args *);
   91 
   92 int msdosfs_sync_vnode(struct vnode *, void *);
   93 
   94 /*
   95  * mp - path - addr in user space of mount point (ie /usr or whatever)
   96  * data - addr in user space of mount params including the name of the block
   97  * special file to treat as a filesystem.
   98  */
   99 int
  100 msdosfs_mount(struct mount *mp, const char *path, void *data,
  101     struct nameidata *ndp, struct proc *p)
  102 {
  103         struct vnode *devvp;      /* vnode for blk device to mount */
  104         struct msdosfs_args *args = data; /* will hold data from mount request */
  105         /* msdosfs specific mount control block */
  106         struct msdosfsmount *pmp = NULL;
  107         char fname[MNAMELEN];
  108         char fspec[MNAMELEN];
  109         int error, flags;
  110 
  111         /*
  112          * If updating, check whether changing from read-only to
  113          * read/write; if there is no device name, that's all we do.
  114          */
  115         if (mp->mnt_flag & MNT_UPDATE) {
  116                 pmp = VFSTOMSDOSFS(mp);
  117                 error = 0;
  118                 if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) &&
  119                     (mp->mnt_flag & MNT_RDONLY)) {
  120                         mp->mnt_flag &= ~MNT_RDONLY;
  121                         VFS_SYNC(mp, MNT_WAIT, 0, p->p_ucred, p);
  122                         mp->mnt_flag |= MNT_RDONLY;
  123 
  124                         flags = WRITECLOSE;
  125                         if (mp->mnt_flag & MNT_FORCE)
  126                                 flags |= FORCECLOSE;
  127                         error = vflush(mp, NULLVP, flags);
  128                         if (!error) {
  129                                 int force = 0;
  130 
  131                                 pmp->pm_flags |= MSDOSFSMNT_RONLY;
  132                                 /* may be not supported, ignore error */
  133                                 VOP_IOCTL(pmp->pm_devvp, DIOCCACHESYNC,
  134                                     &force, FWRITE, FSCRED, p);
  135                         }
  136                 }
  137                 if (!error && (mp->mnt_flag & MNT_RELOAD))
  138                         /* not yet implemented */
  139                         error = EOPNOTSUPP;
  140                 if (error)
  141                         return (error);
  142                 if ((pmp->pm_flags & MSDOSFSMNT_RONLY) &&
  143                     (mp->mnt_flag & MNT_WANTRDWR))
  144                         pmp->pm_flags &= ~MSDOSFSMNT_RONLY;
  145 
  146                 if (args && args->fspec == NULL) {
  147                         /*
  148                          * Process export requests.
  149                          */
  150                         return (vfs_export(mp, &pmp->pm_export,
  151                             &args->export_info));
  152                 }
  153                 if (args == NULL)
  154                         return (0);
  155         }
  156 
  157         /*
  158          * Not an update, or updating the name: look up the name
  159          * and verify that it refers to a sensible block device.
  160          */
  161         error = copyinstr(args->fspec, fspec, sizeof(fspec), NULL);
  162         if (error)
  163                 goto error;
  164 
  165         if (disk_map(fspec, fname, sizeof(fname), DM_OPENBLCK) == -1)
  166                 bcopy(fspec, fname, sizeof(fname));
  167 
  168         NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fname, p);
  169         if ((error = namei(ndp)) != 0)
  170                 goto error;
  171 
  172         devvp = ndp->ni_vp;
  173 
  174         if (devvp->v_type != VBLK) {
  175                 error = ENOTBLK;
  176                 goto error_devvp;
  177         }
  178         if (major(devvp->v_rdev) >= nblkdev) {
  179                 error = ENXIO;
  180                 goto error_devvp;
  181         }
  182 
  183         if ((mp->mnt_flag & MNT_UPDATE) == 0)
  184                 error = msdosfs_mountfs(devvp, mp, p, args);
  185         else {
  186                 if (devvp != pmp->pm_devvp)
  187                         error = EINVAL; /* XXX needs translation */
  188                 else
  189                         vrele(devvp);
  190         }
  191         if (error)
  192                 goto error_devvp;
  193 
  194         pmp = VFSTOMSDOSFS(mp);
  195         pmp->pm_gid = args->gid;
  196         pmp->pm_uid = args->uid;
  197         pmp->pm_mask = args->mask;
  198         pmp->pm_flags |= args->flags & MSDOSFSMNT_MNTOPT;
  199 
  200         if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
  201                 pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
  202         else if (!(pmp->pm_flags &
  203             (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME)))
  204                 pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
  205 
  206         if (pmp->pm_flags & MSDOSFSMNT_LONGNAME)
  207                 mp->mnt_stat.f_namemax = WIN_MAXLEN;
  208         else
  209                 mp->mnt_stat.f_namemax = 12;
  210 
  211         bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
  212         strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
  213         bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
  214         strlcpy(mp->mnt_stat.f_mntfromname, fname, MNAMELEN);
  215         bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN);
  216         strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN);
  217         bcopy(args, &mp->mnt_stat.mount_info.msdosfs_args, sizeof(*args));
  218 
  219 #ifdef MSDOSFS_DEBUG
  220         printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp,
  221             pmp, pmp->pm_inusemap);
  222 #endif
  223 
  224         return (0);
  225 
  226 error_devvp:
  227         vrele(devvp);
  228 
  229 error:
  230         return (error);
  231 }
  232 
  233 int
  234 msdosfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p,
  235     struct msdosfs_args *argp)
  236 {
  237         struct msdosfsmount *pmp;
  238         struct buf *bp;
  239         dev_t dev = devvp->v_rdev;
  240         union bootsector *bsp;
  241         struct byte_bpb33 *b33;
  242         struct byte_bpb50 *b50;
  243         struct byte_bpb710 *b710;
  244         extern struct vnode *rootvp;
  245         u_int8_t SecPerClust;
  246         int     ronly, error, bmapsiz;
  247         uint32_t fat_max_clusters;
  248 
  249         /*
  250          * Disallow multiple mounts of the same device.
  251          * Disallow mounting of a device that is currently in use
  252          * (except for root, which might share swap device for miniroot).
  253          * Flush out any old buffers remaining from a previous use.
  254          */
  255         if ((error = vfs_mountedon(devvp)) != 0)
  256                 return (error);
  257         if (vcount(devvp) > 1 && devvp != rootvp)
  258                 return (EBUSY);
  259         vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
  260         error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, INFSLP);
  261         VOP_UNLOCK(devvp);
  262         if (error)
  263                 return (error);
  264 
  265         ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
  266         error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
  267         if (error)
  268                 return (error);
  269 
  270         bp  = NULL; /* both used in error_exit */
  271         pmp = NULL;
  272 
  273         /*
  274          * Read the boot sector of the filesystem, and then check the
  275          * boot signature.  If not a dos boot sector then error out.
  276          */
  277         if ((error = bread(devvp, 0, 4096, &bp)) != 0)
  278                 goto error_exit;
  279         bsp = (union bootsector *)bp->b_data;
  280         b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
  281         b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
  282         b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;
  283 
  284         pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO);
  285         pmp->pm_mountp = mp;
  286 
  287         /*
  288          * Compute several useful quantities from the bpb in the
  289          * bootsector.  Copy in the dos 5 variant of the bpb then fix up
  290          * the fields that are different between dos 5 and dos 3.3.
  291          */
  292         SecPerClust = b50->bpbSecPerClust;
  293         pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
  294         pmp->pm_ResSectors = getushort(b50->bpbResSectors);
  295         pmp->pm_FATs = b50->bpbFATs;
  296         pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
  297         pmp->pm_Sectors = getushort(b50->bpbSectors);
  298         pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
  299         pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
  300         pmp->pm_Heads = getushort(b50->bpbHeads);
  301         pmp->pm_Media = b50->bpbMedia;
  302 
  303         /* Determine the number of DEV_BSIZE blocks in a MSDOSFS sector */
  304         pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE;
  305 
  306         if (!pmp->pm_BytesPerSec || !SecPerClust) {
  307                 error = EINVAL;
  308                 goto error_exit;
  309         }
  310 
  311         if (pmp->pm_Sectors == 0) {
  312                 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
  313                 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
  314         } else {
  315                 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
  316                 pmp->pm_HugeSectors = pmp->pm_Sectors;
  317         }
  318 
  319         if (pmp->pm_RootDirEnts == 0) {
  320                 if (pmp->pm_Sectors || pmp->pm_FATsecs ||
  321                     getushort(b710->bpbFSVers)) {
  322                         error = EINVAL;
  323                         goto error_exit;
  324                 }
  325                 pmp->pm_fatmask = FAT32_MASK;
  326                 pmp->pm_fatmult = 4;
  327                 pmp->pm_fatdiv = 1;
  328                 pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
  329                 if (getushort(b710->bpbExtFlags) & FATMIRROR)
  330                         pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
  331                 else
  332                         pmp->pm_flags |= MSDOSFS_FATMIRROR;
  333         } else
  334                 pmp->pm_flags |= MSDOSFS_FATMIRROR;
  335 
  336         /*
  337          * More sanity checks:
  338          *      MSDOSFS sectors per cluster: >0 && power of 2
  339          *      MSDOSFS sector size: >= DEV_BSIZE && power of 2
  340          *      HUGE sector count: >0
  341          *      FAT sectors: >0
  342          */
  343         if ((SecPerClust == 0) || (SecPerClust & (SecPerClust - 1)) ||
  344             (pmp->pm_BytesPerSec < DEV_BSIZE) ||
  345             (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) ||
  346             (pmp->pm_HugeSectors == 0) || (pmp->pm_FATsecs == 0) ||
  347             (SecPerClust * pmp->pm_BlkPerSec > MAXBSIZE / DEV_BSIZE)) {
  348                 error = EINVAL;
  349                 goto error_exit;
  350         }
  351 
  352         pmp->pm_HugeSectors *= pmp->pm_BlkPerSec;
  353         pmp->pm_HiddenSects *= pmp->pm_BlkPerSec;
  354         pmp->pm_FATsecs *= pmp->pm_BlkPerSec;
  355         pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec;
  356         SecPerClust *= pmp->pm_BlkPerSec;
  357 
  358         if (FAT32(pmp)) {
  359                 pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
  360                 pmp->pm_firstcluster = pmp->pm_fatblk
  361                         + (pmp->pm_FATs * pmp->pm_FATsecs);
  362                 pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec;
  363         } else {
  364                 pmp->pm_rootdirblk = pmp->pm_fatblk +
  365                         (pmp->pm_FATs * pmp->pm_FATsecs);
  366                 pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
  367                                        + DEV_BSIZE - 1) / DEV_BSIZE;
  368                 pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
  369         }
  370 
  371         pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
  372             SecPerClust;
  373         pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
  374         pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE;
  375 
  376         if (pmp->pm_fatmask == 0) {
  377                 if (pmp->pm_maxcluster
  378                     <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
  379                         /*
  380                          * This will usually be a floppy disk. This size makes
  381                          * sure that one fat entry will not be split across
  382                          * multiple blocks.
  383                          */
  384                         pmp->pm_fatmask = FAT12_MASK;
  385                         pmp->pm_fatmult = 3;
  386                         pmp->pm_fatdiv = 2;
  387                 } else {
  388                         pmp->pm_fatmask = FAT16_MASK;
  389                         pmp->pm_fatmult = 2;
  390                         pmp->pm_fatdiv = 1;
  391                 }
  392         }
  393         if (FAT12(pmp))
  394                 pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
  395         else
  396                 pmp->pm_fatblocksize = MAXBSIZE;
  397 
  398         /*
  399          * We now have the number of sectors in each FAT, so can work
  400          * out how many clusters can be represented in a FAT.  Let's
  401          * make sure the file system doesn't claim to have more clusters
  402          * than this.
  403          *
  404          * We perform the calculation like we do to avoid integer overflow.
  405          *
  406          * This will give us a count of clusters.  They are numbered
  407          * from 0, so the max cluster value is one less than the value
  408          * we end up with.
  409          */
  410         fat_max_clusters = pmp->pm_fatsize / pmp->pm_fatmult;
  411         fat_max_clusters *= pmp->pm_fatdiv;
  412         if (pmp->pm_maxcluster >= fat_max_clusters) {
  413 #ifndef SMALL_KERNEL
  414                 printf("msdosfs: reducing max cluster to %d from %d "
  415                     "due to FAT size\n", fat_max_clusters - 1,
  416                     pmp->pm_maxcluster);
  417 #endif
  418                 pmp->pm_maxcluster = fat_max_clusters - 1;
  419         }
  420 
  421         pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE;
  422         pmp->pm_bnshift = ffs(DEV_BSIZE) - 1;
  423 
  424         /*
  425          * Compute mask and shift value for isolating cluster relative byte
  426          * offsets and cluster numbers from a file offset.
  427          */
  428         pmp->pm_bpcluster = SecPerClust * DEV_BSIZE;
  429         pmp->pm_crbomask = pmp->pm_bpcluster - 1;
  430         pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
  431 
  432         /*
  433          * Check for valid cluster size
  434          * must be a power of 2
  435          */
  436         if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
  437                 error = EINVAL;
  438                 goto error_exit;
  439         }
  440 
  441         /*
  442          * Release the bootsector buffer.
  443          */
  444         brelse(bp);
  445         bp = NULL;
  446 
  447         /*
  448          * Check FSInfo
  449          */
  450         if (pmp->pm_fsinfo) {
  451                 struct fsinfo *fp;
  452 
  453                 if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp),
  454                     &bp)) != 0)
  455                         goto error_exit;
  456                 fp = (struct fsinfo *)bp->b_data;
  457                 if (!bcmp(fp->fsisig1, "RRaA", 4)
  458                     && !bcmp(fp->fsisig2, "rrAa", 4)
  459                     && !bcmp(fp->fsisig3, "\0\0\125\252", 4)
  460                     && !bcmp(fp->fsisig4, "\0\0\125\252", 4))
  461                         /* Valid FSInfo. */
  462                         ;
  463                 else
  464                         pmp->pm_fsinfo = 0;
  465                 /* XXX make sure this tiny buf doesn't come back in fillinusemap! */
  466                 SET(bp->b_flags, B_INVAL);
  467                 brelse(bp);
  468                 bp = NULL;
  469         }
  470 
  471         /*
  472          * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX
  473          */
  474 
  475         /*
  476          * Allocate memory for the bitmap of allocated clusters, and then
  477          * fill it in.
  478          */
  479         bmapsiz = howmany(pmp->pm_maxcluster + 1, N_INUSEBITS);
  480         if (bmapsiz == 0 || SIZE_MAX / bmapsiz < sizeof(*pmp->pm_inusemap)) {
  481                 /* detect multiplicative integer overflow */
  482                 error = EINVAL;
  483                 goto error_exit;
  484         }
  485         pmp->pm_inusemap = mallocarray(bmapsiz, sizeof(*pmp->pm_inusemap),
  486             M_MSDOSFSFAT, M_WAITOK | M_CANFAIL);
  487         if (pmp->pm_inusemap == NULL) {
  488                 error = EINVAL;
  489                 goto error_exit;
  490         }
  491 
  492         /*
  493          * fillinusemap() needs pm_devvp.
  494          */
  495         pmp->pm_dev = dev;
  496         pmp->pm_devvp = devvp;
  497 
  498         /*
  499          * Have the inuse map filled in.
  500          */
  501         if ((error = fillinusemap(pmp)) != 0)
  502                 goto error_exit;
  503 
  504         /*
  505          * If they want fat updates to be synchronous then let them suffer
  506          * the performance degradation in exchange for the on disk copy of
  507          * the fat being correct just about all the time.  I suppose this
  508          * would be a good thing to turn on if the kernel is still flakey.
  509          */
  510         if (mp->mnt_flag & MNT_SYNCHRONOUS)
  511                 pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;
  512 
  513         /*
  514          * Finish up.
  515          */
  516         if (ronly)
  517                 pmp->pm_flags |= MSDOSFSMNT_RONLY;
  518         else
  519                 pmp->pm_fmod = 1;
  520         mp->mnt_data = pmp;
  521         mp->mnt_stat.f_fsid.val[0] = (long)dev;
  522         mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
  523 #ifdef QUOTA
  524         /*
  525          * If we ever do quotas for DOS filesystems this would be a place
  526          * to fill in the info in the msdosfsmount structure. You dolt,
  527          * quotas on dos filesystems make no sense because files have no
  528          * owners on dos filesystems. of course there is some empty space
  529          * in the directory entry where we could put uid's and gid's.
  530          */
  531 #endif
  532         devvp->v_specmountpoint = mp;
  533 
  534         return (0);
  535 
  536 error_exit:
  537         if (devvp->v_specinfo)
  538                 devvp->v_specmountpoint = NULL;
  539         if (bp)
  540                 brelse(bp);
  541 
  542         vn_lock(devvp, LK_EXCLUSIVE|LK_RETRY);
  543         (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
  544         VOP_UNLOCK(devvp);
  545 
  546         if (pmp) {
  547                 if (pmp->pm_inusemap)
  548                         free(pmp->pm_inusemap, M_MSDOSFSFAT, 0);
  549                 free(pmp, M_MSDOSFSMNT, 0);
  550                 mp->mnt_data = NULL;
  551         }
  552         return (error);
  553 }
  554 
  555 int
  556 msdosfs_start(struct mount *mp, int flags, struct proc *p)
  557 {
  558 
  559         return (0);
  560 }
  561 
  562 /*
  563  * Unmount the filesystem described by mp.
  564  */
  565 int
  566 msdosfs_unmount(struct mount *mp, int mntflags,struct proc *p)
  567 {
  568         struct msdosfsmount *pmp;
  569         int error, flags;
  570         struct vnode *vp;
  571 
  572         flags = 0;
  573         if (mntflags & MNT_FORCE)
  574                 flags |= FORCECLOSE;
  575         if ((error = vflush(mp, NULLVP, flags)) != 0)
  576                 return (error);
  577         pmp = VFSTOMSDOSFS(mp);
  578         pmp->pm_devvp->v_specmountpoint = NULL;
  579         vp = pmp->pm_devvp;
  580 #ifdef MSDOSFS_DEBUG
  581         vprint("msdosfs_umount(): just before calling VOP_CLOSE()\n", vp);
  582 #endif
  583         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  584         (void)VOP_CLOSE(vp,
  585             pmp->pm_flags & MSDOSFSMNT_RONLY ? FREAD : FREAD|FWRITE, NOCRED, p);
  586         vput(vp);
  587         free(pmp->pm_inusemap, M_MSDOSFSFAT, 0);
  588         free(pmp, M_MSDOSFSMNT, 0);
  589         mp->mnt_data = NULL;
  590         mp->mnt_flag &= ~MNT_LOCAL;
  591         return (0);
  592 }
  593 
  594 int
  595 msdosfs_root(struct mount *mp, struct vnode **vpp)
  596 {
  597         struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
  598         struct denode *ndep;
  599         int error;
  600 
  601         if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0)
  602                 return (error);
  603 
  604 #ifdef MSDOSFS_DEBUG
  605         printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n",
  606             mp, pmp, ndep, DETOV(ndep));
  607 #endif
  608 
  609         *vpp = DETOV(ndep);
  610         return (0);
  611 }
  612 
  613 int
  614 msdosfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
  615 {
  616         struct msdosfsmount *pmp;
  617 
  618         pmp = VFSTOMSDOSFS(mp);
  619         sbp->f_bsize = pmp->pm_bpcluster;
  620         sbp->f_iosize = pmp->pm_bpcluster;
  621         sbp->f_blocks = pmp->pm_nmbrofclusters;
  622         sbp->f_bfree = pmp->pm_freeclustercount;
  623         sbp->f_bavail = pmp->pm_freeclustercount;
  624         sbp->f_files = pmp->pm_RootDirEnts;                     /* XXX */
  625         sbp->f_ffree = sbp->f_favail = 0;       /* what to put in here? */
  626         copy_statfs_info(sbp, mp);
  627 
  628         return (0);
  629 }
  630 
  631 
  632 struct msdosfs_sync_arg {
  633         struct proc *p;
  634         struct ucred *cred;
  635         int allerror;
  636         int waitfor;
  637 };
  638 
  639 int
  640 msdosfs_sync_vnode(struct vnode *vp, void *arg)
  641 {
  642         struct msdosfs_sync_arg *msa = arg;
  643         struct denode *dep;
  644         int error;
  645         int s, skip = 0;
  646 
  647         dep = VTODE(vp);
  648         s = splbio();
  649         if (vp->v_type == VNON ||
  650             ((dep->de_flag & (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0
  651               && LIST_EMPTY(&vp->v_dirtyblkhd)) ||
  652             msa->waitfor == MNT_LAZY) {
  653                 skip = 1;
  654         }
  655         splx(s);
  656 
  657         if (skip)
  658                 return (0);
  659 
  660         if (vget(vp, LK_EXCLUSIVE | LK_NOWAIT))
  661                 return (0);
  662 
  663         if ((error = VOP_FSYNC(vp, msa->cred, msa->waitfor, msa->p)) != 0)
  664                 msa->allerror = error;
  665         VOP_UNLOCK(vp);
  666         vrele(vp);
  667 
  668         return (0);
  669 }
  670 
  671 
  672 int
  673 msdosfs_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred,
  674     struct proc *p)
  675 {
  676         struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
  677         struct msdosfs_sync_arg msa;
  678         int error;
  679 
  680         msa.allerror = 0;
  681         msa.p = p;
  682         msa.cred = cred;
  683         msa.waitfor = waitfor;
  684 
  685         /*
  686          * If we ever switch to not updating all of the fats all the time,
  687          * this would be the place to update them from the first one.
  688          */
  689         if (pmp->pm_fmod != 0) {
  690                 if (pmp->pm_flags & MSDOSFSMNT_RONLY)
  691                         panic("msdosfs_sync: rofs mod");
  692                 else {
  693                         /* update fats here */
  694                 }
  695         }
  696         /*
  697          * Write back each (modified) denode.
  698          */
  699         vfs_mount_foreach_vnode(mp, msdosfs_sync_vnode, &msa);
  700 
  701         /*
  702          * Force stale file system control information to be flushed.
  703          */
  704         if (waitfor != MNT_LAZY) {
  705                 vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY);
  706                 if ((error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p)) != 0)
  707                         msa.allerror = error;
  708                 VOP_UNLOCK(pmp->pm_devvp);
  709         }
  710 
  711         return (msa.allerror);
  712 }
  713 
  714 int
  715 msdosfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
  716 {
  717         struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
  718         struct defid *defhp = (struct defid *) fhp;
  719         struct denode *dep;
  720         int error;
  721 
  722         error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep);
  723         if (error) {
  724                 *vpp = NULLVP;
  725                 return (error);
  726         }
  727         *vpp = DETOV(dep);
  728         return (0);
  729 }
  730 
  731 int
  732 msdosfs_vptofh(struct vnode *vp, struct fid *fhp)
  733 {
  734         struct denode *dep;
  735         struct defid *defhp;
  736 
  737         dep = VTODE(vp);
  738         defhp = (struct defid *)fhp;
  739         defhp->defid_len = sizeof(struct defid);
  740         defhp->defid_dirclust = dep->de_dirclust;
  741         defhp->defid_dirofs = dep->de_diroffset;
  742         /* defhp->defid_gen = dep->de_gen; */
  743         return (0);
  744 }
  745 
  746 int
  747 msdosfs_check_export(struct mount *mp, struct mbuf *nam, int *exflagsp,
  748     struct ucred **credanonp)
  749 {
  750         struct netcred *np;
  751         struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
  752 
  753         /*
  754          * Get the export permission structure for this <mp, client> tuple.
  755          */
  756         np = vfs_export_lookup(mp, &pmp->pm_export, nam);
  757         if (np == NULL)
  758                 return (EACCES);
  759 
  760         *exflagsp = np->netc_exflags;
  761         *credanonp = &np->netc_anon;
  762         return (0);
  763 }
  764 
  765 #define msdosfs_vget ((int (*)(struct mount *, ino_t, struct vnode **)) \
  766                       eopnotsupp)
  767 
  768 #define msdosfs_quotactl ((int (*)(struct mount *, int, uid_t, caddr_t, \
  769                                         struct proc *))eopnotsupp)
  770 
  771 #define msdosfs_sysctl ((int (*)(int *, u_int, void *, size_t *, void *, \
  772                                     size_t, struct proc *))eopnotsupp)
  773 
  774 const struct vfsops msdosfs_vfsops = {
  775         .vfs_mount      = msdosfs_mount,
  776         .vfs_start      = msdosfs_start,
  777         .vfs_unmount    = msdosfs_unmount,
  778         .vfs_root       = msdosfs_root,
  779         .vfs_quotactl   = msdosfs_quotactl,
  780         .vfs_statfs     = msdosfs_statfs,
  781         .vfs_sync       = msdosfs_sync,
  782         .vfs_vget       = msdosfs_vget,
  783         .vfs_fhtovp     = msdosfs_fhtovp,
  784         .vfs_vptofh     = msdosfs_vptofh,
  785         .vfs_init       = msdosfs_init,
  786         .vfs_sysctl     = msdosfs_sysctl,
  787         .vfs_checkexp   = msdosfs_check_export,
  788 };

Cache object: ec029f2949297b92e911e1ad61a64e53


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