Skip to content

Commit c916dba

Browse files
committed
Disable size check for xfs/ext3/ext4 filesystems before expansion
1 parent c8f2295 commit c916dba

File tree

2 files changed

+394
-5
lines changed

2 files changed

+394
-5
lines changed

staging/src/k8s.io/mount-utils/resizefs_linux.go

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ package mount
2121

2222
import (
2323
"fmt"
24+
"strconv"
2425
"strings"
2526

26-
"k8s.io/apimachinery/pkg/util/sets"
2727
"k8s.io/klog/v2"
2828
utilexec "k8s.io/utils/exec"
2929
)
@@ -129,18 +129,93 @@ func (resizefs *ResizeFs) NeedResize(devicePath string, deviceMountPath string)
129129
return false, nil
130130
}
131131

132-
supportedFormats := sets.New("ext3", "ext4", "xfs", "btrfs")
133-
if !supportedFormats.Has(format) {
132+
switch format {
133+
case "ext3", "ext4", "xfs":
134+
// For ext3/ext4/xfs, recommendation received from linux filesystem folks is to let
135+
// resize2fs/xfs_growfs do the check for us. So we will not do any check here.
136+
return true, nil
137+
case "btrfs":
138+
deviceSize, err := resizefs.getDeviceSize(devicePath)
139+
if err != nil {
140+
return false, err
141+
}
142+
blockSize, fsSize, err := resizefs.getBtrfsSize(devicePath)
143+
klog.V(5).Infof("Btrfs size: filesystem size=%d, block size=%d, err=%v", fsSize, blockSize, err)
144+
if err != nil {
145+
return false, err
146+
}
147+
if deviceSize <= fsSize+blockSize {
148+
return false, nil
149+
}
150+
return true, nil
151+
default:
134152
return false, fmt.Errorf("could not parse fs info of given filesystem format: %s. Supported fs types are: xfs, ext3, ext4", format)
135153
}
136-
return true, nil
154+
}
155+
156+
func (resizefs *ResizeFs) getDeviceSize(devicePath string) (uint64, error) {
157+
output, err := resizefs.exec.Command(blockDev, "--getsize64", devicePath).CombinedOutput()
158+
outStr := strings.TrimSpace(string(output))
159+
if err != nil {
160+
return 0, fmt.Errorf("failed to read size of device %s: %s: %s", devicePath, err, outStr)
161+
}
162+
size, err := strconv.ParseUint(outStr, 10, 64)
163+
if err != nil {
164+
return 0, fmt.Errorf("failed to parse size of device %s %s: %s", devicePath, outStr, err)
165+
}
166+
return size, nil
167+
}
168+
169+
func (resizefs *ResizeFs) getBtrfsSize(devicePath string) (uint64, uint64, error) {
170+
output, err := resizefs.exec.Command("btrfs", "inspect-internal", "dump-super", "-f", devicePath).CombinedOutput()
171+
if err != nil {
172+
return 0, 0, fmt.Errorf("failed to read size of filesystem on %s: %s: %s", devicePath, err, string(output))
173+
}
174+
175+
blockSize, totalBytes, _ := resizefs.parseBtrfsInfoOutput(string(output), "sectorsize", "total_bytes")
176+
177+
if blockSize == 0 {
178+
return 0, 0, fmt.Errorf("could not find block size of device %s", devicePath)
179+
}
180+
if totalBytes == 0 {
181+
return 0, 0, fmt.Errorf("could not find total size of device %s", devicePath)
182+
}
183+
return blockSize, totalBytes, nil
184+
}
185+
186+
func (resizefs *ResizeFs) parseBtrfsInfoOutput(cmdOutput string, blockSizeKey string, totalBytesKey string) (uint64, uint64, error) {
187+
lines := strings.Split(cmdOutput, "\n")
188+
var blockSize, blockCount uint64
189+
var err error
190+
191+
for _, line := range lines {
192+
tokens := strings.Fields(line)
193+
if len(tokens) != 2 {
194+
continue
195+
}
196+
key, value := strings.ToLower(strings.TrimSpace(tokens[0])), strings.ToLower(strings.TrimSpace(tokens[1]))
197+
198+
if key == blockSizeKey {
199+
blockSize, err = strconv.ParseUint(value, 10, 64)
200+
if err != nil {
201+
return 0, 0, fmt.Errorf("failed to parse block size %s: %s", value, err)
202+
}
203+
}
204+
if key == totalBytesKey {
205+
blockCount, err = strconv.ParseUint(value, 10, 64)
206+
if err != nil {
207+
return 0, 0, fmt.Errorf("failed to parse total size %s: %s", value, err)
208+
}
209+
}
210+
}
211+
return blockSize, blockCount, err
137212
}
138213

139214
func (resizefs *ResizeFs) getDeviceRO(devicePath string) (bool, error) {
140215
output, err := resizefs.exec.Command(blockDev, "--getro", devicePath).CombinedOutput()
141216
outStr := strings.TrimSpace(string(output))
142217
if err != nil {
143-
return false, fmt.Errorf("failed to get readonly bit from device %s: %s: %s", devicePath, err, outStr)
218+
return false, fmt.Errorf("failed to get readonly bit from device %s: %w: %s", devicePath, err, outStr)
144219
}
145220
switch outStr {
146221
case "0":

0 commit comments

Comments
 (0)