Skip to content

Commit e6fcaed

Browse files
committed
Add lazy mode for fat32 to speed up writes
For example, it reduces time to create ~5GB file system from 7m40s to 1m30s on my laptop.
1 parent 6ad9db3 commit e6fcaed

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

filesystem/fat32/fat32.go

+35
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ type FileSystem struct {
6060
size int64
6161
start int64
6262
file util.File
63+
lazy bool
6364
}
6465

6566
// Equal compare if two filesystems are equal
@@ -433,6 +434,10 @@ func (fs *FileSystem) writeBootSector() error {
433434
}
434435

435436
func (fs *FileSystem) writeFsis() error {
437+
if fs.lazy {
438+
return nil
439+
}
440+
436441
fsInformationSector := fs.bootSector.biosParameterBlock.fsInformationSector
437442
backupBootSector := fs.bootSector.biosParameterBlock.backupBootSector
438443
fsisPrimary := int64(fsInformationSector * uint16(SectorSize512))
@@ -453,6 +458,10 @@ func (fs *FileSystem) writeFsis() error {
453458
}
454459

455460
func (fs *FileSystem) writeFat() error {
461+
if fs.lazy {
462+
return nil
463+
}
464+
456465
reservedSectors := fs.bootSector.biosParameterBlock.dos331BPB.dos20BPB.reservedSectors
457466
fatPrimaryStart := uint64(reservedSectors) * uint64(SectorSize512)
458467
fatSecondaryStart := fatPrimaryStart + uint64(fs.table.size)
@@ -688,6 +697,32 @@ func (fs *FileSystem) SetLabel(volumeLabel string) error {
688697
return nil
689698
}
690699

700+
// SetLazy sets the lazy flag for the filesystem. If lazy is true, then the filesystem will not write FAT tables and
701+
// other metadata to the disk when creating/writing files or directories. After all changes to file system are done
702+
// Commit() must be called to write the changes to the disk.
703+
func (fs *FileSystem) SetLazy(lazy bool) {
704+
fs.lazy = lazy
705+
}
706+
707+
// Commit writes the FAT tables and other metadata to the disk. This is only necessary if lazy is set to true.
708+
func (fs *FileSystem) Commit() error {
709+
curr := fs.lazy
710+
fs.lazy = false
711+
defer func() {
712+
fs.lazy = curr
713+
}()
714+
715+
if err := fs.writeFsis(); err != nil {
716+
return fmt.Errorf("failed to write the file system information sector: %w", err)
717+
}
718+
719+
if err := fs.writeFat(); err != nil {
720+
return fmt.Errorf("failed to write the file allocation table: %w", err)
721+
}
722+
723+
return nil
724+
}
725+
691726
// read directory entries for a given cluster
692727
func (fs *FileSystem) getClusterList(firstCluster uint32) ([]uint32, error) {
693728
// first, get the chain of clusters

filesystem/fat32/fat32_test.go

+15
Original file line numberDiff line numberDiff line change
@@ -1085,6 +1085,16 @@ func testMkFile(fs filesystem.FileSystem, p string, size int) error {
10851085
}
10861086

10871087
func TestCreateFileTree(t *testing.T) {
1088+
testCreateFileTree(t, false)
1089+
}
1090+
1091+
func TestCreateFileTreeLazy(t *testing.T) {
1092+
testCreateFileTree(t, true)
1093+
}
1094+
1095+
func testCreateFileTree(t *testing.T, lazy bool) {
1096+
t.Helper()
1097+
10881098
filename := "fat32_test"
10891099
tmpDir := t.TempDir()
10901100
tmpImgPath := filepath.Join(tmpDir, filename)
@@ -1104,6 +1114,7 @@ func TestCreateFileTree(t *testing.T) {
11041114
if err != nil {
11051115
t.Fatalf("error creating filesystem: %v", err)
11061116
}
1117+
fs.(*fat32.FileSystem).SetLazy(lazy)
11071118

11081119
if err := fs.Mkdir("/A"); err != nil {
11091120
t.Errorf("Error making dir /A in root: %v", err)
@@ -1150,4 +1161,8 @@ func TestCreateFileTree(t *testing.T) {
11501161
if err := testMkFile(fs, file, gb); err != nil {
11511162
t.Errorf("Error making gigfile1 %s: %v", file, err)
11521163
}
1164+
1165+
if err := fs.(*fat32.FileSystem).Commit(); err != nil {
1166+
t.Errorf("Error committing filesystem: %v", err)
1167+
}
11531168
}

0 commit comments

Comments
 (0)