diff options
Diffstat (limited to 'cmd/btrfs-fsck/main.go')
-rw-r--r-- | cmd/btrfs-fsck/main.go | 230 |
1 files changed, 4 insertions, 226 deletions
diff --git a/cmd/btrfs-fsck/main.go b/cmd/btrfs-fsck/main.go index 1147acf..2c52627 100644 --- a/cmd/btrfs-fsck/main.go +++ b/cmd/btrfs-fsck/main.go @@ -3,13 +3,9 @@ package main import ( "fmt" "os" - "sort" - "lukeshu.com/btrfs-tools/pkg/binstruct" "lukeshu.com/btrfs-tools/pkg/btrfs" "lukeshu.com/btrfs-tools/pkg/btrfs/btrfsitem" - "lukeshu.com/btrfs-tools/pkg/btrfsmisc" - "lukeshu.com/btrfs-tools/pkg/util" ) func main() { @@ -41,232 +37,14 @@ func Main(imgfilename string) (err error) { }, } - fmt.Printf("\nPass 0: superblocks...\n") /////////////////////////////////////////////////// - - superblock, err := fs.Superblock() + superblock, err := pass0(fs) if err != nil { - return fmt.Errorf("superblock: %w", err) - } - - fmt.Printf("\nPass 1: chunk mappings...\n") //////////////////////////////////////////////// - - fmt.Printf("Pass 1: ... initializing chunk mappings\n") - if err := fs.Init(); err != nil { - fmt.Printf("Pass 1: ... init chunk tree: error: %v\n", err) - } - - fmt.Printf("Pass 1: ... walking chunk tree\n") - visitedChunkNodes := make(map[btrfs.LogicalAddr]struct{}) - if err := fs.WalkTree(superblock.Data.ChunkTree, btrfs.WalkTreeHandler{ - Node: func(node *util.Ref[btrfs.LogicalAddr, btrfs.Node], err error) error { - if err != nil { - fmt.Printf("Pass 1: ... walk chunk tree: error: %v\n", err) - } - if node != nil { - visitedChunkNodes[node.Addr] = struct{}{} - } - return err - }, - }); err != nil { - fmt.Printf("Pass 1: ... walk chunk tree: error: %v\n", err) - } - - type reconstructedStripe struct { - Size uint64 - Dev *btrfs.Device - Addr btrfs.PhysicalAddr + return err } - 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 - devSize, _ := dev.Size() - lastProgress := -1 - if err := btrfsmisc.ScanForNodes(dev, superblock.Data, func(nodeRef *util.Ref[btrfs.PhysicalAddr, btrfs.Node], err error) { - if err != nil { - fmt.Printf("Pass 1: ... dev[%q] error: %v\n", dev.Name(), err) - return - } - foundNodes[nodeRef.Data.Head.Addr] = append(foundNodes[nodeRef.Data.Head.Addr], nodeRef.Addr) - _, alreadyVisited := visitedChunkNodes[nodeRef.Data.Head.Addr] - if nodeRef.Data.Head.Owner == btrfs.CHUNK_TREE_OBJECTID && !alreadyVisited { - for i, item := range nodeRef.Data.BodyLeaf { - if item.Head.Key.ItemType != btrfsitem.CHUNK_ITEM_KEY { - continue - } - chunk, ok := item.Body.(btrfsitem.Chunk) - if !ok { - fmt.Printf("Pass 1: ... dev[%q] node@%d: item %d: error: type is CHUNK_ITEM_KEY, but struct is %T\n", - dev.Name(), nodeRef.Addr, i, item.Body) - continue - } - fmt.Printf("Pass 1: ... dev[%q] node@%d: item %d: found chunk\n", - dev.Name(), nodeRef.Addr, i) - lostAndFoundChunks = append(lostAndFoundChunks, btrfs.SysChunk{ - Key: item.Head.Key, - Chunk: chunk, - }) - } - } - }, func(pos btrfs.PhysicalAddr) { - pct := int(100 * float64(pos) / float64(devSize)) - if pct != lastProgress || pos == devSize { - fmt.Printf("Pass 1: ... dev[%q] scanned %v%% (found %d nodes)\n", - dev.Name(), pct, len(foundNodes)) - lastProgress = pct - } - }); err != nil { - return err - } - - fmt.Printf("Pass 1: ... dev[%q] re-inserting lost+found chunks\n", dev.Name()) - if len(lostAndFoundChunks) > 0 { - panic("TODO") - } - fmt.Printf("Pass 1: ... dev[%q] re-constructing stripes for lost+found nodes\n", dev.Name()) - lostAndFoundNodes := make(map[btrfs.PhysicalAddr]btrfs.LogicalAddr) - for laddr, readPaddrs := range foundNodes { - resolvedPaddrs, _ := fs.Resolve(laddr) - for _, readPaddr := range readPaddrs { - if _, ok := resolvedPaddrs[btrfs.QualifiedPhysicalAddr{ - Dev: superblock.Data.DevItem.DevUUID, - Addr: readPaddr, - }]; !ok { - lostAndFoundNodes[readPaddr] = laddr - } - } - } - sortedPaddrs := make([]btrfs.PhysicalAddr, 0, len(lostAndFoundNodes)) - for paddr := range lostAndFoundNodes { - sortedPaddrs = append(sortedPaddrs, paddr) - } - sort.Slice(sortedPaddrs, func(i, j int) bool { - return sortedPaddrs[i] < sortedPaddrs[j] - }) - type stripe struct { - PAddr btrfs.PhysicalAddr - LAddr btrfs.LogicalAddr - Size uint64 - } - var stripes []stripe - for _, paddr := range sortedPaddrs { - var lastStripe *stripe - if len(stripes) > 0 { - lastStripe = &stripes[len(stripes)-1] - } - if lastStripe != nil && (lastStripe.PAddr+btrfs.PhysicalAddr(lastStripe.Size)) == paddr { - lastStripe.Size += uint64(superblock.Data.NodeSize) - } else { - stripes = append(stripes, stripe{ - PAddr: paddr, - LAddr: lostAndFoundNodes[paddr], - Size: uint64(superblock.Data.NodeSize), - }) - } - } - //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, - Dev: dev, - 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 := uint32(uint64(superblock.Data.NodeSize) - uint64(binstruct.StaticSize(btrfs.ItemHeader{}))) - for _, dev := range fs.Devices { - itemSize := uint32(binstruct.StaticSize(btrfsitem.Dev{})) - itemOff -= itemSize - superblock, _ := dev.Superblock() - reconstructedNode.Data.BodyLeaf = append(reconstructedNode.Data.BodyLeaf, btrfs.Item{ - Head: btrfs.ItemHeader{ - Key: btrfs.Key{ - ObjectID: btrfs.DEV_ITEMS_OBJECTID, - ItemType: btrfsitem.DEV_ITEM_KEY, - Offset: 1, // ??? - }, - DataOffset: itemOff, - DataSize: itemSize, - }, - Body: superblock.Data.DevItem, - }) - } - for laddr, stripes := range reconstructedChunks { - stripeSize := stripes[0].Size - for _, stripe := range stripes { - if stripe.Size != stripeSize { - panic("TODO: mismatch") - } - } - itemSize := uint32(binstruct.StaticSize(btrfsitem.ChunkHeader{}) + (len(stripes) * binstruct.StaticSize(btrfsitem.ChunkStripe{}))) - itemOff -= itemSize - chunkStripes := make([]btrfsitem.ChunkStripe, len(stripes)) - for i := range stripes { - superblock, _ := stripes[i].Dev.Superblock() - chunkStripes[i] = btrfsitem.ChunkStripe{ - DeviceID: superblock.Data.DevItem.DeviceID, - DeviceUUID: superblock.Data.DevItem.DevUUID, - Offset: stripes[i].Addr, - } - } - reconstructedNode.Data.BodyLeaf = append(reconstructedNode.Data.BodyLeaf, btrfs.Item{ - Head: btrfs.ItemHeader{ - Key: btrfs.Key{ - ObjectID: btrfs.FIRST_CHUNK_TREE_OBJECTID, - ItemType: btrfsitem.CHUNK_ITEM_KEY, - Offset: uint64(laddr), - }, - DataOffset: itemOff, - DataSize: itemSize, - }, - Body: btrfsitem.Chunk{ - Head: btrfsitem.ChunkHeader{ - Size: stripeSize, - Owner: btrfs.EXTENT_TREE_OBJECTID, - StripeLen: 65536, // ??? - Type: 0, // TODO - IOOptimalAlign: superblock.Data.DevItem.IOOptimalAlign, - IOOptimalWidth: superblock.Data.DevItem.IOOptimalWidth, - IOMinSize: superblock.Data.DevItem.IOMinSize, - NumStripes: uint16(len(stripes)), - SubStripes: 1, - }, - Stripes: chunkStripes, - }, - }) - } - reconstructedNode.Data.Head.NumItems = uint32(len(reconstructedNode.Data.BodyLeaf)) - reconstructedNode.Data.Head.Checksum, err = reconstructedNode.Data.CalculateChecksum() + _ /*allNodes*/, err = pass1(fs, superblock) if err != nil { - fmt.Printf("Pass 1: ... new node checksum: error: %v\n", err) - } - if err := reconstructedNode.Write(); err != nil { - fmt.Printf("Pass 1: ... write new node: error: %v\n", err) + return err } fmt.Printf("\nPass 2: orphaned nodes\n") /////////////////////////////////////////////////// |