diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2022-06-05 23:57:05 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2022-06-05 23:57:05 -0600 |
commit | 6a5b5b59345c6e57ba496c7d517902c339d2f0b8 (patch) | |
tree | e3428175ffd07791fad1406401fe1856e95e8555 | |
parent | 5c02065e573ce42d9d83099b524566878ba61bdb (diff) |
wip gather stripes
-rw-r--r-- | cmd/btrfs-fsck/main.go | 71 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/item_chunk.go | 16 | ||||
-rw-r--r-- | pkg/btrfs/io2_fs.go | 4 | ||||
-rw-r--r-- | pkg/btrfsmisc/print_tree.go | 6 |
4 files changed, 85 insertions, 12 deletions
diff --git a/cmd/btrfs-fsck/main.go b/cmd/btrfs-fsck/main.go index 97b1571..2e47588 100644 --- a/cmd/btrfs-fsck/main.go +++ b/cmd/btrfs-fsck/main.go @@ -70,8 +70,14 @@ func Main(imgfilename string) (err error) { fmt.Printf("Pass 1: ... walk chunk tree: error: %v\n", err) } + type reconstructedStripe struct { + Size uint64 + Addr btrfs.QualifiedPhysicalAddr + } + reconstructedChunks := make(map[btrfs.LogicalAddr][]reconstructedStripe) for _, dev := range fs.Devices { fmt.Printf("Pass 1: ... dev[%q] scanning for nodes\n", dev.Name()) + superblock, _ := dev.Superblock() foundNodes := make(map[btrfs.LogicalAddr][]btrfs.PhysicalAddr) var lostAndFoundChunks []btrfs.SysChunk if err := btrfsmisc.ScanForNodes(dev, superblock.Data, func(nodeRef *util.Ref[btrfs.PhysicalAddr, btrfs.Node], err error) { @@ -150,8 +156,71 @@ func Main(imgfilename string) (err error) { }) } } - fmt.Printf("Pass 1: ... dev[%q] reconstructed stripes: %#v\n", dev.Name(), stripes) + //fmt.Printf("Pass 1: ... dev[%q] reconstructed stripes: %#v\n", dev.Name(), stripes) + for _, stripe := range stripes { + reconstructedChunks[stripe.LAddr] = append(reconstructedChunks[stripe.LAddr], reconstructedStripe{ + Size: stripe.Size, + Addr: btrfs.QualifiedPhysicalAddr{ + Dev: superblock.Data.DevItem.DevUUID, + Addr: stripe.PAddr, + }, + }) + } } + // FIXME(lukeshu): OK, so this just assumes that all the + // reconstructed stripes fit in one node, and that we can just + // store that node at the root node of the chunk tree. This + // isn't true in general, but it's true of my particular + // filesystem. + /* + reconstructedNode := &util.Ref[btrfs.LogicalAddr, btrfs.Node]{ + File: fs, + Addr: superblock.Data.ChunkTree, + Data: btrfs.Node{ + Size: superblock.Data.NodeSize, + Head: btrfs.NodeHeader{ + MetadataUUID: superblock.Data.EffectiveMetadataUUID(), + Addr: superblock.Data.ChunkTree, + Flags: btrfs.NodeWritten, + //BackrefRef: ???, + //ChunkTreeUUID: ???, + Generation: superblock.Data.ChunkRootGeneration, + Owner: btrfs.CHUNK_TREE_OBJECTID, + Level: 0, + }, + }, + } + itemOff := superblock.Data.NodeSize - binstruct.StaticSize(btrfs.ItemHeader{}) + for laddr, stripes := range reconstructedChunks { + stripeSize := stripes[0].Size + for i, stripe := range stripes { + if stripes.Size != stripeSize { + panic("mismatch") + } + } + itemSize := binstruct.StaticSize(btrfsitem.ChunkHeader) + (len(stripes) * binstruct.StaticSize(btrfsitem.ChunkStripe)) + itemOff -= itemSize + reconstructedNode.Data.BodyLeaf = append(reconstructedNode.Data.BodyLeaf, btrfs.Item{ + Head: btrfs.ItemHeader{ + Key: TODO, + DataOffset: itemOff, + DataSize: itemSize, + }, + Body: btrfsitem.Chunk{ + Head: btrfsitem.ChunkHeader{ + Size: stripeSize, + Owner: 2, + StripeLen: + Stripes: stripes, + }, + }) + } + reconstructedNode.Data.Head.NumItems = len(reconstructedNode.Data.BodyLeaf) + reconstructedNode.Data.Head.Checksum, err = reconstructedNode.Data.CalculateChecksum() + if err != nil { + fmt.Printf("Pass 1: ... new node checksum: error: %v\n", err) + } + */ fmt.Printf("\nPass 2: ?????????????????????????\n") //////////////////////////////////////// /* diff --git a/pkg/btrfs/btrfsitem/item_chunk.go b/pkg/btrfs/btrfsitem/item_chunk.go index 4389a46..8ffc83b 100644 --- a/pkg/btrfs/btrfsitem/item_chunk.go +++ b/pkg/btrfs/btrfsitem/item_chunk.go @@ -7,8 +7,13 @@ import ( "lukeshu.com/btrfs-tools/pkg/btrfs/internal" ) +// Maps logical address to physical. type Chunk struct { // CHUNK_ITEM=228 - // Maps logical address to physical. + Head ChunkHeader + Stripes []ChunkStripe +} + +type ChunkHeader struct { Size uint64 `bin:"off=0x0, siz=0x8"` // size of chunk (bytes) Owner internal.ObjID `bin:"off=0x8, siz=0x8"` // root referencing this chunk (2) StripeLen uint64 `bin:"off=0x10, siz=0x8"` // stripe length @@ -19,7 +24,6 @@ type Chunk struct { // CHUNK_ITEM=228 NumStripes uint16 `bin:"off=0x2c, siz=0x2"` // number of stripes SubStripes uint16 `bin:"off=0x2e, siz=0x2"` // sub stripes binstruct.End `bin:"off=0x30"` - Stripes []ChunkStripe `bin:"-"` } type ChunkStripe struct { @@ -30,12 +34,12 @@ type ChunkStripe struct { } func (chunk *Chunk) UnmarshalBinary(dat []byte) (int, error) { - n, err := binstruct.UnmarshalWithoutInterface(dat, chunk) + n, err := binstruct.Unmarshal(dat, &chunk.Head) if err != nil { return n, err } chunk.Stripes = nil - for i := 0; i < int(chunk.NumStripes); i++ { + for i := 0; i < int(chunk.Head.NumStripes); i++ { var stripe ChunkStripe _n, err := binstruct.Unmarshal(dat[n:], &stripe) n += _n @@ -48,8 +52,8 @@ func (chunk *Chunk) UnmarshalBinary(dat []byte) (int, error) { } func (chunk Chunk) MarshalBinary() ([]byte, error) { - chunk.NumStripes = uint16(len(chunk.Stripes)) - ret, err := binstruct.MarshalWithoutInterface(chunk) + chunk.Head.NumStripes = uint16(len(chunk.Stripes)) + ret, err := binstruct.Marshal(chunk.Head) if err != nil { return ret, err } diff --git a/pkg/btrfs/io2_fs.go b/pkg/btrfs/io2_fs.go index ca67a9c..035019c 100644 --- a/pkg/btrfs/io2_fs.go +++ b/pkg/btrfs/io2_fs.go @@ -175,9 +175,9 @@ func (fs *FS) Resolve(laddr LogicalAddr) (paddrs map[QualifiedPhysicalAddr]struc maxlen = math.MaxUint64 for _, chunk := range fs.chunks { - if chunk.Key.Offset <= uint64(laddr) && uint64(laddr) < chunk.Key.Offset+uint64(chunk.Chunk.Size) { + if chunk.Key.Offset <= uint64(laddr) && uint64(laddr) < chunk.Key.Offset+uint64(chunk.Chunk.Head.Size) { offsetWithinChunk := uint64(laddr) - chunk.Key.Offset - maxlen = util.Min(maxlen, chunk.Chunk.Size-offsetWithinChunk) + maxlen = util.Min(maxlen, chunk.Chunk.Head.Size-offsetWithinChunk) for _, stripe := range chunk.Chunk.Stripes { paddrs[QualifiedPhysicalAddr{ Dev: stripe.DeviceUUID, diff --git a/pkg/btrfsmisc/print_tree.go b/pkg/btrfsmisc/print_tree.go index a771b65..3211d1d 100644 --- a/pkg/btrfsmisc/print_tree.go +++ b/pkg/btrfsmisc/print_tree.go @@ -159,11 +159,11 @@ func PrintTree(fs *btrfs.FS, root btrfs.LogicalAddr) error { fmt.Printf("\t\tfree space bitmap\n") case btrfsitem.Chunk: fmt.Printf("\t\tlength %d owner %d stripe_len %d type %v\n", - body.Size, body.Owner, body.StripeLen, body.Type) + body.Head.Size, body.Head.Owner, body.Head.StripeLen, body.Head.Type) fmt.Printf("\t\tio_align %d io_width %d sector_size %d\n", - body.IOOptimalAlign, body.IOOptimalWidth, body.IOMinSize) + body.Head.IOOptimalAlign, body.Head.IOOptimalWidth, body.Head.IOMinSize) fmt.Printf("\t\tnum_stripes %d sub_stripes %d\n", - body.NumStripes, body.SubStripes) + body.Head.NumStripes, body.Head.SubStripes) for i, stripe := range body.Stripes { fmt.Printf("\t\t\tstripe %d devid %d offset %d\n", i, stripe.DeviceID, stripe.Offset) |