1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com>
//
// SPDX-License-Identifier: GPL-2.0-or-later
package scanforextents
import (
"context"
"sort"
"golang.org/x/exp/constraints"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
)
type PhysicalGap struct {
Beg, End btrfsvol.PhysicalAddr
}
func ListPhysicalGaps(fs *btrfs.FS) map[btrfsvol.DeviceID][]PhysicalGap {
gaps := make(map[btrfsvol.DeviceID][]PhysicalGap)
pos := make(map[btrfsvol.DeviceID]btrfsvol.PhysicalAddr)
mappings := fs.LV.Mappings()
sort.Slice(mappings, func(i, j int) bool {
return mappings[i].PAddr.Cmp(mappings[j].PAddr) < 0
})
for _, mapping := range mappings {
if pos[mapping.PAddr.Dev] < mapping.PAddr.Addr {
gaps[mapping.PAddr.Dev] = append(gaps[mapping.PAddr.Dev], PhysicalGap{
Beg: pos[mapping.PAddr.Dev],
End: mapping.PAddr.Addr,
})
}
if pos[mapping.PAddr.Dev] < mapping.PAddr.Addr.Add(mapping.Size) {
pos[mapping.PAddr.Dev] = mapping.PAddr.Addr.Add(mapping.Size)
}
}
for devID, dev := range fs.LV.PhysicalVolumes() {
devSize := dev.Size()
if pos[devID] < devSize {
gaps[devID] = append(gaps[devID], PhysicalGap{
Beg: pos[devID],
End: devSize,
})
}
}
return gaps
}
func roundUp[T constraints.Integer](x, multiple T) T {
return ((x + multiple - 1) / multiple) * multiple
}
func WalkGapsOneDev(ctx context.Context, dev *btrfs.Device,
gaps []PhysicalGap, blockSize btrfsvol.PhysicalAddr,
progress func(cur, total int64),
main func(btrfsvol.PhysicalAddr) error,
) error {
var totalBlocks int64
for _, gap := range gaps {
for paddr := roundUp(gap.Beg, blockSize); paddr+blockSize <= gap.End; paddr += blockSize {
totalBlocks++
}
}
var curBlock int64
for _, gap := range gaps {
for paddr := roundUp(gap.Beg, blockSize); paddr+blockSize <= gap.End; paddr += blockSize {
if err := ctx.Err(); err != nil {
return err
}
progress(curBlock, totalBlocks)
curBlock++
if err := main(paddr); err != nil {
return err
}
}
}
progress(curBlock, totalBlocks)
return nil
}
|