diff --git a/image/qcow2/qcow2.go b/image/qcow2/qcow2.go index ac322dd..0897923 100644 --- a/image/qcow2/qcow2.go +++ b/image/qcow2/qcow2.go @@ -536,6 +536,7 @@ type Qcow2 struct { errUnreadable error clusterSize int l1Table []l1TableEntry + l2TablesCache map[l1TableEntry][]l2TableEntry decompressor Decompressor BackingFile string `json:"backing_file"` BackingFileFullPath string `json:"backing_file_full_path"` @@ -549,7 +550,8 @@ type Qcow2 struct { // and openWithType must be non-nil. func Open(ra io.ReaderAt, openWithType image.OpenWithType) (*Qcow2, error) { img := &Qcow2{ - ra: ra, + ra: ra, + l2TablesCache: make(map[l1TableEntry][]l2TableEntry), } r := io.NewSectionReader(ra, 0, -1) var err error @@ -712,7 +714,7 @@ func (img *Qcow2) readAtAligned(p []byte, off int64) (int, error) { extL2Entry = &extL2Table[l2Index] l2Entry = extL2Entry.L2TableEntry } else { - l2Table, err := readL2Table(img.ra, l2TableOffset, img.clusterSize) + l2Table, err := img.getL2Table(l1Entry) if err != nil { return 0, fmt.Errorf("failed to read L2 table for L1 entry %v (index %d): %w", l1Entry, l1Index, err) } @@ -752,6 +754,19 @@ func (img *Qcow2) readAtAligned(p []byte, off int64) (int, error) { return n, err } +func (img *Qcow2) getL2Table(l1Entry l1TableEntry) ([]l2TableEntry, error) { + var err error + l2Table := img.l2TablesCache[l1Entry] + if l2Table == nil { + l2Table, err = readL2Table(img.ra, l1Entry.l2Offset(), img.clusterSize) + if err != nil { + return nil, err + } + img.l2TablesCache[l1Entry] = l2Table + } + return l2Table, nil +} + func (img *Qcow2) readAtAlignedUnallocated(p []byte, off int64) (int, error) { if img.backingImage == nil { return img.readZero(p, off)