Added option to cluster-align the start of the root directory.

Obtained from:	Android
Obtained from:	052f275621
Obtained from:	8218b6aae9
MFC after:	1 month
Differential Revision:	https://reviews.freebsd.org/D15672
This commit is contained in:
delphij 2018-06-15 06:03:40 +00:00
parent 982cd953f3
commit 284893ba03
4 changed files with 93 additions and 47 deletions

View File

@ -242,6 +242,8 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op)
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 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op)
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 to cluster 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 (o.align && alignment != 0)
warnx("warning: Alignment failed.");
cls = (bpb.bpbHugeSectors - x1) / bpb.bpbSecPerClust;
x = (u_int64_t)bpb.bpbBigFATsecs * bpb.bpbBytesPerSec * NPB / (fat / BPN) -
RESFTE;

View File

@ -34,6 +34,7 @@
#include <stdbool.h>
#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 @@ AOPT('u', uint16_t, sectors_per_track, 1, "Sectors per track")
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;

View File

@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd May 16, 2017
.Dd June 14, 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 @@ Build the filesystem at the specified offset in bytes in the device or file.
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, useful for SD card.
.It Fl B Ar boot
Get bootstrap from file.
.It Fl C Ar create-size

View File

@ -76,7 +76,7 @@ get_tstamp(const char *b)
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 @@ main(int argc, char *argv[])
case 'N':
o.no_create = 1;
break;
case 'A':
o.align = true;
break;
case 'B':
o.bootstrap = optarg;
break;
@ -175,6 +178,10 @@ main(int argc, char *argv[])
argv += optind;
if (argc < 1 || argc > 2)
usage();
if (o.align) {
if (o.hidden_sectors_set)
errx(1, "align (-A) is incompatible with -r");
}
fname = *argv++;
if (!o.create_size && !strchr(fname, '/')) {
snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);