Skip to content

Add lazy mode for fat32 to speed up writes #261

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions filesystem/fat32/fat32.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ type FileSystem struct {
size int64
start int64
file util.File
lazy bool
}

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

func (fs *FileSystem) writeFsis() error {
if fs.lazy {
return nil
}

fsInformationSector := fs.bootSector.biosParameterBlock.fsInformationSector
backupBootSector := fs.bootSector.biosParameterBlock.backupBootSector
fsisPrimary := int64(fsInformationSector * uint16(SectorSize512))
Expand All @@ -453,6 +458,10 @@ func (fs *FileSystem) writeFsis() error {
}

func (fs *FileSystem) writeFat() error {
if fs.lazy {
return nil
}

reservedSectors := fs.bootSector.biosParameterBlock.dos331BPB.dos20BPB.reservedSectors
fatPrimaryStart := uint64(reservedSectors) * uint64(SectorSize512)
fatSecondaryStart := fatPrimaryStart + uint64(fs.table.size)
Expand Down Expand Up @@ -688,6 +697,32 @@ func (fs *FileSystem) SetLabel(volumeLabel string) error {
return nil
}

// SetLazy sets the lazy flag for the filesystem. If lazy is true, then the filesystem will not write FAT tables and
// other metadata to the disk when creating/writing files or directories. After all changes to file system are done
// Commit() must be called to write the changes to the disk.
func (fs *FileSystem) SetLazy(lazy bool) {
fs.lazy = lazy
}

// Commit writes the FAT tables and other metadata to the disk. This is only necessary if lazy is set to true.
func (fs *FileSystem) Commit() error {
curr := fs.lazy
fs.lazy = false
defer func() {
fs.lazy = curr
}()

if err := fs.writeFsis(); err != nil {
return fmt.Errorf("failed to write the file system information sector: %w", err)
}

if err := fs.writeFat(); err != nil {
return fmt.Errorf("failed to write the file allocation table: %w", err)
}

return nil
}

// read directory entries for a given cluster
func (fs *FileSystem) getClusterList(firstCluster uint32) ([]uint32, error) {
// first, get the chain of clusters
Expand Down
15 changes: 15 additions & 0 deletions filesystem/fat32/fat32_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,16 @@ func testMkFile(fs filesystem.FileSystem, p string, size int) error {
}

func TestCreateFileTree(t *testing.T) {
testCreateFileTree(t, false)
}

func TestCreateFileTreeLazy(t *testing.T) {
testCreateFileTree(t, true)
}

func testCreateFileTree(t *testing.T, lazy bool) {
t.Helper()

filename := "fat32_test"
tmpDir := t.TempDir()
tmpImgPath := filepath.Join(tmpDir, filename)
Expand All @@ -1104,6 +1114,7 @@ func TestCreateFileTree(t *testing.T) {
if err != nil {
t.Fatalf("error creating filesystem: %v", err)
}
fs.(*fat32.FileSystem).SetLazy(lazy)

if err := fs.Mkdir("/A"); err != nil {
t.Errorf("Error making dir /A in root: %v", err)
Expand Down Expand Up @@ -1150,4 +1161,8 @@ func TestCreateFileTree(t *testing.T) {
if err := testMkFile(fs, file, gb); err != nil {
t.Errorf("Error making gigfile1 %s: %v", file, err)
}

if err := fs.(*fat32.FileSystem).Commit(); err != nil {
t.Errorf("Error committing filesystem: %v", err)
}
}
Loading