Skip to content

Commit 2c386f1

Browse files
authored
Merge pull request #1561 from stgraber/main
Discard blocks on LVM resize
2 parents d5b4251 + 8a365c0 commit 2c386f1

File tree

3 files changed

+76
-18
lines changed

3 files changed

+76
-18
lines changed

internal/linux/discard.go

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import (
1111
// ClearBlock fully resets a block device or disk file using the most efficient mechanism available.
1212
// For files, it will truncate them down to zero and back to their original size.
1313
// For blocks, it will attempt a variety of discard options, validating the result with marker files and eventually fallback to full zero-ing.
14-
func ClearBlock(blockPath string) error {
14+
//
15+
// An offset can be specified to only reset a part of a device.
16+
func ClearBlock(blockPath string, blockOffset int64) error {
1517
// Open the block device for checking.
1618
fd, err := os.OpenFile(blockPath, os.O_RDWR, 0644)
1719
if err != nil {
@@ -39,7 +41,7 @@ func ClearBlock(blockPath string) error {
3941

4042
if !IsBlockdev(st.Mode()) {
4143
// For files, truncate them.
42-
err := fd.Truncate(0)
44+
err := fd.Truncate(blockOffset)
4345
if err != nil {
4446
return err
4547
}
@@ -55,20 +57,47 @@ func ClearBlock(blockPath string) error {
5557
// Blocks are trickier to reset with options varying based on disk features.
5658
// We use a set of 3 markers to validate whether it was reset.
5759
marker := []byte("INCUS")
58-
markerOffsetStart := int64(0)
59-
markerOffsetMiddle := size / 2
60-
markerOffsetEnd := size - 10
60+
markerLength := int64(len(marker))
61+
markerOffsetStart := blockOffset
62+
markerOffsetMiddle := blockOffset + ((size - blockOffset) / 2)
63+
markerOffsetEnd := size - markerLength
64+
65+
if markerOffsetStart+markerLength > size {
66+
// No markers can fit.
67+
markerOffsetStart = -1
68+
markerOffsetMiddle = -1
69+
markerOffsetEnd = -1
70+
} else {
71+
if markerOffsetMiddle <= markerOffsetStart+markerLength {
72+
// Middle marker goes over start marker.
73+
markerOffsetMiddle = -1
74+
}
75+
76+
if markerOffsetEnd <= markerOffsetMiddle+markerLength {
77+
// End marker goes over middle marker.
78+
markerOffsetEnd = -1
79+
}
80+
81+
if markerOffsetEnd <= markerOffsetStart+markerLength {
82+
// End marker goes over start marker.
83+
markerOffsetEnd = -1
84+
}
85+
}
6186

6287
writeMarkers := func(fd *os.File) error {
6388
for _, offset := range []int64{markerOffsetStart, markerOffsetMiddle, markerOffsetEnd} {
89+
if offset < 0 {
90+
continue
91+
}
92+
6493
// Write the marker at the set offset.
6594
n, err := fd.WriteAt(marker, offset)
6695
if err != nil {
6796
return err
6897
}
6998

70-
if n != len(marker) {
71-
return fmt.Errorf("Only managed to write %d bytes out of %d of the %d offset marker", n, len(marker), offset)
99+
if n != int(markerLength) {
100+
return fmt.Errorf("Only managed to write %d bytes out of %d of the %d offset marker", n, markerLength, offset)
72101
}
73102
}
74103

@@ -79,17 +108,21 @@ func ClearBlock(blockPath string) error {
79108
found := 0
80109

81110
for _, offset := range []int64{markerOffsetStart, markerOffsetMiddle, markerOffsetEnd} {
82-
fmt.Printf("offset=%d\n", offset)
83-
buf := make([]byte, 5)
111+
if offset < 0 {
112+
found++
113+
continue
114+
}
115+
116+
buf := make([]byte, markerLength)
84117

85118
// Read the marker from the offset.
86119
n, err := fd.ReadAt(buf, offset)
87120
if err != nil {
88121
return found, err
89122
}
90123

91-
if n != len(marker) {
92-
return found, fmt.Errorf("Only managed to read %d bytes out of %d of the %d offset marker", n, len(marker), offset)
124+
if n != int(markerLength) {
125+
return found, fmt.Errorf("Only managed to read %d bytes out of %d of the %d offset marker", n, markerLength, offset)
93126
}
94127

95128
// Check if we found it.
@@ -120,7 +153,7 @@ func ClearBlock(blockPath string) error {
120153
_ = fd.Close()
121154

122155
// Attempt a secure discard run.
123-
_, err = subprocess.RunCommand("blkdiscard", "-f", "-s", blockPath)
156+
_, err = subprocess.RunCommand("blkdiscard", "-f", "-o", fmt.Sprintf("%d", blockOffset), "-s", blockPath)
124157
if err == nil {
125158
// Check if the markers are gone.
126159
fd, err := os.Open(blockPath)
@@ -145,7 +178,7 @@ func ClearBlock(blockPath string) error {
145178
}
146179

147180
// Attempt a regular discard run.
148-
_, err = subprocess.RunCommand("blkdiscard", "-f", blockPath)
181+
_, err = subprocess.RunCommand("blkdiscard", "-f", "-o", fmt.Sprintf("%d", blockOffset), blockPath)
149182
if err == nil {
150183
// Check if the markers are gone.
151184
fd, err := os.Open(blockPath)
@@ -170,7 +203,7 @@ func ClearBlock(blockPath string) error {
170203
}
171204

172205
// Attempt device zero-ing.
173-
_, err = subprocess.RunCommand("blkdiscard", "-f", "-z", blockPath)
206+
_, err = subprocess.RunCommand("blkdiscard", "-f", "-o", fmt.Sprintf("%d", blockOffset), "-z", blockPath)
174207
if err == nil {
175208
// Check if the markers are gone.
176209
fd, err := os.Open(blockPath)
@@ -209,12 +242,17 @@ func ClearBlock(blockPath string) error {
209242

210243
defer fd.Close()
211244

212-
n, err := io.CopyN(fd, zero, size)
245+
_, err = fd.Seek(blockOffset, 0)
246+
if err != nil {
247+
return err
248+
}
249+
250+
n, err := io.CopyN(fd, zero, size-blockOffset)
213251
if err != nil {
214252
return err
215253
}
216254

217-
if n != size {
255+
if n != (size - blockOffset) {
218256
return fmt.Errorf("Only managed to reset %d bytes out of %d", n, size)
219257
}
220258

internal/server/storage/drivers/driver_lvm_utils.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,11 +568,31 @@ func (d *lvm) resizeLogicalVolume(lvPath string, sizeBytes int64) error {
568568
args = append(args, "--fs=ignore")
569569
}
570570

571+
// If needed, get the original LV size.
572+
var oldSizeBytes int64
573+
if !d.usesThinpool() {
574+
oldSizeBytes, err = d.logicalVolumeSize(lvPath)
575+
if err != nil {
576+
return err
577+
}
578+
}
579+
571580
_, err = subprocess.TryRunCommand("lvresize", args...)
572581
if err != nil {
573582
return err
574583
}
575584

585+
// On thick pools, discard the blocks in the additional space when the volume is grown.
586+
if !d.usesThinpool() {
587+
if oldSizeBytes < sizeBytes {
588+
// Discard the new blocks.
589+
err := linux.ClearBlock(lvPath, sizeBytes)
590+
if err != nil {
591+
return err
592+
}
593+
}
594+
}
595+
576596
d.logger.Debug("Logical volume resized", logger.Ctx{"dev": lvPath, "size": fmt.Sprintf("%db", sizeBytes)})
577597
return nil
578598
}

internal/server/storage/drivers/generic_vfs.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ func genericVFSCreateVolumeFromMigration(d Driver, initVolume func(vol Volume) (
326326
}
327327

328328
// Reset the disk.
329-
err := linux.ClearBlock(path)
329+
err := linux.ClearBlock(path, 0)
330330
if err != nil {
331331
return err
332332
}
@@ -770,7 +770,7 @@ func genericVFSBackupUnpack(d Driver, sysOS *sys.OS, vol Volume, snapshots []str
770770
var allowUnsafeResize bool
771771

772772
// Reset the disk.
773-
err = linux.ClearBlock(targetPath)
773+
err = linux.ClearBlock(targetPath, 0)
774774
if err != nil {
775775
return err
776776
}

0 commit comments

Comments
 (0)