diff options
-rw-r--r-- | sys/conf/files | 2 | ||||
-rw-r--r-- | sys/fs/msdosfs/msdosfs_vfsops.c | 53 | ||||
-rw-r--r-- | sys/fs/msdosfs/msdosfs_vnops.c | 37 |
3 files changed, 55 insertions, 37 deletions
diff --git a/sys/conf/files b/sys/conf/files index f5155da..760b94a 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -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 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, |