Gather writes to larger chunks (MAXPHYS) instead of issuing them in

sectors.

On my SanDisk Cruzer Blade 16GB USB stick this made formatting much faster:

x before
+ after
+--------------------------------------------------------------------------+
|+                                                                         |
|+                                                                      x  |
|+                                                                      x x|
|A                                                                      MA||
+--------------------------------------------------------------------------+
    N           Min           Max        Median           Avg        Stddev
x   3         15.89         16.38            16         16.09     0.2570992
+   3          0.32          0.37          0.35    0.34666667   0.025166115
Difference at 95.0% confidence
	-15.7433 +/- 0.414029
	-97.8455% +/- 0.25668%
	(Student's t, pooled s = 0.182665)

Reviewed by:	emaste
MFC after:	2 weeks
Differential Revision:	https://reviews.freebsd.org/D24508
This commit is contained in:
Xin LI 2020-07-04 18:37:04 +00:00
parent 6ef8f9d28a
commit 33c2d974d0

View File

@ -64,6 +64,7 @@ static const char rcsid[] =
#define DOSMAGIC 0xaa55 /* DOS magic number */ #define DOSMAGIC 0xaa55 /* DOS magic number */
#define MINBPS 512 /* minimum bytes per sector */ #define MINBPS 512 /* minimum bytes per sector */
#define MAXBPS 4096 /* maximum bytes per sector */
#define MAXSPC 128 /* maximum sectors per cluster */ #define MAXSPC 128 /* maximum sectors per cluster */
#define MAXNFT 16 /* maximum number of FATs */ #define MAXNFT 16 /* maximum number of FATs */
#define DEFBLK 4096 /* default block size */ #define DEFBLK 4096 /* default block size */
@ -77,6 +78,25 @@ static const char rcsid[] =
#define MAXCLS16 0xfff4U /* maximum FAT16 clusters */ #define MAXCLS16 0xfff4U /* maximum FAT16 clusters */
#define MAXCLS32 0xffffff4U /* maximum FAT32 clusters */ #define MAXCLS32 0xffffff4U /* maximum FAT32 clusters */
#ifndef CTASSERT
#define CTASSERT(x) _CTASSERT(x, __LINE__)
#define _CTASSERT(x, y) __CTASSERT(x, y)
#define __CTASSERT(x, y) typedef char __assert_ ## y [(x) ? 1 : -1]
#endif
/*
* For better performance, we want to write larger chunks instead of
* individual sectors (the size can only be 512, 1024, 2048 or 4096
* bytes). Assert that MAXPHYS can always hold an integer number of
* sectors by asserting that both are power of two numbers and the
* MAXPHYS is greater than MAXBPS.
*/
CTASSERT(powerof2(MAXPHYS));
CTASSERT(powerof2(MAXBPS));
CTASSERT(MAXPHYS > MAXBPS);
const static ssize_t chunksize = MAXPHYS;
#define mincls(fat) ((fat) == 12 ? MINCLS12 : \ #define mincls(fat) ((fat) == 12 ? MINCLS12 : \
(fat) == 16 ? MINCLS16 : \ (fat) == 16 ? MINCLS16 : \
MINCLS32) MINCLS32)
@ -243,6 +263,7 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op)
struct bsx *bsx; struct bsx *bsx;
struct de *de; struct de *de;
u_int8_t *img; u_int8_t *img;
u_int8_t *physbuf, *physbuf_end;
const char *bname; const char *bname;
ssize_t n; ssize_t n;
time_t now; time_t now;
@ -252,7 +273,7 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op)
int fd, fd1, rv; int fd, fd1, rv;
struct msdos_options o = *op; struct msdos_options o = *op;
img = NULL; physbuf = NULL;
rv = -1; rv = -1;
fd = fd1 = -1; fd = fd1 = -1;
@ -343,13 +364,11 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op)
bpb.bpbSecPerClust = 64; /* otherwise 32k */ bpb.bpbSecPerClust = 64; /* otherwise 32k */
} }
} }
if (!powerof2(bpb.bpbBytesPerSec)) { if (bpb.bpbBytesPerSec < MINBPS ||
warnx("bytes/sector (%u) is not a power of 2", bpb.bpbBytesPerSec); bpb.bpbBytesPerSec > MAXBPS ||
goto done; !powerof2(bpb.bpbBytesPerSec)) {
} warnx("Invalid bytes/sector (%u): must be 512, 1024, 2048 or 4096",
if (bpb.bpbBytesPerSec < MINBPS) { bpb.bpbBytesPerSec);
warnx("bytes/sector (%u) is too small; minimum is %u",
bpb.bpbBytesPerSec, MINBPS);
goto done; goto done;
} }
@ -621,11 +640,14 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op)
tm = localtime(&now); tm = localtime(&now);
} }
physbuf = malloc(chunksize);
if (!(img = malloc(bpb.bpbBytesPerSec))) { if (physbuf == NULL) {
warn(NULL); warn(NULL);
goto done; goto done;
} }
physbuf_end = physbuf + chunksize;
img = physbuf;
dir = bpb.bpbResSectors + (bpb.bpbFATsecs ? bpb.bpbFATsecs : dir = bpb.bpbResSectors + (bpb.bpbFATsecs ? bpb.bpbFATsecs :
bpb.bpbBigFATsecs) * bpb.bpbFATs; bpb.bpbBigFATsecs) * bpb.bpbFATs;
memset(&si_sa, 0, sizeof(si_sa)); memset(&si_sa, 0, sizeof(si_sa));
@ -750,19 +772,37 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op)
(u_int)tm->tm_mday; (u_int)tm->tm_mday;
mk2(de->deMDate, x); mk2(de->deMDate, x);
} }
if ((n = write(fd, img, bpb.bpbBytesPerSec)) == -1) { /*
warn("%s", fname); * Issue a write of chunksize once we have collected
goto done; * enough sectors.
} */
if ((unsigned)n != bpb.bpbBytesPerSec) { img += bpb.bpbBytesPerSec;
warnx("%s: can't write sector %u", fname, lsn); if (img >= physbuf_end) {
goto done; n = write(fd, physbuf, chunksize);
if (n != chunksize) {
warnx("%s: can't write sector %u", fname, lsn);
goto done;
}
img = physbuf;
} }
} }
/*
* Write remaining sectors, if the last write didn't end
* up filling a whole chunk.
*/
if (img != physbuf) {
ssize_t tailsize = img - physbuf;
n = write(fd, physbuf, tailsize);
if (n != tailsize) {
warnx("%s: can't write sector %u", fname, lsn);
goto done;
}
}
} }
rv = 0; rv = 0;
done: done:
free(img); free(physbuf);
if (fd != -1) if (fd != -1)
close(fd); close(fd);
if (fd1 != -1) if (fd1 != -1)