Index: sbin/newfs_msdos/mkfs_msdos.h =================================================================== --- sbin/newfs_msdos/mkfs_msdos.h +++ sbin/newfs_msdos/mkfs_msdos.h @@ -34,6 +34,7 @@ #include #define ALLOPTS \ AOPT('@', off_t, offset, 0, "Offset in device") \ +AOPT('A', bool, align, -2, "Attempt to cluster align root directory") \ AOPT('B', const char *, bootstrap, -1, "Bootstrap file") \ AOPT('C', off_t, create_size, 0, "Create file") \ AOPT('F', uint8_t, fat_type, 12, "FAT type (12, 16, or 32)") \ @@ -61,7 +62,7 @@ struct msdos_options { #define AOPT(_opt, _type, _name, _min, _desc) _type _name; ALLOPTS -#undef AOPT +#undef AOPT uint32_t timestamp_set:1; uint32_t volume_id_set:1; uint32_t media_descriptor_set:1; Index: sbin/newfs_msdos/mkfs_msdos.c =================================================================== --- sbin/newfs_msdos/mkfs_msdos.c +++ sbin/newfs_msdos/mkfs_msdos.c @@ -242,6 +242,8 @@ ssize_t n; time_t now; u_int fat, bss, rds, cls, dir, lsn, x, x1, x2; + u_int extra_res, alignment, saved_x, attempts=0; + bool set_res, set_spf, set_spc; int fd, fd1, rv; struct msdos_options o = *op; @@ -486,50 +488,83 @@ if (bpb.bpbBackup != MAXU16 && x <= bpb.bpbBackup) x = bpb.bpbBackup + 1; } - if (!bpb.bpbResSectors) - bpb.bpbResSectors = fat == 32 ? - MAX(x, MAX(16384 / bpb.bpbBytesPerSec, 4)) : x; - else if (bpb.bpbResSectors < x) { - warnx("too few reserved sectors (need %d have %d)", x, - bpb.bpbResSectors); - goto done; - } - if (fat != 32 && !bpb.bpbRootDirEnts) - bpb.bpbRootDirEnts = DEFRDE; - rds = howmany(bpb.bpbRootDirEnts, bpb.bpbBytesPerSec / sizeof(struct de)); - if (!bpb.bpbSecPerClust) - for (bpb.bpbSecPerClust = howmany(fat == 16 ? DEFBLK16 : - DEFBLK, bpb.bpbBytesPerSec); - bpb.bpbSecPerClust < MAXSPC && - bpb.bpbResSectors + - howmany((RESFTE + maxcls(fat)) * (fat / BPN), - bpb.bpbBytesPerSec * NPB) * - bpb.bpbFATs + - rds + - (u_int64_t) (maxcls(fat) + 1) * - bpb.bpbSecPerClust <= bpb.bpbHugeSectors; - bpb.bpbSecPerClust <<= 1) - continue; - if (fat != 32 && bpb.bpbBigFATsecs > MAXU16) { - warnx("too many sectors/FAT for FAT12/16"); - goto done; - } - x1 = bpb.bpbResSectors + rds; - x = bpb.bpbBigFATsecs ? bpb.bpbBigFATsecs : 1; - if (x1 + (u_int64_t)x * bpb.bpbFATs > bpb.bpbHugeSectors) { - warnx("meta data exceeds file system size"); - goto done; - } - x1 += x * bpb.bpbFATs; - x = (u_int64_t)(bpb.bpbHugeSectors - x1) * bpb.bpbBytesPerSec * NPB / - (bpb.bpbSecPerClust * bpb.bpbBytesPerSec * NPB + fat / - BPN * bpb.bpbFATs); - x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN), - bpb.bpbBytesPerSec * NPB); - if (!bpb.bpbBigFATsecs) { - bpb.bpbBigFATsecs = x2; - x1 += (bpb.bpbBigFATsecs - 1) * bpb.bpbFATs; - } + + extra_res = 0; + alignment = 0; + set_res = (bpb.bpbResSectors == 0); + set_spf = (bpb.bpbBigFATsecs == 0); + set_spc = (bpb.bpbSecPerClust == 0); + saved_x = x; + + /* + * Attempt to align the root directory if o.align is set. This is done + * by padding with reserved blocks. Note that this can cause other + * factors to change, which can in turn change the alignment. + * This should take at most 2 iterations, as increasing the reserved + * amount may cause the FAT size to decrease by 1, requiring another + * bpbFATs reserved blocks. If bpbSecPerClust changes, it will + * be half of its previous size, and thus will not throw off alignment. + */ + do { + x = saved_x; + if (set_res) + bpb.bpbResSectors = ((fat == 32) ? + MAX(x, MAX(16384 / bpb.bpbBytesPerSec, 4)) : x) + extra_res; + else if (bpb.bpbResSectors < x) { + warnx("too few reserved sectors (need %d have %d)", x, + bpb.bpbResSectors); + goto done; + } + if (fat != 32 && !bpb.bpbRootDirEnts) + bpb.bpbRootDirEnts = DEFRDE; + rds = howmany(bpb.bpbRootDirEnts, + bpb.bpbBytesPerSec / sizeof(struct de)); + if (set_spc) { + for (bpb.bpbSecPerClust = howmany(fat == 16 ? DEFBLK16 : + DEFBLK, bpb.bpbBytesPerSec); + bpb.bpbSecPerClust < MAXSPC && (bpb.bpbResSectors + + howmany((RESFTE + maxcls(fat)) * (fat / BPN), + bpb.bpbBytesPerSec * NPB) * bpb.bpbFATs + + rds + + (u_int64_t) (maxcls(fat) + 1) * bpb.bpbSecPerClust) <= + bpb.bpbHugeSectors; + bpb.bpbSecPerClust <<= 1) + continue; + + } + if (fat != 32 && bpb.bpbBigFATsecs > MAXU16) { + warnx("too many sectors/FAT for FAT12/16"); + goto done; + } + x1 = bpb.bpbResSectors + rds; + x = bpb.bpbBigFATsecs ? bpb.bpbBigFATsecs : 1; + if (x1 + (u_int64_t)x * bpb.bpbFATs > bpb.bpbHugeSectors) { + warnx("meta data exceeds file system size"); + goto done; + } + x1 += x * bpb.bpbFATs; + x = (u_int64_t)(bpb.bpbHugeSectors - x1) * bpb.bpbBytesPerSec * NPB / + (bpb.bpbSecPerClust * bpb.bpbBytesPerSec * NPB + + fat / BPN * bpb.bpbFATs); + x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN), + bpb.bpbBytesPerSec * NPB); + if (set_spf) { + if (bpb.bpbBigFATsecs == 0) + bpb.bpbBigFATsecs = x2; + x1 += (bpb.bpbBigFATsecs - 1) * bpb.bpbFATs; + } + if (set_res) { + /* attempt to align root directory */ + alignment = (bpb.bpbResSectors + bpb.bpbBigFATsecs * bpb.bpbFATs) % + bpb.bpbSecPerClust; + if (o.align) + extra_res += bpb.bpbSecPerClust - alignment; + } + attempts++; + } while (o.align && alignment != 0 && attempts < 2); + if (alignment != 0) + warnx("warning: Alignment failed."); + cls = (bpb.bpbHugeSectors - x1) / bpb.bpbSecPerClust; x = (u_int64_t)bpb.bpbBigFATsecs * bpb.bpbBytesPerSec * NPB / (fat / BPN) - RESFTE; Index: sbin/newfs_msdos/newfs_msdos.8 =================================================================== --- sbin/newfs_msdos/newfs_msdos.8 +++ sbin/newfs_msdos/newfs_msdos.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 16, 2017 +.Dd June 6, 2018 .Dt NEWFS_MSDOS 8 .Os .Sh NAME @@ -35,6 +35,7 @@ .Nm .Op Fl N .Op Fl @ Ar offset +.Op Fl A .Op Fl B Ar boot .Op Fl C Ar create-size .Op Fl F Ar FAT-type @@ -91,6 +92,8 @@ A suffix s, k, m, g (lower or upper case) appended to the offset specifies that the number is in sectors, kilobytes, megabytes or gigabytes, respectively. +.It Fl A +Attempt to cluster align root directory. .It Fl B Ar boot Get bootstrap from file. .It Fl C Ar create-size Index: sbin/newfs_msdos/newfs_msdos.c =================================================================== --- sbin/newfs_msdos/newfs_msdos.c +++ sbin/newfs_msdos/newfs_msdos.c @@ -76,7 +76,7 @@ int main(int argc, char *argv[]) { - static const char opts[] = "@:NB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:T:u:"; + static const char opts[] = "@:NAB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:T:u:"; struct msdos_options o; const char *fname, *dtype; char buf[MAXPATHLEN]; @@ -92,6 +92,9 @@ case 'N': o.no_create = 1; break; + case 'A': + o.align = true; + break; case 'B': o.bootstrap = optarg; break; @@ -175,6 +178,12 @@ argv += optind; if (argc < 1 || argc > 2) usage(); + if (o.align) { + if (o.hidden_sectors_set) + errx(1, "align (-A) is incompatible with -r"); + if (o.no_create) + errx(1, "align (-A) is incompatible with -N"); + } fname = *argv++; if (!o.create_size && !strchr(fname, '/')) { snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);