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 <olli lurza secnetix de>
Tested by:	trhodes
MFC after:	2 weeks
This commit is contained in:
Craig Rodrigues 2007-01-30 03:11:45 +00:00
parent 25777ce331
commit f458f2a553
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=166340
3 changed files with 55 additions and 37 deletions

View file

@ -1106,7 +1106,7 @@ fs/hpfs/hpfs_vnops.c optional hpfs
fs/msdosfs/msdosfs_conv.c optional msdosfs
fs/msdosfs/msdosfs_denode.c optional msdosfs
fs/msdosfs/msdosfs_fat.c optional msdosfs
fs/msdosfs/msdosfs_fileno.c optional msdosfs_large
fs/msdosfs/msdosfs_fileno.c optional msdosfs
fs/msdosfs/msdosfs_iconv.c optional msdosfs_iconv
fs/msdosfs/msdosfs_lookup.c optional msdosfs
fs/msdosfs/msdosfs_vfsops.c optional msdosfs

View file

@ -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
};
@ -466,6 +466,21 @@ mountmsdosfs(devvp, mp, td)
pmp->pm_cp = cp;
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
@ -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);

View file

@ -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,