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:
Xin LI 2018-06-15 06:03:40 +00:00
parent 031f92f512
commit 0531ab7253
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=335189
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; ssize_t n;
time_t now; time_t now;
u_int fat, bss, rds, cls, dir, lsn, x, x1, x2; 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; int fd, fd1, rv;
struct msdos_options o = *op; struct msdos_options o = *op;
@ -486,9 +488,28 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op)
if (bpb.bpbBackup != MAXU16 && x <= bpb.bpbBackup) if (bpb.bpbBackup != MAXU16 && x <= bpb.bpbBackup)
x = bpb.bpbBackup + 1; x = bpb.bpbBackup + 1;
} }
if (!bpb.bpbResSectors)
bpb.bpbResSectors = fat == 32 ? extra_res = 0;
MAX(x, MAX(16384 / bpb.bpbBytesPerSec, 4)) : x; 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) { else if (bpb.bpbResSectors < x) {
warnx("too few reserved sectors (need %d have %d)", x, warnx("too few reserved sectors (need %d have %d)", x,
bpb.bpbResSectors); bpb.bpbResSectors);
@ -496,20 +517,21 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op)
} }
if (fat != 32 && !bpb.bpbRootDirEnts) if (fat != 32 && !bpb.bpbRootDirEnts)
bpb.bpbRootDirEnts = DEFRDE; bpb.bpbRootDirEnts = DEFRDE;
rds = howmany(bpb.bpbRootDirEnts, bpb.bpbBytesPerSec / sizeof(struct de)); rds = howmany(bpb.bpbRootDirEnts,
if (!bpb.bpbSecPerClust) bpb.bpbBytesPerSec / sizeof(struct de));
if (set_spc) {
for (bpb.bpbSecPerClust = howmany(fat == 16 ? DEFBLK16 : for (bpb.bpbSecPerClust = howmany(fat == 16 ? DEFBLK16 :
DEFBLK, bpb.bpbBytesPerSec); DEFBLK, bpb.bpbBytesPerSec);
bpb.bpbSecPerClust < MAXSPC && bpb.bpbSecPerClust < MAXSPC && (bpb.bpbResSectors +
bpb.bpbResSectors +
howmany((RESFTE + maxcls(fat)) * (fat / BPN), howmany((RESFTE + maxcls(fat)) * (fat / BPN),
bpb.bpbBytesPerSec * NPB) * bpb.bpbBytesPerSec * NPB) * bpb.bpbFATs +
bpb.bpbFATs +
rds + rds +
(u_int64_t) (maxcls(fat) + 1) * (u_int64_t) (maxcls(fat) + 1) * bpb.bpbSecPerClust) <=
bpb.bpbSecPerClust <= bpb.bpbHugeSectors; bpb.bpbHugeSectors;
bpb.bpbSecPerClust <<= 1) bpb.bpbSecPerClust <<= 1)
continue; continue;
}
if (fat != 32 && bpb.bpbBigFATsecs > MAXU16) { if (fat != 32 && bpb.bpbBigFATsecs > MAXU16) {
warnx("too many sectors/FAT for FAT12/16"); warnx("too many sectors/FAT for FAT12/16");
goto done; goto done;
@ -522,14 +544,27 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op)
} }
x1 += x * bpb.bpbFATs; x1 += x * bpb.bpbFATs;
x = (u_int64_t)(bpb.bpbHugeSectors - x1) * bpb.bpbBytesPerSec * NPB / x = (u_int64_t)(bpb.bpbHugeSectors - x1) * bpb.bpbBytesPerSec * NPB /
(bpb.bpbSecPerClust * bpb.bpbBytesPerSec * NPB + fat / (bpb.bpbSecPerClust * bpb.bpbBytesPerSec * NPB +
BPN * bpb.bpbFATs); fat / BPN * bpb.bpbFATs);
x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN), x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN),
bpb.bpbBytesPerSec * NPB); bpb.bpbBytesPerSec * NPB);
if (!bpb.bpbBigFATsecs) { if (set_spf) {
if (bpb.bpbBigFATsecs == 0)
bpb.bpbBigFATsecs = x2; bpb.bpbBigFATsecs = x2;
x1 += (bpb.bpbBigFATsecs - 1) * bpb.bpbFATs; 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; cls = (bpb.bpbHugeSectors - x1) / bpb.bpbSecPerClust;
x = (u_int64_t)bpb.bpbBigFATsecs * bpb.bpbBytesPerSec * NPB / (fat / BPN) - x = (u_int64_t)bpb.bpbBigFATsecs * bpb.bpbBytesPerSec * NPB / (fat / BPN) -
RESFTE; RESFTE;

View File

@ -34,6 +34,7 @@
#include <stdbool.h> #include <stdbool.h>
#define ALLOPTS \ #define ALLOPTS \
AOPT('@', off_t, offset, 0, "Offset in device") \ 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('B', const char *, bootstrap, -1, "Bootstrap file") \
AOPT('C', off_t, create_size, 0, "Create file") \ AOPT('C', off_t, create_size, 0, "Create file") \
AOPT('F', uint8_t, fat_type, 12, "FAT type (12, 16, or 32)") \ AOPT('F', uint8_t, fat_type, 12, "FAT type (12, 16, or 32)") \

View File

@ -25,7 +25,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd May 16, 2017 .Dd June 14, 2018
.Dt NEWFS_MSDOS 8 .Dt NEWFS_MSDOS 8
.Os .Os
.Sh NAME .Sh NAME
@ -35,6 +35,7 @@
.Nm .Nm
.Op Fl N .Op Fl N
.Op Fl @ Ar offset .Op Fl @ Ar offset
.Op Fl A
.Op Fl B Ar boot .Op Fl B Ar boot
.Op Fl C Ar create-size .Op Fl C Ar create-size
.Op Fl F Ar FAT-type .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) A suffix s, k, m, g (lower or upper case)
appended to the offset specifies that the appended to the offset specifies that the
number is in sectors, kilobytes, megabytes or gigabytes, respectively. 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 .It Fl B Ar boot
Get bootstrap from file. Get bootstrap from file.
.It Fl C Ar create-size .It Fl C Ar create-size

View File

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