Skip to content
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

Error creating EXT4 filesystem #274

Open
mattmoor opened this issue Dec 26, 2024 · 5 comments
Open

Error creating EXT4 filesystem #274

mattmoor opened this issue Dec 26, 2024 · 5 comments

Comments

@mattmoor
Copy link

I am playing around with trying to construct an extremely simple and contrived disk with an EFI System Partition (FAT32) and a root partition (EXT4).

In the example below, I consistently see the following error:

# rm disk.raw; go run main.go 
2024/12/26 09:00:43 failed to create filesystem: wrote 0 bytes of GDT for block 0 to disk instead of expected 664403968
panic: failed to create filesystem: wrote 0 bytes of GDT for block 0 to disk instead of expected 664403968

If I change the root partition to FAT32 things work fine, but it's FAT32... 😉

Here's the full example I'm playing with:

package main

import (
	"log"

	diskfs "github.com/diskfs/go-diskfs"
	diskpkg "github.com/diskfs/go-diskfs/disk"
	"github.com/diskfs/go-diskfs/filesystem"
	"github.com/diskfs/go-diskfs/partition/gpt"
)

func main() {
	const (
		espSize  uint64 = 100 * 1024 * 1024       // 100 MB
		diskSize uint64 = 10 * 1024 * 1024 * 1024 // 10 GB

		padding uint64 = 1024 * 1024 // 1 MB
		blkSize uint64 = uint64(diskfs.SectorSize512)

		gptGUID  = "00000000-0000-0000-0000-000000000000"
		espGUID  = "11111111-1111-1111-1111-111111111111"
		rootGUID = "22222222-2222-2222-2222-222222222222"
	)

	disk, err := diskfs.Create("disk.raw", int64(diskSize), diskfs.SectorSize512)
	if err != nil {
		log.Panicf("failed to create disk: %v", err)
	}

	if err := disk.Partition(&gpt.Table{
		GUID:          gptGUID,
		ProtectiveMBR: true,
		Partitions: []*gpt.Partition{{
			Name:  "esp",
			Type:  gpt.EFISystemPartition,
			GUID:  espGUID,
			Start: padding / blkSize,
			End:   (padding+espSize)/blkSize - 1,
			Size:  espSize, // (End - Start) * blkSize
		}, {
			Name:  "root",
			Type:  gpt.LinuxFilesystem,
			GUID:  rootGUID,
			Start: (padding + espSize) / blkSize,
			End:   (diskSize-padding)/blkSize - 1,
			Size:  diskSize - espSize - 2*padding, // (End - Start) * blkSize
		}},
	}); err != nil {
		log.Panicf("failed to partition disk: %v", err)
	}

	if _, err := disk.CreateFilesystem(diskpkg.FilesystemSpec{
		Partition:   1,
		FSType:      filesystem.TypeFat32,
		VolumeLabel: "esp",
	}); err != nil {
		log.Panicf("failed to create filesystem: %v", err)
	}

	if _, err := disk.CreateFilesystem(diskpkg.FilesystemSpec{
		Partition:   2,
		FSType:      filesystem.TypeExt4,
		VolumeLabel: "root",
	}); err != nil {
		log.Panicf("failed to create filesystem: %v", err)
	}
}

Note that some of the values were chosen for parity with a manually crafted example I was playing with using fdisk and friends.

@deitch
Copy link
Collaborator

deitch commented Dec 26, 2024

Failure appears to be here when writing the group descriptor table for superblock backup 0 (or any other). The reason is that the data for the GDT is an empty slice, i.e. 0 bytes.

It should be set [here[(https://github.com/diskfs/go-diskfs/blob/master/filesystem/ext4/ext4.go#L548):

	g := gdt.toBytes(gdtChecksumType, sb.checksumSeed)

With the descriptor table set a few lines above:

	gdt := groupDescriptors{}

Why is there nothing in it? I do not know. I looked at the original commit and it has it, so it isn't like it got removed at some point.

Is it possible the GDT never was created properly? I guess it is. I wonder if we look back on the notes we would find some "TODO" that says, "don't forget to complete creating the Group Descriptor Tables!"

Interested in trying your hand at it?

@mattmoor
Copy link
Author

Debugging this, it seems like the gdt is empty here:

gdt := groupDescriptors{}

toBytes basically just walks the list of descriptors in the gdt here:

// toBytes returns groupDescriptors ready to be written to disk
func (gds *groupDescriptors) toBytes(checksumType gdtChecksumType, hashSeed uint32) []byte {
b := make([]byte, 0, 10*groupDescriptorSize)
for _, gd := range gds.descriptors {
b2 := gd.toBytes(checksumType, hashSeed)
b = append(b, b2...)
}
return b
}

However, since this is empty, toBytes does basically nothing?

@deitch
Copy link
Collaborator

deitch commented Dec 26, 2024

Yeah, pretty much. It needs to use correct logic to fill in the desired group descriptors. Once those are there, it should do the right thing with them.

@mattmoor
Copy link
Author

Yeah, I have no clue what goes into the descriptors, or what information they should be based on.

I am guessing that there should be numblocks of them, based on this:

gdtSize := int64(gdSize) * numblocks

... and that the entries will maybe be fairly formulaic based on this:

blocksize := uint32(sectorsPerBlock) * sectorsize32
// how many whole blocks is that?
numblocks := size / int64(blocksize)

The only place I see creating a groupDescriptor currently is here, which isn't super interecting to crib from:

func groupDescriptorFromBytes(b []byte, gdSize uint16, number int, checksumType gdtChecksumType, hashSeed uint32) (*groupDescriptor, error) {

@deitch
Copy link
Collaborator

deitch commented Dec 26, 2024

If it were a quick and easy job, I would have done it. 😃

Check out the file ext4.md, which links to much of it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants