mkdosfs: by default align all structures to cluster boundaries

Align all data structures (reserved sectors, FATs, root directory for
FAT12/16) to an even multiple of the cluster size. This means that if
the partition is aligned, so will all clusters be. This adds
significant performance for anything where the physical sector size is
larger than the logical sector size, e.g. flash media or large-sector
hard disks.

Signed-off-by: Daniel Baumann <mail@daniel-baumann.ch>
This commit is contained in:
H. Peter Anvin 2010-01-06 11:18:55 +01:00 committed by Daniel Baumann
parent 171bc07b0c
commit 247ba068d4
2 changed files with 85 additions and 24 deletions

View File

@ -6,6 +6,9 @@
.SH SYNOPSIS
.B mkdosfs|mkfs.msdos|mkfs.vfat
[
.B \-a
]
[
.B \-A
]
[
@ -82,6 +85,14 @@ is the number of blocks on the device. If omitted,
automatically determines the file system size.
.SH OPTIONS
.TP
.B \-a
Normally, for any filesystem except very small ones, \fBmkdosfs\fP
will align all the data structures to cluster size, to make sure that
as long as the partition is properly aligned, so will all the data
structures in the filesystem. This option disables alignment; this
may provide a handful of additional clusters of storage at the expense
of much performance on flash media or large-sector hard disks.
.TP
.B \-A
Use Atari variation of the MS-DOS file system. This is default if
\fBmkdosfs\fP is run on an Atari, then this option turns off Atari

View File

@ -311,6 +311,7 @@ static int root_dir_entries = 0; /* Number of root directory entries */
static char *blank_sector; /* Blank sector - all zeros */
static int hidden_sectors = 0; /* Number of hidden sectors */
static int malloc_entire_fat = FALSE; /* Whether we should malloc() the entire FAT or not */
static int align_structures = TRUE; /* Whether to enforce alignment */
/* Function prototype definitions */
@ -784,6 +785,18 @@ establish_params (int device_num,int size)
}
}
/*
* If alignment is enabled, round the first argument up to the second; the
* latter must be a power of two.
*/
static unsigned int
align_object (unsigned int sectors, unsigned int clustsize)
{
if (align_structures)
return (sectors + clustsize - 1) & ~(clustsize - 1);
else
return sectors;
}
/* Create the filesystem data tables */
@ -792,7 +805,6 @@ setup_tables (void)
{
unsigned num_sectors;
unsigned cluster_count = 0, fat_length;
unsigned fatdata; /* Sectors for FATs + data area */
struct tm *ctime;
struct msdos_volume_info *vi = (size_fat == 32 ? &bs.fat32.vi : &bs.oldfat.vi);
@ -887,13 +899,24 @@ setup_tables (void)
num_sectors = (long long)blocks*BLOCK_SIZE/sector_size;
if (!atari_format) {
unsigned fatdata1216; /* Sectors for FATs + data area (FAT12/16) */
unsigned fatdata32; /* Sectors for FATs + data area (FAT32) */
unsigned fatlength12, fatlength16, fatlength32;
unsigned maxclust12, maxclust16, maxclust32;
unsigned clust12, clust16, clust32;
int maxclustsize;
unsigned root_dir_sectors = cdiv(root_dir_entries*32, sector_size);
fatdata = num_sectors - cdiv (root_dir_entries * 32, sector_size) -
reserved_sectors;
/*
* If the filesystem is 8192 sectors or less (4 MB with 512-byte
* sectors, i.e. floppy size), don't align the data structures.
*/
if (num_sectors <= 8192) {
if (align_structures && verbose >= 2)
printf ("Disabling alignment due to tiny filesystem\n");
align_structures = FALSE;
}
if (sectors_per_cluster)
bs.cluster_size = maxclustsize = sectors_per_cluster;
@ -901,22 +924,25 @@ setup_tables (void)
/* An initial guess for bs.cluster_size should already be set */
maxclustsize = 128;
if (verbose >= 2)
printf( "%d sectors for FAT+data, starting with %d sectors/cluster\n",
fatdata, bs.cluster_size );
do {
fatdata32 = num_sectors
- align_object(reserved_sectors, bs.cluster_size);
fatdata1216 = fatdata32
- align_object(root_dir_sectors, bs.cluster_size);
if (verbose >= 2)
printf( "Trying with %d sectors/cluster:\n", bs.cluster_size );
/* The factor 2 below avoids cut-off errors for nr_fats == 1.
* The "nr_fats*3" is for the reserved first two FAT entries */
clust12 = 2*((long long) fatdata *sector_size + nr_fats*3) /
clust12 = 2*((long long) fatdata1216*sector_size + nr_fats*3) /
(2*(int) bs.cluster_size * sector_size + nr_fats*3);
fatlength12 = cdiv(((clust12+2) * 3 + 1) >> 1, sector_size);
fatlength12 = align_object(fatlength12, bs.cluster_size);
/* Need to recalculate number of clusters, since the unused parts of the
* FATS and data area together could make up space for an additional,
* not really present cluster. */
clust12 = (fatdata - nr_fats*fatlength12)/bs.cluster_size;
clust12 = (fatdata1216 - nr_fats*fatlength12)/bs.cluster_size;
maxclust12 = (fatlength12 * 2 * sector_size) / 3;
if (maxclust12 > MAX_CLUST_12)
maxclust12 = MAX_CLUST_12;
@ -929,13 +955,14 @@ setup_tables (void)
printf( "FAT12: too much clusters\n" );
}
clust16 = ((long long) fatdata *sector_size + nr_fats*4) /
clust16 = ((long long) fatdata1216 *sector_size + nr_fats*4) /
((int) bs.cluster_size * sector_size + nr_fats*2);
fatlength16 = cdiv ((clust16+2) * 2, sector_size);
fatlength16 = align_object(fatlength16, bs.cluster_size);
/* Need to recalculate number of clusters, since the unused parts of the
* FATS and data area together could make up space for an additional,
* not really present cluster. */
clust16 = (fatdata - nr_fats*fatlength16)/bs.cluster_size;
clust16 = (fatdata1216 - nr_fats*fatlength16)/bs.cluster_size;
maxclust16 = (fatlength16 * sector_size) / 2;
if (maxclust16 > MAX_CLUST_16)
maxclust16 = MAX_CLUST_16;
@ -957,13 +984,14 @@ setup_tables (void)
clust16 = 0;
}
clust32 = ((long long) fatdata *sector_size + nr_fats*8) /
clust32 = ((long long) fatdata32 *sector_size + nr_fats*8) /
((int) bs.cluster_size * sector_size + nr_fats*4);
fatlength32 = cdiv((clust32+2) * 4, sector_size);
fatlength32 = align_object(fatlength32, bs.cluster_size);
/* Need to recalculate number of clusters, since the unused parts of the
* FATS and data area together could make up space for an additional,
* not really present cluster. */
clust32 = (fatdata - nr_fats*fatlength32)/bs.cluster_size;
clust32 = (fatdata32 - nr_fats*fatlength32)/bs.cluster_size;
maxclust32 = (fatlength32 * sector_size) / 4;
if (maxclust32 > MAX_CLUST_32)
maxclust32 = MAX_CLUST_32;
@ -1038,14 +1066,22 @@ setup_tables (void)
bs.fat_length = CT_LE_W(0);
bs.fat32.fat32_length = CT_LE_L(fatlength32);
memcpy(vi->fs_type, MSDOS_FAT32_SIGN, 8);
root_dir_entries = 0;
break;
default:
die("FAT not 12, 16 or 32 bits");
}
/* Adjust the reserved number of sectors for alignment */
reserved_sectors = align_object(reserved_sectors, bs.cluster_size);
/* Adjust the number of root directory entries to help enforce alignment */
root_dir_entries = align_object(root_dir_sectors, bs.cluster_size)
* (sector_size >> 5);
}
else {
unsigned clusters, maxclust;
unsigned clusters, maxclust, fatdata;
/* GEMDOS always uses a 12 bit FAT on floppies, and always a 16 bit FAT on
* hard disks. So use 12 bit if the size of the file system suggests that
@ -1207,9 +1243,19 @@ setup_tables (void)
printf ("FAT size is %d sector%s, and provides %d cluster%s.\n",
fat_length, (fat_length != 1) ? "s" : "",
cluster_count, (cluster_count != 1) ? "s" : "");
if (size_fat != 32)
printf ("Root directory contains %d slots.\n",
(int) (bs.dir_entries[0]) + (int) (bs.dir_entries[1]) * 256);
printf ("There %s %u reserved sector%s.\n",
(reserved_sectors != 1) ? "are" : "is",
reserved_sectors,
(reserved_sectors != 1) ? "s" : "");
if (size_fat != 32) {
unsigned root_dir_entries =
bs.dir_entries[0] + ((bs.dir_entries[1]) * 256);
unsigned root_dir_sectors =
cdiv (root_dir_entries*32, sector_size);
printf ("Root directory contains %u slots and uses %u sectors\n",
root_dir_entries, root_dir_sectors);
}
printf ("Volume ID is %08lx, ", volume_id &
(atari_format ? 0x00ffffff : 0xffffffff));
if ( strcmp(volume_name, " ") )
@ -1383,7 +1429,7 @@ void
usage (void)
{
fatal_error("\
Usage: mkdosfs [-A] [-c] [-C] [-v] [-I] [-l bad-block-file] [-b backup-boot-sector]\n\
Usage: mkdosfs [-a][-A][-c][-C][-v][-I][-l bad-block-file][-b backup-boot-sector]\n\
[-m boot-msg-file][-n volume-name][-i volume-id]\n\
[-s sectors-per-cluster][-S logical-sector-size][-f number-of-FATs]\n\
[-h hidden-sectors][-F fat-size][-r root-dir-entries][-R reserved-sectors]\n\
@ -1431,7 +1477,7 @@ main (int argc, char **argv)
struct stat statbuf;
int i = 0, pos, ch;
int create = 0;
unsigned long long cblocks;
unsigned long long cblocks = 0;
int min_sector_size;
if (argc && *argv) { /* What's the program name? */
@ -1449,7 +1495,7 @@ main (int argc, char **argv)
printf ("%s " VERSION " (" VERSION_DATE ")\n",
program_name);
while ((c = getopt (argc, argv, "Ab:cCf:F:Ii:l:m:n:r:R:s:S:h:v")) != EOF)
while ((c = getopt (argc, argv, "aAb:cCf:F:Ii:l:m:n:r:R:s:S:h:v")) != EOF)
/* Scan the command line for options */
switch (c)
{
@ -1457,6 +1503,10 @@ main (int argc, char **argv)
atari_format = !atari_format;
break;
case 'a': /* a : skip alignment */
align_structures = FALSE;
break;
case 'b': /* b : location of backup boot sector */
backup_boot = (int) strtol (optarg, &tmp, 0);
if (*tmp || backup_boot < 2 || backup_boot > 0xffff)