1c3aac50fSPeter Wemm /* $FreeBSD$ */ 2952a6212SJordan K. Hubbard /* $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws Exp $ */ 327a0bc89SDoug Rabson 427a0bc89SDoug Rabson /*- 5952a6212SJordan K. Hubbard * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 6952a6212SJordan K. Hubbard * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 727a0bc89SDoug Rabson * All rights reserved. 827a0bc89SDoug Rabson * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 927a0bc89SDoug Rabson * 1027a0bc89SDoug Rabson * Redistribution and use in source and binary forms, with or without 1127a0bc89SDoug Rabson * modification, are permitted provided that the following conditions 1227a0bc89SDoug Rabson * are met: 1327a0bc89SDoug Rabson * 1. Redistributions of source code must retain the above copyright 1427a0bc89SDoug Rabson * notice, this list of conditions and the following disclaimer. 1527a0bc89SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 1627a0bc89SDoug Rabson * notice, this list of conditions and the following disclaimer in the 1727a0bc89SDoug Rabson * documentation and/or other materials provided with the distribution. 1827a0bc89SDoug Rabson * 3. All advertising materials mentioning features or use of this software 1927a0bc89SDoug Rabson * must display the following acknowledgement: 2027a0bc89SDoug Rabson * This product includes software developed by TooLs GmbH. 2127a0bc89SDoug Rabson * 4. The name of TooLs GmbH may not be used to endorse or promote products 2227a0bc89SDoug Rabson * derived from this software without specific prior written permission. 2327a0bc89SDoug Rabson * 2427a0bc89SDoug Rabson * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 2527a0bc89SDoug Rabson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2627a0bc89SDoug Rabson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2727a0bc89SDoug Rabson * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2827a0bc89SDoug Rabson * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2927a0bc89SDoug Rabson * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 3027a0bc89SDoug Rabson * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 3127a0bc89SDoug Rabson * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 3227a0bc89SDoug Rabson * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 3327a0bc89SDoug Rabson * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3427a0bc89SDoug Rabson */ 35d167cf6fSWarner Losh /*- 3627a0bc89SDoug Rabson * Written by Paul Popelka (paulp@uts.amdahl.com) 3727a0bc89SDoug Rabson * 3827a0bc89SDoug Rabson * You can do anything you want with this software, just don't say you wrote 3927a0bc89SDoug Rabson * it, and don't remove this notice. 4027a0bc89SDoug Rabson * 4127a0bc89SDoug Rabson * This software is provided "as is". 4227a0bc89SDoug Rabson * 4327a0bc89SDoug Rabson * The author supplies this software to be publicly redistributed on the 4427a0bc89SDoug Rabson * understanding that the author is not responsible for the correct 4527a0bc89SDoug Rabson * functioning of this software in any circumstances and is not liable for 4627a0bc89SDoug Rabson * any damages caused by this software. 4727a0bc89SDoug Rabson * 4827a0bc89SDoug Rabson * October 1992 4927a0bc89SDoug Rabson */ 5027a0bc89SDoug Rabson 5127a0bc89SDoug Rabson #include <sys/param.h> 5227a0bc89SDoug Rabson #include <sys/systm.h> 5365baf8f0SBruce Evans #include <sys/conf.h> 5427a0bc89SDoug Rabson #include <sys/namei.h> 5527a0bc89SDoug Rabson #include <sys/proc.h> 5627a0bc89SDoug Rabson #include <sys/kernel.h> 5727a0bc89SDoug Rabson #include <sys/vnode.h> 5827a0bc89SDoug Rabson #include <sys/mount.h> 599626b608SPoul-Henning Kamp #include <sys/bio.h> 6027a0bc89SDoug Rabson #include <sys/buf.h> 613ac4d1efSBruce Evans #include <sys/fcntl.h> 6227a0bc89SDoug Rabson #include <sys/malloc.h> 63952a6212SJordan K. Hubbard #include <sys/stat.h> /* defines ALLPERMS */ 64c4f02a89SMax Khon #include <sys/iconv.h> 65152ffafeSBruce Evans #include <sys/mutex.h> 66a18b1f1dSJason Evans 671166fb51SRuslan Ermilov #include <fs/msdosfs/bpb.h> 681166fb51SRuslan Ermilov #include <fs/msdosfs/bootsect.h> 69c4f02a89SMax Khon #include <fs/msdosfs/msdosfsmount.h> 701166fb51SRuslan Ermilov #include <fs/msdosfs/direntry.h> 711166fb51SRuslan Ermilov #include <fs/msdosfs/denode.h> 721166fb51SRuslan Ermilov #include <fs/msdosfs/fat.h> 7327a0bc89SDoug Rabson 749a135592SPoul-Henning Kamp #include <geom/geom.h> 759a135592SPoul-Henning Kamp #include <geom/geom_vfs.h> 769a135592SPoul-Henning Kamp 773bc482ecSTim J. Robbins #include "opt_msdosfs.h" 783bc482ecSTim J. Robbins 796a4b48f4SPoul-Henning Kamp /* List of mount options we support */ 806a4b48f4SPoul-Henning Kamp static const char *msdosfs_opts[] = { 816a4b48f4SPoul-Henning Kamp "from", 826a4b48f4SPoul-Henning Kamp "export", 836a4b48f4SPoul-Henning Kamp "uid", "gid", "mask", "dirmask", 846a4b48f4SPoul-Henning Kamp "shortname", "longname", "win95", 856a4b48f4SPoul-Henning Kamp "kiconv", "cs_win", "cs_dos", "cs_local", 866a4b48f4SPoul-Henning Kamp NULL 876a4b48f4SPoul-Henning Kamp }; 886a4b48f4SPoul-Henning Kamp 89152ffafeSBruce Evans #define MSDOSFS_DFLTBSIZE 4096 90152ffafeSBruce Evans 9101f6cfbaSYoshihiro Takahashi #if 1 /*def PC98*/ 9201f6cfbaSYoshihiro Takahashi /* 9301f6cfbaSYoshihiro Takahashi * XXX - The boot signature formatted by NEC PC-98 DOS looks like a 9401f6cfbaSYoshihiro Takahashi * garbage or a random value :-{ 9501f6cfbaSYoshihiro Takahashi * If you want to use that broken-signatured media, define the 9601f6cfbaSYoshihiro Takahashi * following symbol even though PC/AT. 9701f6cfbaSYoshihiro Takahashi * (ex. mount PC-98 DOS formatted FD on PC/AT) 9801f6cfbaSYoshihiro Takahashi */ 9901f6cfbaSYoshihiro Takahashi #define MSDOSFS_NOCHECKSIG 10001f6cfbaSYoshihiro Takahashi #endif 10101f6cfbaSYoshihiro Takahashi 102a1c995b6SPoul-Henning Kamp MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure"); 103a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table"); 10455166637SPoul-Henning Kamp 105c4f02a89SMax Khon struct iconv_functions *msdosfs_iconv = NULL; 106c4f02a89SMax Khon 1076a4b48f4SPoul-Henning Kamp static int update_mp(struct mount *mp, struct thread *td); 10811caded3SAlfred Perlstein static int mountmsdosfs(struct vnode *devvp, struct mount *mp, 1096a4b48f4SPoul-Henning Kamp struct thread *td); 1109bf1a756SPoul-Henning Kamp static vfs_fhtovp_t msdosfs_fhtovp; 1116a4b48f4SPoul-Henning Kamp static vfs_mount_t msdosfs_mount; 1129bf1a756SPoul-Henning Kamp static vfs_root_t msdosfs_root; 1139bf1a756SPoul-Henning Kamp static vfs_statfs_t msdosfs_statfs; 1149bf1a756SPoul-Henning Kamp static vfs_sync_t msdosfs_sync; 1159bf1a756SPoul-Henning Kamp static vfs_unmount_t msdosfs_unmount; 1169bf1a756SPoul-Henning Kamp static vfs_vptofh_t msdosfs_vptofh; 117af482601SBruce Evans 1181a9415afSTim J. Robbins /* Maximum length of a character set name (arbitrary). */ 1191a9415afSTim J. Robbins #define MAXCSLEN 64 1201a9415afSTim J. Robbins 121952a6212SJordan K. Hubbard static int 1226a4b48f4SPoul-Henning Kamp update_mp(mp, td) 123952a6212SJordan K. Hubbard struct mount *mp; 124f257b7a5SAlfred Perlstein struct thread *td; 125952a6212SJordan K. Hubbard { 126952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 1276a4b48f4SPoul-Henning Kamp void *dos, *win, *local; 1286a4b48f4SPoul-Henning Kamp int error, v; 129952a6212SJordan K. Hubbard 1306a4b48f4SPoul-Henning Kamp if (!vfs_getopt(mp->mnt_optnew, "kiconv", NULL, NULL)) { 1316a4b48f4SPoul-Henning Kamp if (msdosfs_iconv != NULL) { 1326a4b48f4SPoul-Henning Kamp error = vfs_getopt(mp->mnt_optnew, 1336a4b48f4SPoul-Henning Kamp "cs_win", &win, NULL); 1346a4b48f4SPoul-Henning Kamp if (!error) 1356a4b48f4SPoul-Henning Kamp error = vfs_getopt(mp->mnt_optnew, 1366a4b48f4SPoul-Henning Kamp "cs_local", &local, NULL); 1376a4b48f4SPoul-Henning Kamp if (!error) 1386a4b48f4SPoul-Henning Kamp error = vfs_getopt(mp->mnt_optnew, 1396a4b48f4SPoul-Henning Kamp "cs_dos", &dos, NULL); 1406a4b48f4SPoul-Henning Kamp if (!error) { 1411a9415afSTim J. Robbins msdosfs_iconv->open(win, local, &pmp->pm_u2w); 1421a9415afSTim J. Robbins msdosfs_iconv->open(local, win, &pmp->pm_w2u); 1431a9415afSTim J. Robbins msdosfs_iconv->open(dos, local, &pmp->pm_u2d); 1441a9415afSTim J. Robbins msdosfs_iconv->open(local, dos, &pmp->pm_d2u); 1456a4b48f4SPoul-Henning Kamp } 1461a9415afSTim J. Robbins if (error != 0) 1471a9415afSTim J. Robbins return (error); 148c4f02a89SMax Khon } else { 149c4f02a89SMax Khon pmp->pm_w2u = NULL; 150c4f02a89SMax Khon pmp->pm_u2w = NULL; 151c4f02a89SMax Khon pmp->pm_d2u = NULL; 152c4f02a89SMax Khon pmp->pm_u2d = NULL; 1537391f611SAndrey A. Chernov } 1541a9415afSTim J. Robbins } 1551a9415afSTim J. Robbins 1566a4b48f4SPoul-Henning Kamp if (1 == vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v)) 1576a4b48f4SPoul-Henning Kamp pmp->pm_gid = v; 1586a4b48f4SPoul-Henning Kamp if (1 == vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v)) 1596a4b48f4SPoul-Henning Kamp pmp->pm_uid = v; 1606a4b48f4SPoul-Henning Kamp if (1 == vfs_scanopt(mp->mnt_optnew, "mask", "%d", &v)) 1616a4b48f4SPoul-Henning Kamp pmp->pm_mask = v & ALLPERMS; 1626a4b48f4SPoul-Henning Kamp if (1 == vfs_scanopt(mp->mnt_optnew, "dirmask", "%d", &v)) 1636a4b48f4SPoul-Henning Kamp pmp->pm_dirmask = v & ALLPERMS; 1646a4b48f4SPoul-Henning Kamp vfs_flagopt(mp->mnt_optnew, "shortname", 1656a4b48f4SPoul-Henning Kamp &pmp->pm_flags, MSDOSFSMNT_SHORTNAME); 1666a4b48f4SPoul-Henning Kamp vfs_flagopt(mp->mnt_optnew, "longname", 1676a4b48f4SPoul-Henning Kamp &pmp->pm_flags, MSDOSFSMNT_LONGNAME); 1686a4b48f4SPoul-Henning Kamp vfs_flagopt(mp->mnt_optnew, "kiconv", 1696a4b48f4SPoul-Henning Kamp &pmp->pm_flags, MSDOSFSMNT_KICONV); 1706a4b48f4SPoul-Henning Kamp 1716a4b48f4SPoul-Henning Kamp /* XXX: Can't use flagopt due to negative option */ 1726a4b48f4SPoul-Henning Kamp if (!vfs_getopt(mp->mnt_optnew, "win95", NULL, NULL)) 1736a4b48f4SPoul-Henning Kamp pmp->pm_flags &= ~MSDOSFSMNT_NOWIN95; 1746a4b48f4SPoul-Henning Kamp else 1756a4b48f4SPoul-Henning Kamp pmp->pm_flags |= MSDOSFSMNT_NOWIN95; 176952a6212SJordan K. Hubbard 177952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 178952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 179952a6212SJordan K. Hubbard else if (!(pmp->pm_flags & 180952a6212SJordan K. Hubbard (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) { 181952a6212SJordan K. Hubbard struct vnode *rootvp; 182952a6212SJordan K. Hubbard 183952a6212SJordan K. Hubbard /* 184952a6212SJordan K. Hubbard * Try to divine whether to support Win'95 long filenames 185952a6212SJordan K. Hubbard */ 186952a6212SJordan K. Hubbard if (FAT32(pmp)) 187952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 188952a6212SJordan K. Hubbard else { 189d9b2d9f7SJeff Roberson if ((error = 190d9b2d9f7SJeff Roberson msdosfs_root(mp, LK_EXCLUSIVE, &rootvp, td)) != 0) 191952a6212SJordan K. Hubbard return error; 192952a6212SJordan K. Hubbard pmp->pm_flags |= findwin95(VTODE(rootvp)) 193952a6212SJordan K. Hubbard ? MSDOSFSMNT_LONGNAME 194952a6212SJordan K. Hubbard : MSDOSFSMNT_SHORTNAME; 195952a6212SJordan K. Hubbard vput(rootvp); 196952a6212SJordan K. Hubbard } 197952a6212SJordan K. Hubbard } 198952a6212SJordan K. Hubbard return 0; 199952a6212SJordan K. Hubbard } 200952a6212SJordan K. Hubbard 2016a4b48f4SPoul-Henning Kamp static int 2026a4b48f4SPoul-Henning Kamp msdosfs_cmount(struct mntarg *ma, void *data, int flags, struct thread *td) 2036a4b48f4SPoul-Henning Kamp { 2046a4b48f4SPoul-Henning Kamp struct msdosfs_args args; 2056a4b48f4SPoul-Henning Kamp int error; 2066a4b48f4SPoul-Henning Kamp 2076a4b48f4SPoul-Henning Kamp if (data == NULL) 2086a4b48f4SPoul-Henning Kamp return (EINVAL); 2096a4b48f4SPoul-Henning Kamp error = copyin(data, &args, sizeof args); 2106a4b48f4SPoul-Henning Kamp if (error) 2116a4b48f4SPoul-Henning Kamp return (error); 2126a4b48f4SPoul-Henning Kamp 2136a4b48f4SPoul-Henning Kamp ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); 2146a4b48f4SPoul-Henning Kamp ma = mount_arg(ma, "export", &args.export, sizeof args.export); 2156a4b48f4SPoul-Henning Kamp ma = mount_argf(ma, "uid", "%d", args.uid); 2166a4b48f4SPoul-Henning Kamp ma = mount_argf(ma, "gid", "%d", args.gid); 2176a4b48f4SPoul-Henning Kamp ma = mount_argf(ma, "mask", "%d", args.mask); 2186a4b48f4SPoul-Henning Kamp ma = mount_argf(ma, "dirmask", "%d", args.dirmask); 2196a4b48f4SPoul-Henning Kamp 2206a4b48f4SPoul-Henning Kamp ma = mount_argb(ma, args.flags & MSDOSFSMNT_SHORTNAME, "noshortname"); 2216a4b48f4SPoul-Henning Kamp ma = mount_argb(ma, args.flags & MSDOSFSMNT_LONGNAME, "nolongname"); 2226a4b48f4SPoul-Henning Kamp ma = mount_argb(ma, !(args.flags & MSDOSFSMNT_NOWIN95), "nowin95"); 2236a4b48f4SPoul-Henning Kamp ma = mount_argb(ma, args.flags & MSDOSFSMNT_KICONV, "nokiconv"); 2246a4b48f4SPoul-Henning Kamp 2256a4b48f4SPoul-Henning Kamp ma = mount_argsu(ma, "cs_win", args.cs_win, MAXCSLEN); 2266a4b48f4SPoul-Henning Kamp ma = mount_argsu(ma, "cs_dos", args.cs_dos, MAXCSLEN); 2276a4b48f4SPoul-Henning Kamp ma = mount_argsu(ma, "cs_local", args.cs_local, MAXCSLEN); 2286a4b48f4SPoul-Henning Kamp 2296a4b48f4SPoul-Henning Kamp error = kernel_mount(ma, flags); 2306a4b48f4SPoul-Henning Kamp 2316a4b48f4SPoul-Henning Kamp return (error); 2326a4b48f4SPoul-Henning Kamp } 2336a4b48f4SPoul-Henning Kamp 23427a0bc89SDoug Rabson /* 23527a0bc89SDoug Rabson * mp - path - addr in user space of mount point (ie /usr or whatever) 23627a0bc89SDoug Rabson * data - addr in user space of mount params including the name of the block 23727a0bc89SDoug Rabson * special file to treat as a filesystem. 23827a0bc89SDoug Rabson */ 2397fefffeeSPoul-Henning Kamp static int 2406a4b48f4SPoul-Henning Kamp msdosfs_mount(struct mount *mp, struct thread *td) 24127a0bc89SDoug Rabson { 24227a0bc89SDoug Rabson struct vnode *devvp; /* vnode for blk device to mount */ 243269c902fSPoul-Henning Kamp struct export_args export; 244952a6212SJordan K. Hubbard /* msdosfs specific mount control block */ 245952a6212SJordan K. Hubbard struct msdosfsmount *pmp = NULL; 2465e8c582aSPoul-Henning Kamp struct nameidata ndp; 247269c902fSPoul-Henning Kamp int error, flags; 248952a6212SJordan K. Hubbard mode_t accessmode; 2496a4b48f4SPoul-Henning Kamp char *from; 25027a0bc89SDoug Rabson 2516a4b48f4SPoul-Henning Kamp if (vfs_filteropt(mp->mnt_optnew, msdosfs_opts)) 2526a4b48f4SPoul-Henning Kamp return (EINVAL); 2536a4b48f4SPoul-Henning Kamp 25427a0bc89SDoug Rabson /* 255952a6212SJordan K. Hubbard * If updating, check whether changing from read-only to 256952a6212SJordan K. Hubbard * read/write; if there is no device name, that's all we do. 25727a0bc89SDoug Rabson */ 25827a0bc89SDoug Rabson if (mp->mnt_flag & MNT_UPDATE) { 259952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 260269c902fSPoul-Henning Kamp 261269c902fSPoul-Henning Kamp error = vfs_copyopt(mp->mnt_optnew, "export", 262269c902fSPoul-Henning Kamp &export, sizeof export); 263269c902fSPoul-Henning Kamp if (error == 0 && export.ex_flags != 0) { 264269c902fSPoul-Henning Kamp /* 265269c902fSPoul-Henning Kamp * Process export requests. 266269c902fSPoul-Henning Kamp */ 267269c902fSPoul-Henning Kamp if ((export.ex_flags & MNT_EXPORTED) != 0 && 268269c902fSPoul-Henning Kamp (pmp->pm_flags & MSDOSFS_LARGEFS) != 0) 269269c902fSPoul-Henning Kamp return (EOPNOTSUPP); 270269c902fSPoul-Henning Kamp return (vfs_export(mp, &export)); 271269c902fSPoul-Henning Kamp } 2729a135592SPoul-Henning Kamp if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && 2736a4b48f4SPoul-Henning Kamp vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { 2748df6bac4SPoul-Henning Kamp error = VFS_SYNC(mp, MNT_WAIT, td); 275e83f1423SPoul-Henning Kamp if (error) 276e83f1423SPoul-Henning Kamp return (error); 27727a0bc89SDoug Rabson flags = WRITECLOSE; 27827a0bc89SDoug Rabson if (mp->mnt_flag & MNT_FORCE) 27927a0bc89SDoug Rabson flags |= FORCECLOSE; 280f257b7a5SAlfred Perlstein error = vflush(mp, 0, flags, td); 2816a4b48f4SPoul-Henning Kamp if (error) 2826a4b48f4SPoul-Henning Kamp return (error); 2839a135592SPoul-Henning Kamp DROP_GIANT(); 2849a135592SPoul-Henning Kamp g_topology_lock(); 2859a135592SPoul-Henning Kamp g_access(pmp->pm_cp, 0, -1, 0); 2869a135592SPoul-Henning Kamp g_topology_unlock(); 2879a135592SPoul-Henning Kamp PICKUP_GIANT(); 2886a4b48f4SPoul-Henning Kamp } else if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && 2896a4b48f4SPoul-Henning Kamp !vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { 290952a6212SJordan K. Hubbard /* 291952a6212SJordan K. Hubbard * If upgrade to read-write by non-root, then verify 292952a6212SJordan K. Hubbard * that user has necessary permissions on the device. 293952a6212SJordan K. Hubbard */ 29444731cabSJohn Baldwin if (suser(td)) { 295952a6212SJordan K. Hubbard devvp = pmp->pm_devvp; 296b40ce416SJulian Elischer vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 297952a6212SJordan K. Hubbard error = VOP_ACCESS(devvp, VREAD | VWRITE, 298a854ed98SJohn Baldwin td->td_ucred, td); 299952a6212SJordan K. Hubbard if (error) { 300b40ce416SJulian Elischer VOP_UNLOCK(devvp, 0, td); 301952a6212SJordan K. Hubbard return (error); 302952a6212SJordan K. Hubbard } 303b40ce416SJulian Elischer VOP_UNLOCK(devvp, 0, td); 304952a6212SJordan K. Hubbard } 3059a135592SPoul-Henning Kamp DROP_GIANT(); 3069a135592SPoul-Henning Kamp g_topology_lock(); 3079a135592SPoul-Henning Kamp error = g_access(pmp->pm_cp, 0, 1, 0); 3089a135592SPoul-Henning Kamp g_topology_unlock(); 3099a135592SPoul-Henning Kamp PICKUP_GIANT(); 3109a135592SPoul-Henning Kamp if (error) 3119a135592SPoul-Henning Kamp return (error); 312cede1f56STom Rhodes 313a78c9287SBruce Evans /* Now that the volume is modifiable, mark it dirty. */ 314cede1f56STom Rhodes error = markvoldirty(pmp, 1); 315cede1f56STom Rhodes if (error) 316a78c9287SBruce Evans return (error); 317952a6212SJordan K. Hubbard } 3186a4b48f4SPoul-Henning Kamp vfs_flagopt(mp->mnt_optnew, "ro", 3196a4b48f4SPoul-Henning Kamp &pmp->pm_flags, MSDOSFSMNT_RONLY); 3206a4b48f4SPoul-Henning Kamp vfs_flagopt(mp->mnt_optnew, "ro", 3216a4b48f4SPoul-Henning Kamp &mp->mnt_flag, MNT_RDONLY); 3226a4b48f4SPoul-Henning Kamp if (vfs_getopt(mp->mnt_optnew, "from", NULL, NULL)) { 323952a6212SJordan K. Hubbard #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ 324952a6212SJordan K. Hubbard if (args.flags & MSDOSFSMNT_MNTOPT) { 325952a6212SJordan K. Hubbard pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; 326952a6212SJordan K. Hubbard pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; 327952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 328952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 329952a6212SJordan K. Hubbard } 330952a6212SJordan K. Hubbard #endif 33127a0bc89SDoug Rabson } 332952a6212SJordan K. Hubbard } 33327a0bc89SDoug Rabson /* 334952a6212SJordan K. Hubbard * Not an update, or updating the name: look up the name 335e9827c6dSBruce Evans * and verify that it refers to a sensible disk device. 33627a0bc89SDoug Rabson */ 3376a4b48f4SPoul-Henning Kamp if (vfs_getopt(mp->mnt_optnew, "from", (void **)&from, NULL)) 3386a4b48f4SPoul-Henning Kamp return (EINVAL); 33975d7ba93SSuleiman Souhlal NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, from, td); 3405e8c582aSPoul-Henning Kamp error = namei(&ndp); 341952a6212SJordan K. Hubbard if (error) 342952a6212SJordan K. Hubbard return (error); 3435e8c582aSPoul-Henning Kamp devvp = ndp.ni_vp; 3445e8c582aSPoul-Henning Kamp NDFREE(&ndp, NDF_ONLY_PNBUF); 345952a6212SJordan K. Hubbard 346ba4ad1fcSPoul-Henning Kamp if (!vn_isdisk(devvp, &error)) { 34775d7ba93SSuleiman Souhlal vput(devvp); 348ba4ad1fcSPoul-Henning Kamp return (error); 34927a0bc89SDoug Rabson } 35027a0bc89SDoug Rabson /* 351952a6212SJordan K. Hubbard * If mount by non-root, then verify that user has necessary 352952a6212SJordan K. Hubbard * permissions on the device. 35327a0bc89SDoug Rabson */ 35444731cabSJohn Baldwin if (suser(td)) { 355952a6212SJordan K. Hubbard accessmode = VREAD; 356952a6212SJordan K. Hubbard if ((mp->mnt_flag & MNT_RDONLY) == 0) 357952a6212SJordan K. Hubbard accessmode |= VWRITE; 358a854ed98SJohn Baldwin error = VOP_ACCESS(devvp, accessmode, td->td_ucred, td); 359952a6212SJordan K. Hubbard if (error) { 360952a6212SJordan K. Hubbard vput(devvp); 361952a6212SJordan K. Hubbard return (error); 362952a6212SJordan K. Hubbard } 363952a6212SJordan K. Hubbard } 364952a6212SJordan K. Hubbard if ((mp->mnt_flag & MNT_UPDATE) == 0) { 3656a4b48f4SPoul-Henning Kamp error = mountmsdosfs(devvp, mp, td); 366952a6212SJordan K. Hubbard #ifdef MSDOSFS_DEBUG /* only needed for the printf below */ 367952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 368952a6212SJordan K. Hubbard #endif 369952a6212SJordan K. Hubbard } else { 37027a0bc89SDoug Rabson if (devvp != pmp->pm_devvp) 371952a6212SJordan K. Hubbard error = EINVAL; /* XXX needs translation */ 37227a0bc89SDoug Rabson else 37375d7ba93SSuleiman Souhlal vput(devvp); 37427a0bc89SDoug Rabson } 37527a0bc89SDoug Rabson if (error) { 37627a0bc89SDoug Rabson vrele(devvp); 377952a6212SJordan K. Hubbard return (error); 378952a6212SJordan K. Hubbard } 379952a6212SJordan K. Hubbard 3806a4b48f4SPoul-Henning Kamp error = update_mp(mp, td); 381952a6212SJordan K. Hubbard if (error) { 3821a9415afSTim J. Robbins if ((mp->mnt_flag & MNT_UPDATE) == 0) 383b40ce416SJulian Elischer msdosfs_unmount(mp, MNT_FORCE, td); 38427a0bc89SDoug Rabson return error; 38527a0bc89SDoug Rabson } 3866a4b48f4SPoul-Henning Kamp 3876a4b48f4SPoul-Henning Kamp vfs_mountedfrom(mp, from); 38827a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 3896a4b48f4SPoul-Henning Kamp printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 39027a0bc89SDoug Rabson #endif 391952a6212SJordan K. Hubbard return (0); 39227a0bc89SDoug Rabson } 39327a0bc89SDoug Rabson 3947fefffeeSPoul-Henning Kamp static int 3956a4b48f4SPoul-Henning Kamp mountmsdosfs(devvp, mp, td) 39627a0bc89SDoug Rabson struct vnode *devvp; 39727a0bc89SDoug Rabson struct mount *mp; 398b40ce416SJulian Elischer struct thread *td; 39927a0bc89SDoug Rabson { 400952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 401952a6212SJordan K. Hubbard struct buf *bp; 40289c9c53dSPoul-Henning Kamp struct cdev *dev = devvp->v_rdev; 40327a0bc89SDoug Rabson union bootsector *bsp; 40427a0bc89SDoug Rabson struct byte_bpb33 *b33; 40527a0bc89SDoug Rabson struct byte_bpb50 *b50; 406952a6212SJordan K. Hubbard struct byte_bpb710 *b710; 407952a6212SJordan K. Hubbard u_int8_t SecPerClust; 408499d3ffaSBoris Popov u_long clusters; 409952a6212SJordan K. Hubbard int ronly, error; 4109a135592SPoul-Henning Kamp struct g_consumer *cp; 4119a135592SPoul-Henning Kamp struct bufobj *bo; 41227a0bc89SDoug Rabson 4136a4b48f4SPoul-Henning Kamp ronly = !vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL); 4149a135592SPoul-Henning Kamp /* XXX: use VOP_ACCESS to check FS perms */ 4159a135592SPoul-Henning Kamp DROP_GIANT(); 4169a135592SPoul-Henning Kamp g_topology_lock(); 4179a135592SPoul-Henning Kamp error = g_vfs_open(devvp, &cp, "msdos", ronly ? 0 : 1); 4189a135592SPoul-Henning Kamp g_topology_unlock(); 4199a135592SPoul-Henning Kamp PICKUP_GIANT(); 420b40ce416SJulian Elischer VOP_UNLOCK(devvp, 0, td); 421c3c6d51eSPoul-Henning Kamp if (error) 422952a6212SJordan K. Hubbard return (error); 423952a6212SJordan K. Hubbard 4249a135592SPoul-Henning Kamp bo = &devvp->v_bufobj; 425952a6212SJordan K. Hubbard bp = NULL; /* both used in error_exit */ 426952a6212SJordan K. Hubbard pmp = NULL; 427952a6212SJordan K. Hubbard 42827a0bc89SDoug Rabson /* 429952a6212SJordan K. Hubbard * Read the boot sector of the filesystem, and then check the 430952a6212SJordan K. Hubbard * boot signature. If not a dos boot sector then error out. 43101f6cfbaSYoshihiro Takahashi * 432152ffafeSBruce Evans * NOTE: 2048 is a maximum sector size in current... 43327a0bc89SDoug Rabson */ 434152ffafeSBruce Evans error = bread(devvp, 0, 2048, NOCRED, &bp); 435c3c6d51eSPoul-Henning Kamp if (error) 43627a0bc89SDoug Rabson goto error_exit; 437952a6212SJordan K. Hubbard bp->b_flags |= B_AGE; 438952a6212SJordan K. Hubbard bsp = (union bootsector *)bp->b_data; 43927a0bc89SDoug Rabson b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 44027a0bc89SDoug Rabson b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 44101a4d019SJohn Baldwin b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB; 442952a6212SJordan K. Hubbard 44301f6cfbaSYoshihiro Takahashi #ifndef MSDOSFS_NOCHECKSIG 444952a6212SJordan K. Hubbard if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 445952a6212SJordan K. Hubbard || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 44627a0bc89SDoug Rabson error = EINVAL; 44727a0bc89SDoug Rabson goto error_exit; 44827a0bc89SDoug Rabson } 44901f6cfbaSYoshihiro Takahashi #endif 45027a0bc89SDoug Rabson 451a163d034SWarner Losh pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO); 45227a0bc89SDoug Rabson pmp->pm_mountp = mp; 4539a135592SPoul-Henning Kamp pmp->pm_cp = cp; 4549a135592SPoul-Henning Kamp pmp->pm_bo = bo; 45527a0bc89SDoug Rabson 45627a0bc89SDoug Rabson /* 45727a0bc89SDoug Rabson * Compute several useful quantities from the bpb in the 45827a0bc89SDoug Rabson * bootsector. Copy in the dos 5 variant of the bpb then fix up 45927a0bc89SDoug Rabson * the fields that are different between dos 5 and dos 3.3. 46027a0bc89SDoug Rabson */ 461952a6212SJordan K. Hubbard SecPerClust = b50->bpbSecPerClust; 46227a0bc89SDoug Rabson pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 463696f22f0SJohn Baldwin if (pmp->pm_BytesPerSec < DEV_BSIZE) { 464696f22f0SJohn Baldwin error = EINVAL; 465696f22f0SJohn Baldwin goto error_exit; 466696f22f0SJohn Baldwin } 46727a0bc89SDoug Rabson pmp->pm_ResSectors = getushort(b50->bpbResSectors); 46827a0bc89SDoug Rabson pmp->pm_FATs = b50->bpbFATs; 46927a0bc89SDoug Rabson pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 47027a0bc89SDoug Rabson pmp->pm_Sectors = getushort(b50->bpbSectors); 47127a0bc89SDoug Rabson pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 47227a0bc89SDoug Rabson pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 47327a0bc89SDoug Rabson pmp->pm_Heads = getushort(b50->bpbHeads); 474952a6212SJordan K. Hubbard pmp->pm_Media = b50->bpbMedia; 47527a0bc89SDoug Rabson 47601f6cfbaSYoshihiro Takahashi /* calculate the ratio of sector size to DEV_BSIZE */ 47701f6cfbaSYoshihiro Takahashi pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE; 47801f6cfbaSYoshihiro Takahashi 47927a0bc89SDoug Rabson /* XXX - We should probably check more values here */ 480952a6212SJordan K. Hubbard if (!pmp->pm_BytesPerSec || !SecPerClust 4810ff34b5eSRobert Watson || !pmp->pm_Heads 482ad63a118SSatoshi Asami #ifdef PC98 483952a6212SJordan K. Hubbard || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { 484ad63a118SSatoshi Asami #else 485952a6212SJordan K. Hubbard || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 486ad63a118SSatoshi Asami #endif 48727a0bc89SDoug Rabson error = EINVAL; 48827a0bc89SDoug Rabson goto error_exit; 48927a0bc89SDoug Rabson } 49027a0bc89SDoug Rabson 49127a0bc89SDoug Rabson if (pmp->pm_Sectors == 0) { 49227a0bc89SDoug Rabson pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 49327a0bc89SDoug Rabson pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 49427a0bc89SDoug Rabson } else { 49527a0bc89SDoug Rabson pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 49627a0bc89SDoug Rabson pmp->pm_HugeSectors = pmp->pm_Sectors; 49727a0bc89SDoug Rabson } 4983bc482ecSTim J. Robbins #ifndef MSDOSFS_LARGE 499c681be37SDmitrij Tejblum if (pmp->pm_HugeSectors > 0xffffffff / 500c681be37SDmitrij Tejblum (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) { 501952a6212SJordan K. Hubbard /* 502952a6212SJordan K. Hubbard * We cannot deal currently with this size of disk 503952a6212SJordan K. Hubbard * due to fileid limitations (see msdosfs_getattr and 504952a6212SJordan K. Hubbard * msdosfs_readdir) 505952a6212SJordan K. Hubbard */ 506952a6212SJordan K. Hubbard error = EINVAL; 507aaf0bb19SAndrey A. Chernov printf("mountmsdosfs(): disk too big, sorry\n"); 508952a6212SJordan K. Hubbard goto error_exit; 509952a6212SJordan K. Hubbard } 5103bc482ecSTim J. Robbins #endif /* !MSDOSFS_LARGE */ 511952a6212SJordan K. Hubbard 512952a6212SJordan K. Hubbard if (pmp->pm_RootDirEnts == 0) { 513952a6212SJordan K. Hubbard if (bsp->bs710.bsBootSectSig2 != BOOTSIG2 514952a6212SJordan K. Hubbard || bsp->bs710.bsBootSectSig3 != BOOTSIG3 515952a6212SJordan K. Hubbard || pmp->pm_Sectors 516952a6212SJordan K. Hubbard || pmp->pm_FATsecs 517952a6212SJordan K. Hubbard || getushort(b710->bpbFSVers)) { 518952a6212SJordan K. Hubbard error = EINVAL; 519aaf0bb19SAndrey A. Chernov printf("mountmsdosfs(): bad FAT32 filesystem\n"); 520952a6212SJordan K. Hubbard goto error_exit; 521952a6212SJordan K. Hubbard } 522952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT32_MASK; 523952a6212SJordan K. Hubbard pmp->pm_fatmult = 4; 524952a6212SJordan K. Hubbard pmp->pm_fatdiv = 1; 525952a6212SJordan K. Hubbard pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 526952a6212SJordan K. Hubbard if (getushort(b710->bpbExtFlags) & FATMIRROR) 527952a6212SJordan K. Hubbard pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 528952a6212SJordan K. Hubbard else 529952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFS_FATMIRROR; 530952a6212SJordan K. Hubbard } else 531952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFS_FATMIRROR; 532952a6212SJordan K. Hubbard 533952a6212SJordan K. Hubbard /* 534952a6212SJordan K. Hubbard * Check a few values (could do some more): 535952a6212SJordan K. Hubbard * - logical sector size: power of 2, >= block size 536952a6212SJordan K. Hubbard * - sectors per cluster: power of 2, >= 1 537952a6212SJordan K. Hubbard * - number of sectors: >= 1, <= size of partition 538696f22f0SJohn Baldwin * - number of FAT sectors: >= 1 539952a6212SJordan K. Hubbard */ 540952a6212SJordan K. Hubbard if ( (SecPerClust == 0) 541952a6212SJordan K. Hubbard || (SecPerClust & (SecPerClust - 1)) 54201f6cfbaSYoshihiro Takahashi || (pmp->pm_BytesPerSec < DEV_BSIZE) 543952a6212SJordan K. Hubbard || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) 544952a6212SJordan K. Hubbard || (pmp->pm_HugeSectors == 0) 545696f22f0SJohn Baldwin || (pmp->pm_FATsecs == 0) 546952a6212SJordan K. Hubbard ) { 547952a6212SJordan K. Hubbard error = EINVAL; 548952a6212SJordan K. Hubbard goto error_exit; 549952a6212SJordan K. Hubbard } 55001f6cfbaSYoshihiro Takahashi 55101f6cfbaSYoshihiro Takahashi pmp->pm_HugeSectors *= pmp->pm_BlkPerSec; 55201f6cfbaSYoshihiro Takahashi pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; /* XXX not used? */ 55301f6cfbaSYoshihiro Takahashi pmp->pm_FATsecs *= pmp->pm_BlkPerSec; 55401f6cfbaSYoshihiro Takahashi SecPerClust *= pmp->pm_BlkPerSec; 55501f6cfbaSYoshihiro Takahashi 55601f6cfbaSYoshihiro Takahashi pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec; 55701f6cfbaSYoshihiro Takahashi 558952a6212SJordan K. Hubbard if (FAT32(pmp)) { 559952a6212SJordan K. Hubbard pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 560952a6212SJordan K. Hubbard pmp->pm_firstcluster = pmp->pm_fatblk 561952a6212SJordan K. Hubbard + (pmp->pm_FATs * pmp->pm_FATsecs); 56201f6cfbaSYoshihiro Takahashi pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec; 563952a6212SJordan K. Hubbard } else { 56427a0bc89SDoug Rabson pmp->pm_rootdirblk = pmp->pm_fatblk + 56527a0bc89SDoug Rabson (pmp->pm_FATs * pmp->pm_FATsecs); 566952a6212SJordan K. Hubbard pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) 56701f6cfbaSYoshihiro Takahashi + DEV_BSIZE - 1) 56801f6cfbaSYoshihiro Takahashi / DEV_BSIZE; /* in blocks */ 56927a0bc89SDoug Rabson pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 570952a6212SJordan K. Hubbard } 571952a6212SJordan K. Hubbard 572499d3ffaSBoris Popov pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 573499d3ffaSBoris Popov SecPerClust + 1; 57401f6cfbaSYoshihiro Takahashi pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; /* XXX not used? */ 575952a6212SJordan K. Hubbard 576952a6212SJordan K. Hubbard if (pmp->pm_fatmask == 0) { 577952a6212SJordan K. Hubbard if (pmp->pm_maxcluster 578952a6212SJordan K. Hubbard <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 57927a0bc89SDoug Rabson /* 580952a6212SJordan K. Hubbard * This will usually be a floppy disk. This size makes 581952a6212SJordan K. Hubbard * sure that one fat entry will not be split across 582952a6212SJordan K. Hubbard * multiple blocks. 58327a0bc89SDoug Rabson */ 584952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT12_MASK; 585952a6212SJordan K. Hubbard pmp->pm_fatmult = 3; 586952a6212SJordan K. Hubbard pmp->pm_fatdiv = 2; 587952a6212SJordan K. Hubbard } else { 588952a6212SJordan K. Hubbard pmp->pm_fatmask = FAT16_MASK; 589952a6212SJordan K. Hubbard pmp->pm_fatmult = 2; 590952a6212SJordan K. Hubbard pmp->pm_fatdiv = 1; 591952a6212SJordan K. Hubbard } 592952a6212SJordan K. Hubbard } 593499d3ffaSBoris Popov 594499d3ffaSBoris Popov clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv; 595499d3ffaSBoris Popov if (pmp->pm_maxcluster >= clusters) { 596499d3ffaSBoris Popov printf("Warning: number of clusters (%ld) exceeds FAT " 597499d3ffaSBoris Popov "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters); 598499d3ffaSBoris Popov pmp->pm_maxcluster = clusters - 1; 599499d3ffaSBoris Popov } 600499d3ffaSBoris Popov 601499d3ffaSBoris Popov 602952a6212SJordan K. Hubbard if (FAT12(pmp)) 60327a0bc89SDoug Rabson pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 60427a0bc89SDoug Rabson else 605152ffafeSBruce Evans pmp->pm_fatblocksize = MSDOSFS_DFLTBSIZE; 606952a6212SJordan K. Hubbard 60701f6cfbaSYoshihiro Takahashi pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; 60801f6cfbaSYoshihiro Takahashi pmp->pm_bnshift = ffs(DEV_BSIZE) - 1; 60927a0bc89SDoug Rabson 61027a0bc89SDoug Rabson /* 61127a0bc89SDoug Rabson * Compute mask and shift value for isolating cluster relative byte 61227a0bc89SDoug Rabson * offsets and cluster numbers from a file offset. 61327a0bc89SDoug Rabson */ 61401f6cfbaSYoshihiro Takahashi pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; 615952a6212SJordan K. Hubbard pmp->pm_crbomask = pmp->pm_bpcluster - 1; 616952a6212SJordan K. Hubbard pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 61727a0bc89SDoug Rabson 618952a6212SJordan K. Hubbard /* 619952a6212SJordan K. Hubbard * Check for valid cluster size 620952a6212SJordan K. Hubbard * must be a power of 2 621952a6212SJordan K. Hubbard */ 622952a6212SJordan K. Hubbard if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 623952a6212SJordan K. Hubbard error = EINVAL; 624952a6212SJordan K. Hubbard goto error_exit; 625ad63a118SSatoshi Asami } 62627a0bc89SDoug Rabson 62727a0bc89SDoug Rabson /* 62827a0bc89SDoug Rabson * Release the bootsector buffer. 62927a0bc89SDoug Rabson */ 630952a6212SJordan K. Hubbard brelse(bp); 631952a6212SJordan K. Hubbard bp = NULL; 632952a6212SJordan K. Hubbard 633952a6212SJordan K. Hubbard /* 634952a6212SJordan K. Hubbard * Check FSInfo. 635952a6212SJordan K. Hubbard */ 636952a6212SJordan K. Hubbard if (pmp->pm_fsinfo) { 637952a6212SJordan K. Hubbard struct fsinfo *fp; 638952a6212SJordan K. Hubbard 63901f6cfbaSYoshihiro Takahashi if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp), 64001f6cfbaSYoshihiro Takahashi NOCRED, &bp)) != 0) 641952a6212SJordan K. Hubbard goto error_exit; 642952a6212SJordan K. Hubbard fp = (struct fsinfo *)bp->b_data; 643952a6212SJordan K. Hubbard if (!bcmp(fp->fsisig1, "RRaA", 4) 644952a6212SJordan K. Hubbard && !bcmp(fp->fsisig2, "rrAa", 4) 645952a6212SJordan K. Hubbard && !bcmp(fp->fsisig3, "\0\0\125\252", 4) 6468bb386f2STim J. Robbins && !bcmp(fp->fsisig4, "\0\0\125\252", 4)) { 647952a6212SJordan K. Hubbard pmp->pm_nxtfree = getulong(fp->fsinxtfree); 6488bb386f2STim J. Robbins if (pmp->pm_nxtfree == 0xffffffff) 6498bb386f2STim J. Robbins pmp->pm_nxtfree = CLUST_FIRST; 6508bb386f2STim J. Robbins } else 651952a6212SJordan K. Hubbard pmp->pm_fsinfo = 0; 652952a6212SJordan K. Hubbard brelse(bp); 653952a6212SJordan K. Hubbard bp = NULL; 654952a6212SJordan K. Hubbard } 655952a6212SJordan K. Hubbard 656952a6212SJordan K. Hubbard /* 657abe78e97STom Rhodes * Check and validate (or perhaps invalidate?) the fsinfo structure? 658952a6212SJordan K. Hubbard */ 659abe78e97STom Rhodes if (pmp->pm_fsinfo && pmp->pm_nxtfree > pmp->pm_maxcluster) { 66034bdf0dcSBruce Evans printf( 66134bdf0dcSBruce Evans "Next free cluster in FSInfo (%lu) exceeds maxcluster (%lu)\n", 662abe78e97STom Rhodes pmp->pm_nxtfree, pmp->pm_maxcluster); 663abe78e97STom Rhodes error = EINVAL; 664abe78e97STom Rhodes goto error_exit; 665abe78e97STom Rhodes } 66627a0bc89SDoug Rabson 66727a0bc89SDoug Rabson /* 66827a0bc89SDoug Rabson * Allocate memory for the bitmap of allocated clusters, and then 66927a0bc89SDoug Rabson * fill it in. 67027a0bc89SDoug Rabson */ 6710ef0dd6fSBruce Evans pmp->pm_inusemap = malloc(howmany(pmp->pm_maxcluster + 1, N_INUSEBITS) 67227a0bc89SDoug Rabson * sizeof(*pmp->pm_inusemap), 673a163d034SWarner Losh M_MSDOSFSFAT, M_WAITOK); 67427a0bc89SDoug Rabson 67527a0bc89SDoug Rabson /* 67627a0bc89SDoug Rabson * fillinusemap() needs pm_devvp. 67727a0bc89SDoug Rabson */ 67827a0bc89SDoug Rabson pmp->pm_devvp = devvp; 67927a0bc89SDoug Rabson 68027a0bc89SDoug Rabson /* 68127a0bc89SDoug Rabson * Have the inuse map filled in. 68227a0bc89SDoug Rabson */ 683952a6212SJordan K. Hubbard if ((error = fillinusemap(pmp)) != 0) 68427a0bc89SDoug Rabson goto error_exit; 68527a0bc89SDoug Rabson 68627a0bc89SDoug Rabson /* 68727a0bc89SDoug Rabson * If they want fat updates to be synchronous then let them suffer 68827a0bc89SDoug Rabson * the performance degradation in exchange for the on disk copy of 68927a0bc89SDoug Rabson * the fat being correct just about all the time. I suppose this 69027a0bc89SDoug Rabson * would be a good thing to turn on if the kernel is still flakey. 69127a0bc89SDoug Rabson */ 692952a6212SJordan K. Hubbard if (mp->mnt_flag & MNT_SYNCHRONOUS) 693952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 69427a0bc89SDoug Rabson 69527a0bc89SDoug Rabson /* 69627a0bc89SDoug Rabson * Finish up. 69727a0bc89SDoug Rabson */ 698952a6212SJordan K. Hubbard if (ronly) 699952a6212SJordan K. Hubbard pmp->pm_flags |= MSDOSFSMNT_RONLY; 700cede1f56STom Rhodes else { 701a78c9287SBruce Evans /* Mark the volume dirty while it is mounted read/write. */ 702cede1f56STom Rhodes if ((error = markvoldirty(pmp, 1)) != 0) 703cede1f56STom Rhodes goto error_exit; 70427a0bc89SDoug Rabson pmp->pm_fmod = 1; 705cede1f56STom Rhodes } 70627a0bc89SDoug Rabson mp->mnt_data = (qaddr_t) pmp; 707939cb752SBruce Evans mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 708af3f60d5SBruce Evans mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 709cc9d8990SPeter Wemm mp->mnt_flag |= MNT_LOCAL; 71027a0bc89SDoug Rabson 7113bc482ecSTim J. Robbins #ifdef MSDOSFS_LARGE 7123bc482ecSTim J. Robbins msdosfs_fileno_init(mp); 7133bc482ecSTim J. Robbins #endif 7143bc482ecSTim J. Robbins 71527a0bc89SDoug Rabson return 0; 71627a0bc89SDoug Rabson 717952a6212SJordan K. Hubbard error_exit: 718952a6212SJordan K. Hubbard if (bp) 719952a6212SJordan K. Hubbard brelse(bp); 7209a135592SPoul-Henning Kamp if (cp != NULL) { 7219a135592SPoul-Henning Kamp DROP_GIANT(); 7229a135592SPoul-Henning Kamp g_topology_lock(); 72384a69752SPoul-Henning Kamp g_vfs_close(cp, td); 7249a135592SPoul-Henning Kamp g_topology_unlock(); 7259a135592SPoul-Henning Kamp PICKUP_GIANT(); 7269a135592SPoul-Henning Kamp } 72727a0bc89SDoug Rabson if (pmp) { 72827a0bc89SDoug Rabson if (pmp->pm_inusemap) 729952a6212SJordan K. Hubbard free(pmp->pm_inusemap, M_MSDOSFSFAT); 730952a6212SJordan K. Hubbard free(pmp, M_MSDOSFSMNT); 73127a0bc89SDoug Rabson mp->mnt_data = (qaddr_t)0; 73227a0bc89SDoug Rabson } 733952a6212SJordan K. Hubbard return (error); 73427a0bc89SDoug Rabson } 73527a0bc89SDoug Rabson 73627a0bc89SDoug Rabson /* 73727a0bc89SDoug Rabson * Unmount the filesystem described by mp. 73827a0bc89SDoug Rabson */ 7397fefffeeSPoul-Henning Kamp static int 740b40ce416SJulian Elischer msdosfs_unmount(mp, mntflags, td) 74127a0bc89SDoug Rabson struct mount *mp; 74227a0bc89SDoug Rabson int mntflags; 743b40ce416SJulian Elischer struct thread *td; 74427a0bc89SDoug Rabson { 745952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 746952a6212SJordan K. Hubbard int error, flags; 74727a0bc89SDoug Rabson 748952a6212SJordan K. Hubbard flags = 0; 749952a6212SJordan K. Hubbard if (mntflags & MNT_FORCE) 75027a0bc89SDoug Rabson flags |= FORCECLOSE; 751f257b7a5SAlfred Perlstein error = vflush(mp, 0, flags, td); 752c3c6d51eSPoul-Henning Kamp if (error) 75327a0bc89SDoug Rabson return error; 754952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 755c4f02a89SMax Khon if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 756c4f02a89SMax Khon if (pmp->pm_w2u) 757c4f02a89SMax Khon msdosfs_iconv->close(pmp->pm_w2u); 758c4f02a89SMax Khon if (pmp->pm_u2w) 759c4f02a89SMax Khon msdosfs_iconv->close(pmp->pm_u2w); 760c4f02a89SMax Khon if (pmp->pm_d2u) 761c4f02a89SMax Khon msdosfs_iconv->close(pmp->pm_d2u); 762c4f02a89SMax Khon if (pmp->pm_u2d) 763c4f02a89SMax Khon msdosfs_iconv->close(pmp->pm_u2d); 764c4f02a89SMax Khon } 765cede1f56STom Rhodes 766a78c9287SBruce Evans /* If the volume was mounted read/write, mark it clean now. */ 767cede1f56STom Rhodes if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) { 768cede1f56STom Rhodes error = markvoldirty(pmp, 0); 769a78c9287SBruce Evans if (error && (flags & FORCECLOSE) == 0) 770cede1f56STom Rhodes return (error); 771cede1f56STom Rhodes } 772952a6212SJordan K. Hubbard #ifdef MSDOSFS_DEBUG 773952a6212SJordan K. Hubbard { 774952a6212SJordan K. Hubbard struct vnode *vp = pmp->pm_devvp; 775952a6212SJordan K. Hubbard 7764d93c0beSJeff Roberson VI_LOCK(vp); 777f69d42a1SPoul-Henning Kamp vn_printf(vp, 778f69d42a1SPoul-Henning Kamp "msdosfs_umount(): just before calling VOP_CLOSE()\n"); 779952a6212SJordan K. Hubbard printf("freef %p, freeb %p, mount %p\n", 780fc2ffbe6SPoul-Henning Kamp TAILQ_NEXT(vp, v_freelist), vp->v_freelist.tqe_prev, 781952a6212SJordan K. Hubbard vp->v_mount); 782952a6212SJordan K. Hubbard printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", 783156cb265SPoul-Henning Kamp TAILQ_FIRST(&vp->v_bufobj.bo_clean.bv_hd), 784156cb265SPoul-Henning Kamp TAILQ_FIRST(&vp->v_bufobj.bo_dirty.bv_hd), 785156cb265SPoul-Henning Kamp vp->v_bufobj.bo_numoutput, vp->v_type); 7864d93c0beSJeff Roberson VI_UNLOCK(vp); 787952a6212SJordan K. Hubbard } 788952a6212SJordan K. Hubbard #endif 7899a135592SPoul-Henning Kamp DROP_GIANT(); 7909a135592SPoul-Henning Kamp g_topology_lock(); 79184a69752SPoul-Henning Kamp g_vfs_close(pmp->pm_cp, td); 7929a135592SPoul-Henning Kamp g_topology_unlock(); 7939a135592SPoul-Henning Kamp PICKUP_GIANT(); 79427a0bc89SDoug Rabson vrele(pmp->pm_devvp); 795952a6212SJordan K. Hubbard free(pmp->pm_inusemap, M_MSDOSFSFAT); 7963bc482ecSTim J. Robbins #ifdef MSDOSFS_LARGE 7973bc482ecSTim J. Robbins msdosfs_fileno_free(mp); 7983bc482ecSTim J. Robbins #endif 799952a6212SJordan K. Hubbard free(pmp, M_MSDOSFSMNT); 80027a0bc89SDoug Rabson mp->mnt_data = (qaddr_t)0; 801cc9d8990SPeter Wemm mp->mnt_flag &= ~MNT_LOCAL; 802952a6212SJordan K. Hubbard return (error); 80327a0bc89SDoug Rabson } 80427a0bc89SDoug Rabson 8057fefffeeSPoul-Henning Kamp static int 806d9b2d9f7SJeff Roberson msdosfs_root(mp, flags, vpp, td) 80727a0bc89SDoug Rabson struct mount *mp; 808d9b2d9f7SJeff Roberson int flags; 80927a0bc89SDoug Rabson struct vnode **vpp; 810f257b7a5SAlfred Perlstein struct thread *td; 81127a0bc89SDoug Rabson { 812952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 81327a0bc89SDoug Rabson struct denode *ndep; 81427a0bc89SDoug Rabson int error; 81527a0bc89SDoug Rabson 81627a0bc89SDoug Rabson #ifdef MSDOSFS_DEBUG 817952a6212SJordan K. Hubbard printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 81827a0bc89SDoug Rabson #endif 819952a6212SJordan K. Hubbard error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep); 820952a6212SJordan K. Hubbard if (error) 821952a6212SJordan K. Hubbard return (error); 82227a0bc89SDoug Rabson *vpp = DETOV(ndep); 823952a6212SJordan K. Hubbard return (0); 82427a0bc89SDoug Rabson } 82527a0bc89SDoug Rabson 8267fefffeeSPoul-Henning Kamp static int 827b40ce416SJulian Elischer msdosfs_statfs(mp, sbp, td) 82827a0bc89SDoug Rabson struct mount *mp; 82927a0bc89SDoug Rabson struct statfs *sbp; 830b40ce416SJulian Elischer struct thread *td; 83127a0bc89SDoug Rabson { 832952a6212SJordan K. Hubbard struct msdosfsmount *pmp; 83327a0bc89SDoug Rabson 834952a6212SJordan K. Hubbard pmp = VFSTOMSDOSFS(mp); 83527a0bc89SDoug Rabson sbp->f_bsize = pmp->pm_bpcluster; 83627a0bc89SDoug Rabson sbp->f_iosize = pmp->pm_bpcluster; 837499d3ffaSBoris Popov sbp->f_blocks = pmp->pm_maxcluster + 1; 83827a0bc89SDoug Rabson sbp->f_bfree = pmp->pm_freeclustercount; 83927a0bc89SDoug Rabson sbp->f_bavail = pmp->pm_freeclustercount; 84027a0bc89SDoug Rabson sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 84127a0bc89SDoug Rabson sbp->f_ffree = 0; /* what to put in here? */ 842952a6212SJordan K. Hubbard return (0); 84327a0bc89SDoug Rabson } 84427a0bc89SDoug Rabson 8457fefffeeSPoul-Henning Kamp static int 8468df6bac4SPoul-Henning Kamp msdosfs_sync(mp, waitfor, td) 84727a0bc89SDoug Rabson struct mount *mp; 84827a0bc89SDoug Rabson int waitfor; 849b40ce416SJulian Elischer struct thread *td; 85027a0bc89SDoug Rabson { 851952a6212SJordan K. Hubbard struct vnode *vp, *nvp; 85227a0bc89SDoug Rabson struct denode *dep; 853952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 854952a6212SJordan K. Hubbard int error, allerror = 0; 85527a0bc89SDoug Rabson 85627a0bc89SDoug Rabson /* 85727a0bc89SDoug Rabson * If we ever switch to not updating all of the fats all the time, 85827a0bc89SDoug Rabson * this would be the place to update them from the first one. 85927a0bc89SDoug Rabson */ 860dfd5dee1SPeter Wemm if (pmp->pm_fmod != 0) { 861952a6212SJordan K. Hubbard if (pmp->pm_flags & MSDOSFSMNT_RONLY) 86227a0bc89SDoug Rabson panic("msdosfs_sync: rofs mod"); 86327a0bc89SDoug Rabson else { 86427a0bc89SDoug Rabson /* update fats here */ 86527a0bc89SDoug Rabson } 866dfd5dee1SPeter Wemm } 86727a0bc89SDoug Rabson /* 868952a6212SJordan K. Hubbard * Write back each (modified) denode. 86927a0bc89SDoug Rabson */ 870ca430f2eSAlexander Kabaev MNT_ILOCK(mp); 87127a0bc89SDoug Rabson loop: 872e3c5a7a4SPoul-Henning Kamp MNT_VNODE_FOREACH(vp, mp, nvp) { 8734d93c0beSJeff Roberson VI_LOCK(vp); 8748da00465SJeff Roberson if (vp->v_type == VNON || (vp->v_iflag & VI_DOOMED)) { 8754ab2c8bdSJeff Roberson VI_UNLOCK(vp); 8764ab2c8bdSJeff Roberson continue; 8774ab2c8bdSJeff Roberson } 878ca430f2eSAlexander Kabaev MNT_IUNLOCK(mp); 87927a0bc89SDoug Rabson dep = VTODE(vp); 880f00f5d71SPoul-Henning Kamp if ((dep->de_flag & 881c681be37SDmitrij Tejblum (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0 && 882156cb265SPoul-Henning Kamp (vp->v_bufobj.bo_dirty.bv_cnt == 0 || 883f00f5d71SPoul-Henning Kamp waitfor == MNT_LAZY)) { 8844d93c0beSJeff Roberson VI_UNLOCK(vp); 885ca430f2eSAlexander Kabaev MNT_ILOCK(mp); 88627a0bc89SDoug Rabson continue; 887af3f60d5SBruce Evans } 888b40ce416SJulian Elischer error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, td); 889af3f60d5SBruce Evans if (error) { 890ca430f2eSAlexander Kabaev MNT_ILOCK(mp); 891af3f60d5SBruce Evans if (error == ENOENT) 89227a0bc89SDoug Rabson goto loop; 893af3f60d5SBruce Evans continue; 894af3f60d5SBruce Evans } 8958df6bac4SPoul-Henning Kamp error = VOP_FSYNC(vp, waitfor, td); 896c3c6d51eSPoul-Henning Kamp if (error) 89727a0bc89SDoug Rabson allerror = error; 898cb9ddc80SAlexander Kabaev VOP_UNLOCK(vp, 0, td); 899cb9ddc80SAlexander Kabaev vrele(vp); 900ca430f2eSAlexander Kabaev MNT_ILOCK(mp); 90127a0bc89SDoug Rabson } 902ca430f2eSAlexander Kabaev MNT_IUNLOCK(mp); 90327a0bc89SDoug Rabson 90427a0bc89SDoug Rabson /* 90527a0bc89SDoug Rabson * Flush filesystem control info. 90627a0bc89SDoug Rabson */ 907c681be37SDmitrij Tejblum if (waitfor != MNT_LAZY) { 908b40ce416SJulian Elischer vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY, td); 9098df6bac4SPoul-Henning Kamp error = VOP_FSYNC(pmp->pm_devvp, waitfor, td); 910c3c6d51eSPoul-Henning Kamp if (error) 91127a0bc89SDoug Rabson allerror = error; 912b40ce416SJulian Elischer VOP_UNLOCK(pmp->pm_devvp, 0, td); 913c681be37SDmitrij Tejblum } 914952a6212SJordan K. Hubbard return (allerror); 91527a0bc89SDoug Rabson } 91627a0bc89SDoug Rabson 9177fefffeeSPoul-Henning Kamp static int 918c24fda81SAlfred Perlstein msdosfs_fhtovp(mp, fhp, vpp) 91927a0bc89SDoug Rabson struct mount *mp; 92027a0bc89SDoug Rabson struct fid *fhp; 92127a0bc89SDoug Rabson struct vnode **vpp; 92227a0bc89SDoug Rabson { 923952a6212SJordan K. Hubbard struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 92427a0bc89SDoug Rabson struct defid *defhp = (struct defid *) fhp; 92527a0bc89SDoug Rabson struct denode *dep; 92627a0bc89SDoug Rabson int error; 92727a0bc89SDoug Rabson 928952a6212SJordan K. Hubbard error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); 92927a0bc89SDoug Rabson if (error) { 93027a0bc89SDoug Rabson *vpp = NULLVP; 931952a6212SJordan K. Hubbard return (error); 93227a0bc89SDoug Rabson } 93327a0bc89SDoug Rabson *vpp = DETOV(dep); 934625d4bc0SPoul-Henning Kamp vnode_create_vobject(*vpp, dep->de_FileSize, curthread); 935c24fda81SAlfred Perlstein return (0); 936c24fda81SAlfred Perlstein } 937c24fda81SAlfred Perlstein 938c24fda81SAlfred Perlstein static int 93927a0bc89SDoug Rabson msdosfs_vptofh(vp, fhp) 94027a0bc89SDoug Rabson struct vnode *vp; 94127a0bc89SDoug Rabson struct fid *fhp; 94227a0bc89SDoug Rabson { 943952a6212SJordan K. Hubbard struct denode *dep; 944952a6212SJordan K. Hubbard struct defid *defhp; 94527a0bc89SDoug Rabson 946952a6212SJordan K. Hubbard dep = VTODE(vp); 947952a6212SJordan K. Hubbard defhp = (struct defid *)fhp; 94827a0bc89SDoug Rabson defhp->defid_len = sizeof(struct defid); 94927a0bc89SDoug Rabson defhp->defid_dirclust = dep->de_dirclust; 95027a0bc89SDoug Rabson defhp->defid_dirofs = dep->de_diroffset; 951952a6212SJordan K. Hubbard /* defhp->defid_gen = dep->de_gen; */ 952952a6212SJordan K. Hubbard return (0); 95327a0bc89SDoug Rabson } 95427a0bc89SDoug Rabson 95530ffadf3SPoul-Henning Kamp static struct vfsops msdosfs_vfsops = { 9567652131bSPoul-Henning Kamp .vfs_fhtovp = msdosfs_fhtovp, 9576a4b48f4SPoul-Henning Kamp .vfs_mount = msdosfs_mount, 9586a4b48f4SPoul-Henning Kamp .vfs_cmount = msdosfs_cmount, 9597652131bSPoul-Henning Kamp .vfs_root = msdosfs_root, 9607652131bSPoul-Henning Kamp .vfs_statfs = msdosfs_statfs, 9617652131bSPoul-Henning Kamp .vfs_sync = msdosfs_sync, 9627652131bSPoul-Henning Kamp .vfs_unmount = msdosfs_unmount, 9637652131bSPoul-Henning Kamp .vfs_vptofh = msdosfs_vptofh, 96427a0bc89SDoug Rabson }; 965c901836cSGarrett Wollman 9664ccd7546SRuslan Ermilov VFS_SET(msdosfs_vfsops, msdosfs, 0); 967c4f02a89SMax Khon MODULE_VERSION(msdosfs, 1); 968