root/msdosfs/msdosfs_vfsops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. msdosfs_mount
  2. msdosfs_mountfs
  3. msdosfs_start
  4. msdosfs_unmount
  5. msdosfs_root
  6. msdosfs_statfs
  7. msdosfs_sync_vnode
  8. msdosfs_sync
  9. msdosfs_fhtovp
  10. msdosfs_vptofh
  11. msdosfs_check_export

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

/* [<][>][^][v][top][bottom][index][help] */