[BACK]Return to msdosfs_vfsops.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / fs / msdosfs

Annotation of src/sys/fs/msdosfs/msdosfs_vfsops.c, Revision 1.121

1.121   ! hannken     1: /*     $NetBSD: msdosfs_vfsops.c,v 1.120 2017/02/17 08:27:20 hannken Exp $     */
1.1       jdolecek    2:
                      3: /*-
                      4:  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
                      5:  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
                      6:  * All rights reserved.
                      7:  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *     This product includes software developed by TooLs GmbH.
                     20:  * 4. The name of TooLs GmbH may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     25:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     26:  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     27:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     28:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     29:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     30:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     31:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     32:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     33:  */
                     34: /*
                     35:  * Written by Paul Popelka (paulp@uts.amdahl.com)
                     36:  *
                     37:  * You can do anything you want with this software, just don't say you wrote
                     38:  * it, and don't remove this notice.
                     39:  *
                     40:  * This software is provided "as is".
                     41:  *
                     42:  * The author supplies this software to be publicly redistributed on the
                     43:  * understanding that the author is not responsible for the correct
                     44:  * functioning of this software in any circumstances and is not liable for
                     45:  * any damages caused by this software.
                     46:  *
                     47:  * October 1992
                     48:  */
                     49:
                     50: #include <sys/cdefs.h>
1.121   ! hannken    51: __KERNEL_RCSID(0, "$NetBSD: msdosfs_vfsops.c,v 1.120 2017/02/17 08:27:20 hannken Exp $");
1.1       jdolecek   52:
                     53: #if defined(_KERNEL_OPT)
                     54: #include "opt_compat_netbsd.h"
                     55: #endif
                     56:
                     57: #include <sys/param.h>
                     58: #include <sys/systm.h>
1.12      atatat     59: #include <sys/sysctl.h>
1.1       jdolecek   60: #include <sys/namei.h>
                     61: #include <sys/proc.h>
                     62: #include <sys/kernel.h>
                     63: #include <sys/vnode.h>
1.60      dholland   64: #include <miscfs/genfs/genfs.h>
1.1       jdolecek   65: #include <miscfs/specfs/specdev.h> /* XXX */   /* defines v_rdev */
                     66: #include <sys/mount.h>
                     67: #include <sys/buf.h>
                     68: #include <sys/file.h>
                     69: #include <sys/device.h>
                     70: #include <sys/disklabel.h>
1.42      christos   71: #include <sys/disk.h>
1.81      hannken    72: #include <sys/fstrans.h>
1.1       jdolecek   73: #include <sys/ioctl.h>
                     74: #include <sys/malloc.h>
                     75: #include <sys/dirent.h>
                     76: #include <sys/stat.h>
                     77: #include <sys/conf.h>
1.31      elad       78: #include <sys/kauth.h>
1.66      rumble     79: #include <sys/module.h>
1.1       jdolecek   80:
                     81: #include <fs/msdosfs/bpb.h>
                     82: #include <fs/msdosfs/bootsect.h>
                     83: #include <fs/msdosfs/direntry.h>
                     84: #include <fs/msdosfs/denode.h>
                     85: #include <fs/msdosfs/msdosfsmount.h>
                     86: #include <fs/msdosfs/fat.h>
                     87:
1.82      pooka      88: MODULE(MODULE_CLASS_VFS, msdos, NULL);
1.66      rumble     89:
1.42      christos   90: #ifdef MSDOSFS_DEBUG
1.115     maxv       91: #define DPRINTF(fmt, ...) uprintf("%s(): " fmt "\n", __func__, ##__VA_ARGS__)
1.42      christos   92: #else
1.115     maxv       93: #define DPRINTF(fmt, ...)
1.42      christos   94: #endif
                     95:
1.110     maxv       96: #define GEMDOSFS_BSIZE 512
                     97:
1.20      jdolecek   98: #define MSDOSFS_NAMEMAX(pmp) \
                     99:        (pmp)->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12
                    100:
1.29      christos  101: int msdosfs_mountfs(struct vnode *, struct mount *, struct lwp *,
1.26      xtraeme   102:     struct msdosfs_args *);
1.1       jdolecek  103:
1.26      xtraeme   104: static int update_mp(struct mount *, struct msdosfs_args *);
1.2       thorpej   105:
1.45      pooka     106: MALLOC_JUSTDEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOS FS mount structure");
1.100     jakllsch  107: MALLOC_JUSTDEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOS FS FAT table");
1.51      rumble    108: MALLOC_JUSTDEFINE(M_MSDOSFSTMP, "MSDOSFS temp", "MSDOS FS temp. structures");
1.1       jdolecek  109:
1.68      rumble    110: static struct sysctllog *msdosfs_sysctl_log;
                    111:
1.1       jdolecek  112: extern const struct vnodeopv_desc msdosfs_vnodeop_opv_desc;
                    113:
                    114: const struct vnodeopv_desc * const msdosfs_vnodeopv_descs[] = {
                    115:        &msdosfs_vnodeop_opv_desc,
                    116:        NULL,
                    117: };
                    118:
                    119: struct vfsops msdosfs_vfsops = {
1.106     hannken   120:        .vfs_name = MOUNT_MSDOS,
                    121:        .vfs_min_mount_data = sizeof (struct msdosfs_args),
                    122:        .vfs_mount = msdosfs_mount,
                    123:        .vfs_start = msdosfs_start,
                    124:        .vfs_unmount = msdosfs_unmount,
                    125:        .vfs_root = msdosfs_root,
                    126:        .vfs_quotactl = (void *)eopnotsupp,
                    127:        .vfs_statvfs = msdosfs_statvfs,
                    128:        .vfs_sync = msdosfs_sync,
                    129:        .vfs_vget = msdosfs_vget,
1.109     hannken   130:        .vfs_loadvnode = msdosfs_loadvnode,
1.106     hannken   131:        .vfs_fhtovp = msdosfs_fhtovp,
                    132:        .vfs_vptofh = msdosfs_vptofh,
                    133:        .vfs_init = msdosfs_init,
                    134:        .vfs_reinit = msdosfs_reinit,
                    135:        .vfs_done = msdosfs_done,
                    136:        .vfs_mountroot = msdosfs_mountroot,
                    137:        .vfs_snapshot = (void *)eopnotsupp,
                    138:        .vfs_extattrctl = vfs_stdextattrctl,
                    139:        .vfs_suspendctl = msdosfs_suspendctl,
                    140:        .vfs_renamelock_enter = genfs_renamelock_enter,
                    141:        .vfs_renamelock_exit = genfs_renamelock_exit,
                    142:        .vfs_fsync = (void *)eopnotsupp,
                    143:        .vfs_opv_descs = msdosfs_vnodeopv_descs
1.1       jdolecek  144: };
1.66      rumble    145:
                    146: static int
1.83      mlelstv   147: msdos_modcmd(modcmd_t cmd, void *arg)
1.66      rumble    148: {
1.68      rumble    149:        int error;
1.66      rumble    150:
                    151:        switch (cmd) {
                    152:        case MODULE_CMD_INIT:
1.68      rumble    153:                error = vfs_attach(&msdosfs_vfsops);
                    154:                if (error != 0)
                    155:                        break;
                    156:                sysctl_createv(&msdosfs_sysctl_log, 0, NULL, NULL,
                    157:                               CTLFLAG_PERMANENT,
                    158:                               CTLTYPE_NODE, "msdosfs",
                    159:                               SYSCTL_DESCR("MS-DOS file system"),
                    160:                               NULL, 0, NULL, 0,
                    161:                               CTL_VFS, 4, CTL_EOL);
                    162:                /*
                    163:                 * XXX the "4" above could be dynamic, thereby eliminating one
                    164:                 * more instance of the "number to vfs" mapping problem, but
                    165:                 * "4" is the order as taken from sys/mount.h
                    166:                 */
                    167:                break;
1.66      rumble    168:        case MODULE_CMD_FINI:
1.68      rumble    169:                error = vfs_detach(&msdosfs_vfsops);
                    170:                if (error != 0)
                    171:                        break;
                    172:                sysctl_teardown(&msdosfs_sysctl_log);
                    173:                break;
1.66      rumble    174:        default:
1.68      rumble    175:                error = ENOTTY;
                    176:                break;
1.66      rumble    177:        }
1.68      rumble    178:
                    179:        return (error);
1.66      rumble    180: }
1.1       jdolecek  181:
                    182: static int
1.72      dsl       183: update_mp(struct mount *mp, struct msdosfs_args *argp)
1.1       jdolecek  184: {
                    185:        struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
                    186:        int error;
                    187:
                    188:        pmp->pm_gid = argp->gid;
                    189:        pmp->pm_uid = argp->uid;
                    190:        pmp->pm_mask = argp->mask & ALLPERMS;
1.8       jdolecek  191:        pmp->pm_dirmask = argp->dirmask & ALLPERMS;
1.9       itojun    192:        pmp->pm_gmtoff = argp->gmtoff;
1.1       jdolecek  193:        pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT;
                    194:
                    195:        /*
1.71      abs       196:         * GEMDOS knows nothing about win95 long filenames
1.1       jdolecek  197:         */
                    198:        if (pmp->pm_flags & MSDOSFSMNT_GEMDOSFS)
                    199:                pmp->pm_flags |= MSDOSFSMNT_NOWIN95;
                    200:
                    201:        if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
                    202:                pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
                    203:        else if (!(pmp->pm_flags &
                    204:            (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) {
1.24      christos  205:                struct vnode *rtvp;
1.1       jdolecek  206:
                    207:                /*
                    208:                 * Try to divine whether to support Win'95 long filenames
                    209:                 */
                    210:                if (FAT32(pmp))
                    211:                        pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
                    212:                else {
1.24      christos  213:                        if ((error = msdosfs_root(mp, &rtvp)) != 0)
1.1       jdolecek  214:                                return error;
1.24      christos  215:                        pmp->pm_flags |= findwin95(VTODE(rtvp))
1.1       jdolecek  216:                                ? MSDOSFSMNT_LONGNAME
                    217:                                        : MSDOSFSMNT_SHORTNAME;
1.24      christos  218:                        vput(rtvp);
1.1       jdolecek  219:                }
                    220:        }
1.20      jdolecek  221:
                    222:        mp->mnt_stat.f_namemax = MSDOSFS_NAMEMAX(pmp);
                    223:
1.1       jdolecek  224:        return 0;
                    225: }
                    226:
                    227: int
1.73      cegger    228: msdosfs_mountroot(void)
1.1       jdolecek  229: {
                    230:        struct mount *mp;
1.29      christos  231:        struct lwp *l = curlwp; /* XXX */
1.1       jdolecek  232:        int error;
                    233:        struct msdosfs_args args;
                    234:
1.30      thorpej   235:        if (device_class(root_device) != DV_DISK)
1.1       jdolecek  236:                return (ENODEV);
                    237:
                    238:        if ((error = vfs_rootmountalloc(MOUNT_MSDOS, "root_device", &mp))) {
                    239:                vrele(rootvp);
                    240:                return (error);
                    241:        }
                    242:
1.8       jdolecek  243:        args.flags = MSDOSFSMNT_VERSIONED;
1.1       jdolecek  244:        args.uid = 0;
                    245:        args.gid = 0;
                    246:        args.mask = 0777;
1.8       jdolecek  247:        args.version = MSDOSFSMNT_VERSION;
                    248:        args.dirmask = 0777;
1.1       jdolecek  249:
1.29      christos  250:        if ((error = msdosfs_mountfs(rootvp, mp, l, &args)) != 0) {
1.63      ad        251:                vfs_unbusy(mp, false, NULL);
1.65      ad        252:                vfs_destroy(mp);
1.1       jdolecek  253:                return (error);
                    254:        }
                    255:
1.6       thorpej   256:        if ((error = update_mp(mp, &args)) != 0) {
1.54      pooka     257:                (void)msdosfs_unmount(mp, 0);
1.63      ad        258:                vfs_unbusy(mp, false, NULL);
1.65      ad        259:                vfs_destroy(mp);
1.1       jdolecek  260:                vrele(rootvp);
                    261:                return (error);
                    262:        }
                    263:
1.103     christos  264:        mountlist_append(mp);
1.54      pooka     265:        (void)msdosfs_statvfs(mp, &mp->mnt_stat);
1.63      ad        266:        vfs_unbusy(mp, false, NULL);
1.1       jdolecek  267:        return (0);
                    268: }
                    269:
                    270: /*
                    271:  * mp - path - addr in user space of mount point (ie /usr or whatever)
                    272:  * data - addr in user space of mount params including the name of the block
                    273:  * special file to treat as a filesystem.
                    274:  */
                    275: int
1.72      dsl       276: msdosfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
1.1       jdolecek  277: {
1.54      pooka     278:        struct lwp *l = curlwp;
1.1       jdolecek  279:        struct vnode *devvp;      /* vnode for blk device to mount */
1.46      dsl       280:        struct msdosfs_args *args = data; /* holds data from mount request */
1.1       jdolecek  281:        /* msdosfs specific mount control block */
                    282:        struct msdosfsmount *pmp = NULL;
                    283:        int error, flags;
                    284:        mode_t accessmode;
                    285:
1.107     maxv      286:        if (args == NULL)
                    287:                return EINVAL;
1.46      dsl       288:        if (*data_len < sizeof *args)
                    289:                return EINVAL;
                    290:
1.1       jdolecek  291:        if (mp->mnt_flag & MNT_GETARGS) {
                    292:                pmp = VFSTOMSDOSFS(mp);
                    293:                if (pmp == NULL)
                    294:                        return EIO;
1.46      dsl       295:                args->fspec = NULL;
                    296:                args->uid = pmp->pm_uid;
                    297:                args->gid = pmp->pm_gid;
                    298:                args->mask = pmp->pm_mask;
                    299:                args->flags = pmp->pm_flags;
                    300:                args->version = MSDOSFSMNT_VERSION;
                    301:                args->dirmask = pmp->pm_dirmask;
                    302:                args->gmtoff = pmp->pm_gmtoff;
                    303:                *data_len = sizeof *args;
                    304:                return 0;
1.42      christos  305:        }
1.8       jdolecek  306:
                    307:        /*
                    308:         * If not versioned (i.e. using old mount_msdos(8)), fill in
                    309:         * the additional structure items with suitable defaults.
                    310:         */
1.46      dsl       311:        if ((args->flags & MSDOSFSMNT_VERSIONED) == 0) {
                    312:                args->version = 1;
                    313:                args->dirmask = args->mask;
1.8       jdolecek  314:        }
                    315:
1.1       jdolecek  316:        /*
1.15      jdolecek  317:         * Reset GMT offset for pre-v3 mount structure args.
                    318:         */
1.46      dsl       319:        if (args->version < 3)
                    320:                args->gmtoff = 0;
1.15      jdolecek  321:
                    322:        /*
1.1       jdolecek  323:         * If updating, check whether changing from read-only to
                    324:         * read/write; if there is no device name, that's all we do.
                    325:         */
                    326:        if (mp->mnt_flag & MNT_UPDATE) {
                    327:                pmp = VFSTOMSDOSFS(mp);
                    328:                error = 0;
1.75      elad      329:                if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) &&
                    330:                    (mp->mnt_flag & MNT_RDONLY)) {
1.1       jdolecek  331:                        flags = WRITECLOSE;
                    332:                        if (mp->mnt_flag & MNT_FORCE)
                    333:                                flags |= FORCECLOSE;
                    334:                        error = vflush(mp, NULLVP, flags);
                    335:                }
                    336:                if (!error && (mp->mnt_flag & MNT_RELOAD))
                    337:                        /* not yet implemented */
                    338:                        error = EOPNOTSUPP;
1.42      christos  339:                if (error) {
1.115     maxv      340:                        DPRINTF("vflush %d", error);
1.1       jdolecek  341:                        return (error);
1.42      christos  342:                }
1.75      elad      343:                if ((pmp->pm_flags & MSDOSFSMNT_RONLY) &&
                    344:                    (mp->mnt_iflag & IMNT_WANTRDWR)) {
1.1       jdolecek  345:                        /*
                    346:                         * If upgrade to read-write by non-root, then verify
                    347:                         * that user has necessary permissions on the device.
1.74      elad      348:                         *
1.75      elad      349:                         * Permission to update a mount is checked higher, so
                    350:                         * here we presume updating the mount is okay (for
                    351:                         * example, as far as securelevel goes) which leaves us
                    352:                         * with the normal check.
1.1       jdolecek  353:                         */
1.74      elad      354:                        devvp = pmp->pm_devvp;
                    355:                        vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1.94      elad      356:                        error = kauth_authorize_system(l->l_cred,
                    357:                            KAUTH_SYSTEM_MOUNT, KAUTH_REQ_SYSTEM_MOUNT_DEVICE,
                    358:                            mp, devvp, KAUTH_ARG(VREAD | VWRITE));
1.86      hannken   359:                        VOP_UNLOCK(devvp);
1.115     maxv      360:                        DPRINTF("KAUTH_REQ_SYSTEM_MOUNT_DEVICE %d", error);
1.74      elad      361:                        if (error)
                    362:                                return (error);
                    363:
1.1       jdolecek  364:                        pmp->pm_flags &= ~MSDOSFSMNT_RONLY;
                    365:                }
1.46      dsl       366:                if (args->fspec == NULL) {
1.115     maxv      367:                        DPRINTF("missing fspec");
1.28      jmmv      368:                        return EINVAL;
1.42      christos  369:                }
1.1       jdolecek  370:        }
                    371:        /*
                    372:         * Not an update, or updating the name: look up the name
                    373:         * and verify that it refers to a sensible block device.
                    374:         */
1.76      dholland  375:        error = namei_simple_user(args->fspec,
                    376:                                NSM_FOLLOW_NOEMULROOT, &devvp);
                    377:        if (error != 0) {
1.115     maxv      378:                DPRINTF("namei %d", error);
1.1       jdolecek  379:                return (error);
1.42      christos  380:        }
1.1       jdolecek  381:
                    382:        if (devvp->v_type != VBLK) {
1.115     maxv      383:                DPRINTF("not block");
1.1       jdolecek  384:                vrele(devvp);
                    385:                return (ENOTBLK);
                    386:        }
                    387:        if (bdevsw_lookup(devvp->v_rdev) == NULL) {
1.115     maxv      388:                DPRINTF("no block switch");
1.1       jdolecek  389:                vrele(devvp);
                    390:                return (ENXIO);
                    391:        }
                    392:        /*
                    393:         * If mount by non-root, then verify that user has necessary
                    394:         * permissions on the device.
                    395:         */
1.74      elad      396:        accessmode = VREAD;
                    397:        if ((mp->mnt_flag & MNT_RDONLY) == 0)
                    398:                accessmode |= VWRITE;
                    399:        vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1.94      elad      400:        error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
                    401:            KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp, KAUTH_ARG(accessmode));
1.86      hannken   402:        VOP_UNLOCK(devvp);
1.74      elad      403:        if (error) {
1.115     maxv      404:                DPRINTF("KAUTH_REQ_SYSTEM_MOUNT_DEVICE %d", error);
1.74      elad      405:                vrele(devvp);
                    406:                return (error);
1.1       jdolecek  407:        }
                    408:        if ((mp->mnt_flag & MNT_UPDATE) == 0) {
1.24      christos  409:                int xflags;
1.22      mycroft   410:
                    411:                if (mp->mnt_flag & MNT_RDONLY)
1.24      christos  412:                        xflags = FREAD;
1.22      mycroft   413:                else
1.24      christos  414:                        xflags = FREAD|FWRITE;
1.93      hannken   415:                vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1.54      pooka     416:                error = VOP_OPEN(devvp, xflags, FSCRED);
1.93      hannken   417:                VOP_UNLOCK(devvp);
1.42      christos  418:                if (error) {
1.115     maxv      419:                        DPRINTF("VOP_OPEN %d", error);
1.22      mycroft   420:                        goto fail;
1.42      christos  421:                }
1.46      dsl       422:                error = msdosfs_mountfs(devvp, mp, l, args);
1.22      mycroft   423:                if (error) {
1.115     maxv      424:                        DPRINTF("msdosfs_mountfs %d", error);
1.22      mycroft   425:                        vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1.54      pooka     426:                        (void) VOP_CLOSE(devvp, xflags, NOCRED);
1.86      hannken   427:                        VOP_UNLOCK(devvp);
1.22      mycroft   428:                        goto fail;
                    429:                }
1.1       jdolecek  430: #ifdef MSDOSFS_DEBUG           /* only needed for the printf below */
                    431:                pmp = VFSTOMSDOSFS(mp);
                    432: #endif
                    433:        } else {
1.22      mycroft   434:                vrele(devvp);
1.42      christos  435:                if (devvp != pmp->pm_devvp) {
1.115     maxv      436:                        DPRINTF("devvp %p pmp %p", devvp, pmp->pm_devvp);
1.22      mycroft   437:                        return (EINVAL);        /* needs translation */
1.42      christos  438:                }
1.1       jdolecek  439:        }
1.46      dsl       440:        if ((error = update_mp(mp, args)) != 0) {
1.54      pooka     441:                msdosfs_unmount(mp, MNT_FORCE);
1.115     maxv      442:                DPRINTF("update_mp %d", error);
1.1       jdolecek  443:                return error;
                    444:        }
                    445:
                    446: #ifdef MSDOSFS_DEBUG
                    447:        printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap);
                    448: #endif
1.46      dsl       449:        return set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE,
1.47      pooka     450:            mp->mnt_op->vfs_name, mp, l);
1.22      mycroft   451:
                    452: fail:
                    453:        vrele(devvp);
                    454:        return (error);
1.1       jdolecek  455: }
                    456:
                    457: int
1.72      dsl       458: msdosfs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l, struct msdosfs_args *argp)
1.1       jdolecek  459: {
                    460:        struct msdosfsmount *pmp;
                    461:        struct buf *bp;
                    462:        dev_t dev = devvp->v_rdev;
                    463:        union bootsector *bsp;
                    464:        struct byte_bpb33 *b33;
                    465:        struct byte_bpb50 *b50;
                    466:        struct byte_bpb710 *b710;
1.79      mlelstv   467:        uint8_t SecPerClust;
1.110     maxv      468:        int     ronly, error, BlkPerSec;
1.79      mlelstv   469:        uint64_t psize;
                    470:        unsigned secsize;
1.1       jdolecek  471:
1.22      mycroft   472:        /* Flush out any old buffers remaining from a previous use. */
1.33      ad        473:        if ((error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0)) != 0)
1.1       jdolecek  474:                return (error);
                    475:
                    476:        ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
                    477:
                    478:        bp  = NULL; /* both used in error_exit */
                    479:        pmp = NULL;
                    480:
1.81      hannken   481:        error = fstrans_mount(mp);
                    482:        if (error)
                    483:                goto error_exit;
                    484:
1.79      mlelstv   485:        error = getdisksize(devvp, &psize, &secsize);
1.96      tsutsui   486:        if (error) {
1.84      pooka     487:                if (argp->flags & MSDOSFSMNT_GEMDOSFS)
                    488:                        goto error_exit;
1.85      pooka     489:
                    490:                /* ok, so it failed.  we most likely don't need the info */
1.84      pooka     491:                secsize = DEV_BSIZE;
                    492:                psize = 0;
1.85      pooka     493:                error = 0;
1.84      pooka     494:        }
1.114     maxv      495:        if (secsize < DEV_BSIZE) {
1.115     maxv      496:                DPRINTF("Invalid block secsize (%d < DEV_BSIZE)", secsize);
1.114     maxv      497:                error = EINVAL;
                    498:                goto error_exit;
                    499:        }
1.79      mlelstv   500:
1.1       jdolecek  501:        if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
1.110     maxv      502:                if (secsize != GEMDOSFS_BSIZE) {
1.115     maxv      503:                        DPRINTF("Invalid block secsize %d for GEMDOS", secsize);
1.1       jdolecek  504:                        error = EINVAL;
                    505:                        goto error_exit;
                    506:                }
1.110     maxv      507:        }
1.1       jdolecek  508:
                    509:        /*
                    510:         * Read the boot sector of the filesystem, and then check the
                    511:         * boot signature.  If not a dos boot sector then error out.
                    512:         */
1.116     christos  513:        if (secsize < sizeof(*b50)) {
1.117     christos  514:                DPRINTF("50 bootsec %u\n", secsize);
1.116     christos  515:                error = EINVAL;
                    516:                goto error_exit;
                    517:        }
1.118     maxv      518:        if ((error = bread(devvp, 0, secsize, 0, &bp)) != 0)
1.1       jdolecek  519:                goto error_exit;
                    520:        bsp = (union bootsector *)bp->b_data;
                    521:        b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
                    522:        b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
1.10      lukem     523:        b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;
1.1       jdolecek  524:
                    525:        if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) {
                    526:                if (bsp->bs50.bsBootSectSig0 != BOOTSIG0
                    527:                    || bsp->bs50.bsBootSectSig1 != BOOTSIG1) {
1.115     maxv      528:                        DPRINTF("bootsig0 %d bootsig1 %d",
1.42      christos  529:                            bsp->bs50.bsBootSectSig0,
1.115     maxv      530:                            bsp->bs50.bsBootSectSig1);
1.1       jdolecek  531:                        error = EINVAL;
                    532:                        goto error_exit;
                    533:                }
                    534:        }
                    535:
1.112     maxv      536:        pmp = malloc(sizeof(*pmp), M_MSDOSFSMNT, M_WAITOK|M_ZERO);
1.1       jdolecek  537:        pmp->pm_mountp = mp;
                    538:
                    539:        /*
                    540:         * Compute several useful quantities from the bpb in the
                    541:         * bootsector.  Copy in the dos 5 variant of the bpb then fix up
                    542:         * the fields that are different between dos 5 and dos 3.3.
                    543:         */
                    544:        SecPerClust = b50->bpbSecPerClust;
                    545:        pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
                    546:        pmp->pm_ResSectors = getushort(b50->bpbResSectors);
                    547:        pmp->pm_FATs = b50->bpbFATs;
                    548:        pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
                    549:        pmp->pm_Sectors = getushort(b50->bpbSectors);
                    550:        pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
                    551:        pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
                    552:        pmp->pm_Heads = getushort(b50->bpbHeads);
                    553:        pmp->pm_Media = b50->bpbMedia;
                    554:
                    555:        if (pmp->pm_Sectors == 0) {
                    556:                pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
                    557:                pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
                    558:        } else {
1.116     christos  559:                if (secsize < sizeof(*b33)) {
1.117     christos  560:                        DPRINTF("33 bootsec %u\n", secsize);
1.116     christos  561:                        error = EINVAL;
                    562:                        goto error_exit;
                    563:                }
1.1       jdolecek  564:                pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
                    565:                pmp->pm_HugeSectors = pmp->pm_Sectors;
                    566:        }
                    567:
1.110     maxv      568:        /*
                    569:         * Sanity checks, from the FAT specification:
                    570:         * - sectors per cluster: >= 1, power of 2
                    571:         * - logical sector size: >= 1, power of 2
                    572:         * - cluster size:        <= max FS block size
                    573:         * - number of sectors:   >= 1
                    574:         */
                    575:        if ((SecPerClust == 0) || !powerof2(SecPerClust) ||
                    576:            (pmp->pm_BytesPerSec == 0) || !powerof2(pmp->pm_BytesPerSec) ||
                    577:            (SecPerClust * pmp->pm_BytesPerSec > MAXBSIZE) ||
                    578:            (pmp->pm_HugeSectors == 0)) {
1.115     maxv      579:                DPRINTF("consistency checks");
1.110     maxv      580:                error = EINVAL;
                    581:                goto error_exit;
                    582:        }
                    583:
                    584:        if (!(argp->flags & MSDOSFSMNT_GEMDOSFS) &&
                    585:            (pmp->pm_SecPerTrack > 63)) {
1.115     maxv      586:                DPRINTF("SecPerTrack %d", pmp->pm_SecPerTrack);
1.110     maxv      587:                error = EINVAL;
                    588:                goto error_exit;
                    589:        }
                    590:
1.1       jdolecek  591:        if (pmp->pm_RootDirEnts == 0) {
1.116     christos  592:                if (secsize < sizeof(*b710)) {
1.117     christos  593:                        DPRINTF("710 bootsec %u\n", secsize);
1.116     christos  594:                        error = EINVAL;
                    595:                        goto error_exit;
                    596:                }
1.112     maxv      597:                unsigned short FSVers = getushort(b710->bpbFSVers);
                    598:                unsigned short ExtFlags = getushort(b710->bpbExtFlags);
1.34      gdt       599:                /*
                    600:                 * Some say that bsBootSectSig[23] must be zero, but
                    601:                 * Windows does not require this and some digital cameras
                    602:                 * do not set these to zero.  Therefore, do not insist.
                    603:                 */
1.112     maxv      604:                if (pmp->pm_Sectors || pmp->pm_FATsecs || FSVers) {
1.115     maxv      605:                        DPRINTF("Sectors %d FATsecs %lu FSVers %d",
                    606:                            pmp->pm_Sectors, pmp->pm_FATsecs, FSVers);
1.1       jdolecek  607:                        error = EINVAL;
                    608:                        goto error_exit;
                    609:                }
                    610:                pmp->pm_fatmask = FAT32_MASK;
                    611:                pmp->pm_fatmult = 4;
                    612:                pmp->pm_fatdiv = 1;
                    613:                pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
                    614:
1.112     maxv      615:                /* Mirroring is enabled if the FATMIRROR bit is not set. */
                    616:                if ((ExtFlags & FATMIRROR) == 0)
1.1       jdolecek  617:                        pmp->pm_flags |= MSDOSFS_FATMIRROR;
                    618:                else
1.112     maxv      619:                        pmp->pm_curfat = ExtFlags & FATNUM;
1.1       jdolecek  620:        } else
                    621:                pmp->pm_flags |= MSDOSFS_FATMIRROR;
                    622:
                    623:        if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
                    624:                if (FAT32(pmp)) {
1.112     maxv      625:                        /* GEMDOS doesn't know FAT32. */
1.115     maxv      626:                        DPRINTF("FAT32 for GEMDOS");
1.1       jdolecek  627:                        error = EINVAL;
                    628:                        goto error_exit;
                    629:                }
                    630:
                    631:                /*
                    632:                 * Check a few values (could do some more):
1.110     maxv      633:                 * - logical sector size: >= block size
                    634:                 * - number of sectors:   <= size of partition
1.1       jdolecek  635:                 */
1.110     maxv      636:                if ((pmp->pm_BytesPerSec < GEMDOSFS_BSIZE) ||
                    637:                    (pmp->pm_HugeSectors *
                    638:                     (pmp->pm_BytesPerSec / GEMDOSFS_BSIZE) > psize)) {
1.115     maxv      639:                        DPRINTF("consistency checks for GEMDOS");
1.1       jdolecek  640:                        error = EINVAL;
                    641:                        goto error_exit;
                    642:                }
                    643:                /*
1.100     jakllsch  644:                 * XXX - Many parts of the msdosfs driver seem to assume that
1.1       jdolecek  645:                 * the number of bytes per logical sector (BytesPerSec) will
                    646:                 * always be the same as the number of bytes per disk block
                    647:                 * Let's pretend it is.
                    648:                 */
1.110     maxv      649:                BlkPerSec = pmp->pm_BytesPerSec / GEMDOSFS_BSIZE;
                    650:                pmp->pm_BytesPerSec  = GEMDOSFS_BSIZE;
                    651:                pmp->pm_HugeSectors *= BlkPerSec;
                    652:                pmp->pm_HiddenSects *= BlkPerSec;
                    653:                pmp->pm_ResSectors  *= BlkPerSec;
                    654:                pmp->pm_Sectors     *= BlkPerSec;
                    655:                pmp->pm_FATsecs     *= BlkPerSec;
                    656:                SecPerClust         *= BlkPerSec;
1.1       jdolecek  657:        }
1.58      pooka     658:
                    659:        /* Check that fs has nonzero FAT size */
                    660:        if (pmp->pm_FATsecs == 0) {
1.115     maxv      661:                DPRINTF("FATsecs is 0");
1.58      pooka     662:                error = EINVAL;
                    663:                goto error_exit;
                    664:        }
                    665:
1.1       jdolecek  666:        pmp->pm_fatblk = pmp->pm_ResSectors;
                    667:        if (FAT32(pmp)) {
1.116     christos  668:                if (secsize < sizeof(*b710)) {
1.117     christos  669:                        DPRINTF("710 bootsec %u\n", secsize);
1.116     christos  670:                        error = EINVAL;
                    671:                        goto error_exit;
                    672:                }
1.1       jdolecek  673:                pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
                    674:                pmp->pm_firstcluster = pmp->pm_fatblk
                    675:                        + (pmp->pm_FATs * pmp->pm_FATsecs);
                    676:                pmp->pm_fsinfo = getushort(b710->bpbFSInfo);
                    677:        } else {
                    678:                pmp->pm_rootdirblk = pmp->pm_fatblk +
                    679:                        (pmp->pm_FATs * pmp->pm_FATsecs);
                    680:                pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
                    681:                                       + pmp->pm_BytesPerSec - 1)
                    682:                        / pmp->pm_BytesPerSec;/* in sectors */
                    683:                pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
                    684:        }
                    685:
                    686:        pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
                    687:            SecPerClust;
                    688:        pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
                    689:        pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
                    690:
                    691:        if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
1.78      mlelstv   692:                if (pmp->pm_nmbrofclusters <= (0xff0 - 2)) {
1.1       jdolecek  693:                        pmp->pm_fatmask = FAT12_MASK;
                    694:                        pmp->pm_fatmult = 3;
                    695:                        pmp->pm_fatdiv = 2;
                    696:                } else {
                    697:                        pmp->pm_fatmask = FAT16_MASK;
                    698:                        pmp->pm_fatmult = 2;
                    699:                        pmp->pm_fatdiv = 1;
                    700:                }
                    701:        } else if (pmp->pm_fatmask == 0) {
                    702:                if (pmp->pm_maxcluster
                    703:                    <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
                    704:                        /*
                    705:                         * This will usually be a floppy disk. This size makes
1.100     jakllsch  706:                         * sure that one FAT entry will not be split across
1.1       jdolecek  707:                         * multiple blocks.
                    708:                         */
                    709:                        pmp->pm_fatmask = FAT12_MASK;
                    710:                        pmp->pm_fatmult = 3;
                    711:                        pmp->pm_fatdiv = 2;
                    712:                } else {
                    713:                        pmp->pm_fatmask = FAT16_MASK;
                    714:                        pmp->pm_fatmult = 2;
                    715:                        pmp->pm_fatdiv = 1;
                    716:                }
                    717:        }
                    718:        if (FAT12(pmp))
                    719:                pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
                    720:        else
                    721:                pmp->pm_fatblocksize = MAXBSIZE;
                    722:
                    723:        pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
                    724:        pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1;
                    725:
                    726:        /*
                    727:         * Compute mask and shift value for isolating cluster relative byte
                    728:         * offsets and cluster numbers from a file offset.
                    729:         */
                    730:        pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec;
                    731:        pmp->pm_crbomask = pmp->pm_bpcluster - 1;
                    732:        pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
                    733:
                    734:        /*
                    735:         * Check for valid cluster size
                    736:         * must be a power of 2
                    737:         */
                    738:        if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
1.115     maxv      739:                DPRINTF("bpcluster %lu cnshift %lu", pmp->pm_bpcluster,
                    740:                    pmp->pm_cnshift);
1.1       jdolecek  741:                error = EINVAL;
                    742:                goto error_exit;
                    743:        }
                    744:
                    745:        /*
1.101     jakllsch  746:         * Cluster size must be within limit of MAXBSIZE.
                    747:         * Many FAT filesystems will not have clusters larger than
                    748:         * 32KiB due to limits in Windows versions before Vista.
                    749:         */
                    750:        if (pmp->pm_bpcluster > MAXBSIZE) {
1.115     maxv      751:                DPRINTF("bpcluster %lu > MAXBSIZE %d",
                    752:                    pmp->pm_bpcluster, MAXBSIZE);
1.101     jakllsch  753:                error = EINVAL;
                    754:                goto error_exit;
                    755:        }
                    756:
                    757:        /*
1.1       jdolecek  758:         * Release the bootsector buffer.
                    759:         */
1.52      ad        760:        brelse(bp, BC_AGE);
1.1       jdolecek  761:        bp = NULL;
                    762:
                    763:        /*
                    764:         * Check FSInfo.
                    765:         */
                    766:        if (pmp->pm_fsinfo) {
                    767:                struct fsinfo *fp;
1.113     christos  768:                const int rdsz = roundup(sizeof(*fp), pmp->pm_BytesPerSec);
1.1       jdolecek  769:
1.40      scw       770:                /*
                    771:                 * XXX  If the fsinfo block is stored on media with
                    772:                 *      2KB or larger sectors, is the fsinfo structure
                    773:                 *      padded at the end or in the middle?
                    774:                 */
                    775:                if ((error = bread(devvp, de_bn2kb(pmp, pmp->pm_fsinfo),
1.118     maxv      776:                    rdsz, 0, &bp)) != 0)
1.1       jdolecek  777:                        goto error_exit;
                    778:                fp = (struct fsinfo *)bp->b_data;
                    779:                if (!memcmp(fp->fsisig1, "RRaA", 4)
                    780:                    && !memcmp(fp->fsisig2, "rrAa", 4)
                    781:                    && !memcmp(fp->fsisig3, "\0\0\125\252", 4)
                    782:                    && !memcmp(fp->fsisig4, "\0\0\125\252", 4))
                    783:                        pmp->pm_nxtfree = getulong(fp->fsinxtfree);
                    784:                else
                    785:                        pmp->pm_fsinfo = 0;
1.52      ad        786:                brelse(bp, 0);
1.1       jdolecek  787:                bp = NULL;
                    788:        }
                    789:
                    790:        /*
                    791:         * Check and validate (or perhaps invalidate?) the fsinfo structure?
                    792:         * XXX
                    793:         */
                    794:        if (pmp->pm_fsinfo) {
1.99      jakllsch  795:                if ((pmp->pm_nxtfree == 0xffffffffUL) ||
                    796:                    (pmp->pm_nxtfree > pmp->pm_maxcluster))
1.1       jdolecek  797:                        pmp->pm_fsinfo = 0;
                    798:        }
                    799:
                    800:        /*
                    801:         * Allocate memory for the bitmap of allocated clusters, and then
                    802:         * fill it in.
                    803:         */
1.97      jakllsch  804:        pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS)
1.1       jdolecek  805:                                   / N_INUSEBITS)
                    806:                                  * sizeof(*pmp->pm_inusemap),
                    807:                                  M_MSDOSFSFAT, M_WAITOK);
                    808:
                    809:        /*
                    810:         * fillinusemap() needs pm_devvp.
                    811:         */
                    812:        pmp->pm_dev = dev;
                    813:        pmp->pm_devvp = devvp;
                    814:
                    815:        /*
                    816:         * Have the inuse map filled in.
                    817:         */
1.42      christos  818:        if ((error = fillinusemap(pmp)) != 0) {
1.115     maxv      819:                DPRINTF("fillinusemap %d", error);
1.1       jdolecek  820:                goto error_exit;
1.42      christos  821:        }
1.1       jdolecek  822:
                    823:        /*
1.100     jakllsch  824:         * If they want FAT updates to be synchronous then let them suffer
1.1       jdolecek  825:         * the performance degradation in exchange for the on disk copy of
1.100     jakllsch  826:         * the FAT being correct just about all the time.  I suppose this
1.1       jdolecek  827:         * would be a good thing to turn on if the kernel is still flakey.
                    828:         */
                    829:        if (mp->mnt_flag & MNT_SYNCHRONOUS)
                    830:                pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;
                    831:
                    832:        /*
                    833:         * Finish up.
                    834:         */
                    835:        if (ronly)
                    836:                pmp->pm_flags |= MSDOSFSMNT_RONLY;
                    837:        else
                    838:                pmp->pm_fmod = 1;
                    839:        mp->mnt_data = pmp;
1.20      jdolecek  840:        mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev;
                    841:        mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_MSDOS);
                    842:        mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
                    843:        mp->mnt_stat.f_namemax = MSDOSFS_NAMEMAX(pmp);
1.1       jdolecek  844:        mp->mnt_flag |= MNT_LOCAL;
                    845:        mp->mnt_dev_bshift = pmp->pm_bnshift;
                    846:        mp->mnt_fs_bshift = pmp->pm_cnshift;
                    847:
                    848:        /*
                    849:         * If we ever do quotas for DOS filesystems this would be a place
                    850:         * to fill in the info in the msdosfsmount structure. You dolt,
                    851:         * quotas on dos filesystems make no sense because files have no
                    852:         * owners on dos filesystems. of course there is some empty space
                    853:         * in the directory entry where we could put uid's and gid's.
                    854:         */
1.69      pooka     855:
1.102     hannken   856:        spec_node_setmountedfs(devvp, mp);
1.1       jdolecek  857:
                    858:        return (0);
                    859:
1.80      pooka     860: error_exit:
1.81      hannken   861:        fstrans_unmount(mp);
1.1       jdolecek  862:        if (bp)
1.52      ad        863:                brelse(bp, BC_AGE);
1.1       jdolecek  864:        if (pmp) {
                    865:                if (pmp->pm_inusemap)
                    866:                        free(pmp->pm_inusemap, M_MSDOSFSFAT);
                    867:                free(pmp, M_MSDOSFSMNT);
                    868:                mp->mnt_data = NULL;
                    869:        }
                    870:        return (error);
                    871: }
                    872:
                    873: int
1.54      pooka     874: msdosfs_start(struct mount *mp, int flags)
1.1       jdolecek  875: {
                    876:
                    877:        return (0);
                    878: }
                    879:
                    880: /*
                    881:  * Unmount the filesystem described by mp.
                    882:  */
                    883: int
1.72      dsl       884: msdosfs_unmount(struct mount *mp, int mntflags)
1.1       jdolecek  885: {
                    886:        struct msdosfsmount *pmp;
                    887:        int error, flags;
                    888:
                    889:        flags = 0;
                    890:        if (mntflags & MNT_FORCE)
                    891:                flags |= FORCECLOSE;
                    892:        if ((error = vflush(mp, NULLVP, flags)) != 0)
                    893:                return (error);
                    894:        pmp = VFSTOMSDOSFS(mp);
                    895:        if (pmp->pm_devvp->v_type != VBAD)
1.102     hannken   896:                spec_node_setmountedfs(pmp->pm_devvp, NULL);
1.1       jdolecek  897: #ifdef MSDOSFS_DEBUG
                    898:        {
                    899:                struct vnode *vp = pmp->pm_devvp;
                    900:
                    901:                printf("msdosfs_umount(): just before calling VOP_CLOSE()\n");
1.64      ad        902:                printf("flag %08x, usecount %d, writecount %d, holdcnt %d\n",
1.53      ad        903:                    vp->v_vflag | vp->v_iflag | vp->v_uflag, vp->v_usecount,
                    904:                    vp->v_writecount, vp->v_holdcnt);
1.25      jmmv      905:                printf("mount %p, op %p\n",
                    906:                    vp->v_mount, vp->v_op);
1.1       jdolecek  907:                printf("cleanblkhd %p, dirtyblkhd %p, numoutput %d, type %d\n",
                    908:                    vp->v_cleanblkhd.lh_first,
                    909:                    vp->v_dirtyblkhd.lh_first,
                    910:                    vp->v_numoutput, vp->v_type);
                    911:                printf("union %p, tag %d, data[0] %08x, data[1] %08x\n",
                    912:                    vp->v_socket, vp->v_tag,
                    913:                    ((u_int *)vp->v_data)[0],
                    914:                    ((u_int *)vp->v_data)[1]);
                    915:        }
                    916: #endif
                    917:        vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY);
1.80      pooka     918:        (void) VOP_CLOSE(pmp->pm_devvp,
1.54      pooka     919:            pmp->pm_flags & MSDOSFSMNT_RONLY ? FREAD : FREAD|FWRITE, NOCRED);
1.1       jdolecek  920:        vput(pmp->pm_devvp);
1.90      hannken   921:        msdosfs_fh_destroy(pmp);
1.1       jdolecek  922:        free(pmp->pm_inusemap, M_MSDOSFSFAT);
                    923:        free(pmp, M_MSDOSFSMNT);
                    924:        mp->mnt_data = NULL;
                    925:        mp->mnt_flag &= ~MNT_LOCAL;
1.81      hannken   926:        fstrans_unmount(mp);
1.80      pooka     927:        return (0);
1.1       jdolecek  928: }
                    929:
                    930: int
1.72      dsl       931: msdosfs_root(struct mount *mp, struct vnode **vpp)
1.1       jdolecek  932: {
                    933:        struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
                    934:        int error;
                    935:
                    936: #ifdef MSDOSFS_DEBUG
                    937:        printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp);
                    938: #endif
1.109     hannken   939:        if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, vpp)) != 0)
                    940:                return error;
                    941:        error = vn_lock(*vpp, LK_EXCLUSIVE);
                    942:        if (error) {
                    943:                vrele(*vpp);
                    944:                *vpp = NULL;
                    945:                return error;
                    946:        }
                    947:        return 0;
1.1       jdolecek  948: }
                    949:
                    950: int
1.54      pooka     951: msdosfs_statvfs(struct mount *mp, struct statvfs *sbp)
1.1       jdolecek  952: {
                    953:        struct msdosfsmount *pmp;
                    954:
                    955:        pmp = VFSTOMSDOSFS(mp);
                    956:        sbp->f_bsize = pmp->pm_bpcluster;
1.14      christos  957:        sbp->f_frsize = sbp->f_bsize;
1.1       jdolecek  958:        sbp->f_iosize = pmp->pm_bpcluster;
                    959:        sbp->f_blocks = pmp->pm_nmbrofclusters;
                    960:        sbp->f_bfree = pmp->pm_freeclustercount;
                    961:        sbp->f_bavail = pmp->pm_freeclustercount;
1.14      christos  962:        sbp->f_bresvd = 0;
1.1       jdolecek  963:        sbp->f_files = pmp->pm_RootDirEnts;                     /* XXX */
                    964:        sbp->f_ffree = 0;       /* what to put in here? */
1.14      christos  965:        sbp->f_favail = 0;      /* what to put in here? */
                    966:        sbp->f_fresvd = 0;
                    967:        copy_statvfs_info(sbp, mp);
1.1       jdolecek  968:        return (0);
                    969: }
                    970:
1.108     christos  971: struct msdosfs_sync_ctx {
                    972:        int waitfor;
                    973: };
                    974:
                    975: static bool
                    976: msdosfs_sync_selector(void *cl, struct vnode *vp)
                    977: {
                    978:        struct msdosfs_sync_ctx *c = cl;
                    979:        struct denode *dep;
                    980:
                    981:        dep = VTODE(vp);
                    982:        if (c->waitfor == MNT_LAZY || vp->v_type == VNON ||
                    983:            dep == NULL || (((dep->de_flag &
                    984:            (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0) &&
                    985:             (LIST_EMPTY(&vp->v_dirtyblkhd) &&
                    986:              UVM_OBJ_IS_CLEAN(&vp->v_uobj))))
                    987:                return false;
                    988:        return true;
                    989: }
                    990:
1.1       jdolecek  991: int
1.72      dsl       992: msdosfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
1.1       jdolecek  993: {
1.105     hannken   994:        struct vnode *vp;
                    995:        struct vnode_iterator *marker;
1.1       jdolecek  996:        struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
1.89      hannken   997:        int error, allerror = 0;
1.108     christos  998:        struct msdosfs_sync_ctx ctx;
1.1       jdolecek  999:
                   1000:        /*
1.100     jakllsch 1001:         * If we ever switch to not updating all of the FATs all the time,
1.1       jdolecek 1002:         * this would be the place to update them from the first one.
                   1003:         */
                   1004:        if (pmp->pm_fmod != 0) {
                   1005:                if (pmp->pm_flags & MSDOSFSMNT_RONLY)
                   1006:                        panic("msdosfs_sync: rofs mod");
                   1007:                else {
1.100     jakllsch 1008:                        /* update FATs here */
1.1       jdolecek 1009:                }
                   1010:        }
1.81      hannken  1011:        fstrans_start(mp, FSTRANS_SHARED);
1.1       jdolecek 1012:        /*
                   1013:         * Write back each (modified) denode.
                   1014:         */
1.105     hannken  1015:        vfs_vnode_iterator_init(mp, &marker);
1.108     christos 1016:        ctx.waitfor = waitfor;
                   1017:        while ((vp = vfs_vnode_iterator_next(marker, msdosfs_sync_selector,
                   1018:            &ctx)))
                   1019:        {
1.105     hannken  1020:                error = vn_lock(vp, LK_EXCLUSIVE);
                   1021:                if (error) {
                   1022:                        vrele(vp);
1.56      ad       1023:                        continue;
1.105     hannken  1024:                }
1.1       jdolecek 1025:                if ((error = VOP_FSYNC(vp, cred,
1.54      pooka    1026:                    waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0)) != 0)
1.1       jdolecek 1027:                        allerror = error;
1.89      hannken  1028:                vput(vp);
1.1       jdolecek 1029:        }
1.105     hannken  1030:        vfs_vnode_iterator_destroy(marker);
1.56      ad       1031:
1.1       jdolecek 1032:        /*
                   1033:         * Force stale file system control information to be flushed.
                   1034:         */
1.120     hannken  1035:        vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY);
1.1       jdolecek 1036:        if ((error = VOP_FSYNC(pmp->pm_devvp, cred,
1.54      pooka    1037:            waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0)) != 0)
1.1       jdolecek 1038:                allerror = error;
1.120     hannken  1039:        VOP_UNLOCK(pmp->pm_devvp);
1.81      hannken  1040:        fstrans_done(mp);
1.1       jdolecek 1041:        return (allerror);
                   1042: }
                   1043:
                   1044: int
1.72      dsl      1045: msdosfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
1.1       jdolecek 1046: {
                   1047:        struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
1.32      martin   1048:        struct defid defh;
1.90      hannken  1049:        uint32_t gen;
1.1       jdolecek 1050:        int error;
                   1051:
1.42      christos 1052:        if (fhp->fid_len != sizeof(struct defid)) {
1.115     maxv     1053:                DPRINTF("fid_len %d %zd", fhp->fid_len, sizeof(struct defid));
1.32      martin   1054:                return EINVAL;
1.42      christos 1055:        }
1.32      martin   1056:        memcpy(&defh, fhp, sizeof(defh));
1.90      hannken  1057:        error = msdosfs_fh_lookup(pmp, defh.defid_dirclust, defh.defid_dirofs,
                   1058:            &gen);
                   1059:        if (error == 0 && gen != defh.defid_gen)
                   1060:                error = ESTALE;
                   1061:        if (error) {
                   1062:                *vpp = NULLVP;
                   1063:                return error;
                   1064:        }
1.109     hannken  1065:        error = deget(pmp, defh.defid_dirclust, defh.defid_dirofs, vpp);
1.1       jdolecek 1066:        if (error) {
1.115     maxv     1067:                DPRINTF("deget %d", error);
1.1       jdolecek 1068:                *vpp = NULLVP;
1.109     hannken  1069:                return error;
                   1070:        }
                   1071:        error = vn_lock(*vpp, LK_EXCLUSIVE);
                   1072:        if (error) {
                   1073:                vrele(*vpp);
                   1074:                *vpp = NULLVP;
                   1075:                return error;
1.1       jdolecek 1076:        }
1.109     hannken  1077:        return 0;
1.1       jdolecek 1078: }
                   1079:
                   1080: int
1.72      dsl      1081: msdosfs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
1.1       jdolecek 1082: {
1.90      hannken  1083:        struct msdosfsmount *pmp = VFSTOMSDOSFS(vp->v_mount);
1.1       jdolecek 1084:        struct denode *dep;
1.32      martin   1085:        struct defid defh;
1.90      hannken  1086:        int error;
1.1       jdolecek 1087:
1.32      martin   1088:        if (*fh_size < sizeof(struct defid)) {
                   1089:                *fh_size = sizeof(struct defid);
                   1090:                return E2BIG;
                   1091:        }
                   1092:        *fh_size = sizeof(struct defid);
1.1       jdolecek 1093:        dep = VTODE(vp);
1.32      martin   1094:        memset(&defh, 0, sizeof(defh));
                   1095:        defh.defid_len = sizeof(struct defid);
                   1096:        defh.defid_dirclust = dep->de_dirclust;
                   1097:        defh.defid_dirofs = dep->de_diroffset;
1.90      hannken  1098:        error = msdosfs_fh_enter(pmp, dep->de_dirclust, dep->de_diroffset,
                   1099:             &defh.defid_gen);
                   1100:        if (error == 0)
                   1101:                memcpy(fhp, &defh, sizeof(defh));
                   1102:        return error;
1.1       jdolecek 1103: }
                   1104:
                   1105: int
1.39      christos 1106: msdosfs_vget(struct mount *mp, ino_t ino,
                   1107:     struct vnode **vpp)
1.1       jdolecek 1108: {
                   1109:
                   1110:        return (EOPNOTSUPP);
                   1111: }
1.81      hannken  1112:
                   1113: int
                   1114: msdosfs_suspendctl(struct mount *mp, int cmd)
                   1115: {
                   1116:        int error;
                   1117:        struct lwp *l = curlwp;
                   1118:
                   1119:        switch (cmd) {
                   1120:        case SUSPEND_SUSPEND:
                   1121:                if ((error = fstrans_setstate(mp, FSTRANS_SUSPENDING)) != 0)
                   1122:                        return error;
1.121   ! hannken  1123:                if ((error = fstrans_setstate(mp, FSTRANS_SUSPENDED)) != 0) {
1.81      hannken  1124:                        (void) fstrans_setstate(mp, FSTRANS_NORMAL);
                   1125:                        return error;
                   1126:                }
                   1127:                return 0;
                   1128:
                   1129:        case SUSPEND_RESUME:
                   1130:                return fstrans_setstate(mp, FSTRANS_NORMAL);
                   1131:
                   1132:        default:
                   1133:                return EINVAL;
                   1134:        }
                   1135: }

CVSweb <webmaster@jp.NetBSD.org>