From fdf518fe9a7942b309ce0ea9424e5670fcdf27c3 Mon Sep 17 00:00:00 2001 From: rodrigc Date: Tue, 30 Jan 2007 03:11:45 +0000 Subject: Add a "-o large" mount option for msdosfs. Convert compile-time checks for #ifdef MSDOSFS_LARGE to run-time checks to see if "-o large" was specified. Test case provided by Oliver Fromme: truncate -s 200G test.img mdconfig -a -t vnode -f test.img -u 9 newfs_msdos -s 419430400 -n 1 /dev/md9 zip250 mount -t msdosfs /dev/md9 /mnt # should fail mount -t msdosfs -o large /dev/md9 /mnt # should succeed PR: 105964 Requested by: Oliver Fromme Tested by: trhodes MFC after: 2 weeks --- sys/fs/msdosfs/msdosfs_vfsops.c | 53 ++++++++++++++++++++++++++--------------- sys/fs/msdosfs/msdosfs_vnops.c | 37 +++++++++++++++------------- 2 files changed, 54 insertions(+), 36 deletions(-) (limited to 'sys/fs') diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c index 5bc7ba8..d1999e9 100644 --- a/sys/fs/msdosfs/msdosfs_vfsops.c +++ b/sys/fs/msdosfs/msdosfs_vfsops.c @@ -83,7 +83,7 @@ static const char *msdosfs_opts[] = { "export", "force", "sync", "uid", "gid", "mask", "dirmask", "shortname", "shortnames", "longname", "longnames", "nowin95", "win95", - "kiconv", "cs_win", "cs_dos", "cs_local", + "kiconv", "cs_win", "cs_dos", "cs_local", "large", NULL }; @@ -467,6 +467,21 @@ mountmsdosfs(devvp, mp, td) pmp->pm_bo = bo; /* + * Experimental support for large MS-DOS filesystems. + * WARNING: This uses at least 32 bytes of kernel memory (which is not + * reclaimed until the FS is unmounted) for each file on disk to map + * between the 32-bit inode numbers used by VFS and the 64-bit + * pseudo-inode numbers used internally by msdosfs. This is only + * safe to use in certain controlled situations (e.g. read-only FS + * with less than 1 million files). + * Since the mappings do not persist across unmounts (or reboots), these + * filesystems are not suitable for exporting through NFS, or any other + * application that requires fixed inode numbers. + */ + vfs_flagopt(mp->mnt_optnew, "large", &pmp->pm_flags, + MSDOSFS_LARGEFS); + + /* * Compute several useful quantities from the bpb in the * bootsector. Copy in the dos 5 variant of the bpb then fix up * the fields that are different between dos 5 and dos 3.3. @@ -508,19 +523,20 @@ mountmsdosfs(devvp, mp, td) pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); pmp->pm_HugeSectors = pmp->pm_Sectors; } -#ifndef MSDOSFS_LARGE - if (pmp->pm_HugeSectors > 0xffffffff / - (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) { - /* - * We cannot deal currently with this size of disk - * due to fileid limitations (see msdosfs_getattr and - * msdosfs_readdir) - */ - error = EINVAL; - printf("mountmsdosfs(): disk too big, sorry\n"); - goto error_exit; + if (!(pmp->pm_flags & MSDOSFS_LARGEFS)) { + if (pmp->pm_HugeSectors > 0xffffffff / + (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) { + /* + * We cannot deal currently with this size of disk + * due to fileid limitations (see msdosfs_getattr and + * msdosfs_readdir) + */ + error = EINVAL; + vfs_mount_error(mp, + "Disk too big, try '-o large' mount option"); + goto error_exit; + } } -#endif /* !MSDOSFS_LARGE */ if (pmp->pm_RootDirEnts == 0) { if (pmp->pm_Sectors @@ -721,9 +737,8 @@ mountmsdosfs(devvp, mp, td) mp->mnt_flag |= MNT_LOCAL; MNT_IUNLOCK(mp); -#ifdef MSDOSFS_LARGE - msdosfs_fileno_init(mp); -#endif + if (pmp->pm_flags & MSDOSFS_LARGEFS) + msdosfs_fileno_init(mp); return 0; @@ -806,9 +821,9 @@ msdosfs_unmount(mp, mntflags, td) PICKUP_GIANT(); vrele(pmp->pm_devvp); free(pmp->pm_inusemap, M_MSDOSFSFAT); -#ifdef MSDOSFS_LARGE - msdosfs_fileno_free(mp); -#endif + if (pmp->pm_flags & MSDOSFS_LARGEFS) { + msdosfs_fileno_free(mp); + } free(pmp, M_MSDOSFSMNT); mp->mnt_data = (qaddr_t)0; MNT_ILOCK(mp); diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c index 57b0ec8..cc0a046 100644 --- a/sys/fs/msdosfs/msdosfs_vnops.c +++ b/sys/fs/msdosfs/msdosfs_vnops.c @@ -326,11 +326,12 @@ msdosfs_getattr(ap) fileid = (uint64_t)roottobn(pmp, 0) * dirsperblk; fileid += (uint64_t)dep->de_diroffset / sizeof(struct direntry); } -#ifdef MSDOSFS_LARGE - vap->va_fileid = msdosfs_fileno_map(pmp->pm_mountp, fileid); -#else - vap->va_fileid = (long)fileid; -#endif + + if (pmp->pm_flags & MSDOSFS_LARGEFS) + vap->va_fileid = msdosfs_fileno_map(pmp->pm_mountp, fileid); + else + vap->va_fileid = (long)fileid; + if ((dep->de_Attributes & ATTR_READONLY) == 0) mode = S_IRWXU|S_IRWXG|S_IRWXO; else @@ -1571,12 +1572,14 @@ msdosfs_readdir(ap) * dirsperblk; else fileno = 1; -#ifdef MSDOSFS_LARGE - dirbuf.d_fileno = msdosfs_fileno_map( - pmp->pm_mountp, fileno); -#else - dirbuf.d_fileno = (uint32_t)fileno; -#endif + if (pmp->pm_flags & MSDOSFS_LARGEFS) { + dirbuf.d_fileno = + msdosfs_fileno_map(pmp->pm_mountp, + fileno); + } else { + + dirbuf.d_fileno = (uint32_t)fileno; + } dirbuf.d_type = DT_DIR; switch (n) { case 0: @@ -1700,12 +1703,12 @@ msdosfs_readdir(ap) fileno = (uint64_t)offset / sizeof(struct direntry); dirbuf.d_type = DT_REG; } -#ifdef MSDOSFS_LARGE - dirbuf.d_fileno = msdosfs_fileno_map(pmp->pm_mountp, - fileno); -#else - dirbuf.d_fileno = (uint32_t)fileno; -#endif + if (pmp->pm_flags & MSDOSFS_LARGEFS) { + dirbuf.d_fileno = + msdosfs_fileno_map(pmp->pm_mountp, fileno); + } else + dirbuf.d_fileno = (uint32_t)fileno; + if (chksum != winChksum(dentp)) { dirbuf.d_namlen = dos2unixfn(dentp->deName, (u_char *)dirbuf.d_name, -- cgit v1.1