From c1f41ceab392ac8d13a5cacdba738b18d314ee9f Mon Sep 17 00:00:00 2001 From: Roman Bednar Date: Mon, 7 Mar 2022 12:35:55 +0100 Subject: [PATCH] Add support for btrfs resize Mount utils support resizing of btrfs volume, however it lacks btrfs device block size and total size detection needed to determine if resize is needed. Adding btrfs support is useful for certain CSI drivers (e.g. Azure) which now have to implement custom solution for btrfs resize. With this patch it should be easy for such drivers to use mount-utils module instead and help unify (and correct) the resize flows. --- .../src/k8s.io/mount-utils/resizefs_linux.go | 48 ++++ .../k8s.io/mount-utils/resizefs_linux_test.go | 238 ++++++++++++++++++ 2 files changed, 286 insertions(+) diff --git a/staging/src/k8s.io/mount-utils/resizefs_linux.go b/staging/src/k8s.io/mount-utils/resizefs_linux.go index b92ce118200..929d061e52b 100644 --- a/staging/src/k8s.io/mount-utils/resizefs_linux.go +++ b/staging/src/k8s.io/mount-utils/resizefs_linux.go @@ -129,6 +129,9 @@ func (resizefs *ResizeFs) NeedResize(devicePath string, deviceMountPath string) case "xfs": blockSize, fsSize, err = resizefs.getXFSSize(deviceMountPath) klog.V(5).Infof("Xfs size: filesystem size=%d, block size=%d, err=%v", fsSize, blockSize, err) + case "btrfs": + blockSize, fsSize, err = resizefs.getBtrfsSize(devicePath) + klog.V(5).Infof("Btrfs size: filesystem size=%d, block size=%d, err=%v", fsSize, blockSize, err) default: klog.Errorf("Not able to parse given filesystem info. fsType: %s, will not resize", format) return false, fmt.Errorf("Could not parse fs info on given filesystem format: %s. Supported fs types are: xfs, ext3, ext4", format) @@ -190,6 +193,51 @@ func (resizefs *ResizeFs) getXFSSize(devicePath string) (uint64, uint64, error) return blockSize, blockSize * blockCount, nil } +func (resizefs *ResizeFs) getBtrfsSize(devicePath string) (uint64, uint64, error) { + output, err := resizefs.exec.Command("btrfs", "inspect-internal", "dump-super", "-f", devicePath).CombinedOutput() + if err != nil { + return 0, 0, fmt.Errorf("failed to read size of filesystem on %s: %s: %s", devicePath, err, string(output)) + } + + blockSize, totalBytes, _ := resizefs.parseBtrfsInfoOutput(string(output), "sectorsize", "total_bytes") + + if blockSize == 0 { + return 0, 0, fmt.Errorf("could not find block size of device %s", devicePath) + } + if totalBytes == 0 { + return 0, 0, fmt.Errorf("could not find total size of device %s", devicePath) + } + return blockSize, totalBytes, nil +} + +func (resizefs *ResizeFs) parseBtrfsInfoOutput(cmdOutput string, blockSizeKey string, totalBytesKey string) (uint64, uint64, error) { + lines := strings.Split(cmdOutput, "\n") + var blockSize, blockCount uint64 + var err error + + for _, line := range lines { + tokens := strings.Fields(line) + if len(tokens) != 2 { + continue + } + key, value := strings.ToLower(strings.TrimSpace(tokens[0])), strings.ToLower(strings.TrimSpace(tokens[1])) + + if key == blockSizeKey { + blockSize, err = strconv.ParseUint(value, 10, 64) + if err != nil { + return 0, 0, fmt.Errorf("failed to parse block size %s: %s", value, err) + } + } + if key == totalBytesKey { + blockCount, err = strconv.ParseUint(value, 10, 64) + if err != nil { + return 0, 0, fmt.Errorf("failed to parse total size %s: %s", value, err) + } + } + } + return blockSize, blockCount, err +} + func (resizefs *ResizeFs) parseFsInfoOutput(cmdOutput string, spliter string, blockSizeKey string, blockCountKey string) (uint64, uint64, error) { lines := strings.Split(cmdOutput, "\n") var blockSize, blockCount uint64 diff --git a/staging/src/k8s.io/mount-utils/resizefs_linux_test.go b/staging/src/k8s.io/mount-utils/resizefs_linux_test.go index 601598c4019..1b0b435fbf2 100644 --- a/staging/src/k8s.io/mount-utils/resizefs_linux_test.go +++ b/staging/src/k8s.io/mount-utils/resizefs_linux_test.go @@ -166,6 +166,224 @@ Journal sequence: 0x00037109 Journal start: 1 Journal checksum type: crc32c Journal checksum: 0xb7df3c6e +` + cmdOutputSuccessBtrfs := + `superblock: bytenr=65536, device=/dev/loop0 +--------------------------------------------------------- +csum_type 0 (crc32c) +csum_size 4 +csum 0x31693b11 [match] +bytenr 65536 +flags 0x1 + ( WRITTEN ) +magic _BHRfS_M [match] +fsid 3f53c8f7-3c57-4185-bf1d-b305b42cce97 +metadata_uuid 3f53c8f7-3c57-4185-bf1d-b305b42cce97 +label +generation 7 +root 30441472 +sys_array_size 129 +chunk_root_generation 6 +root_level 0 +chunk_root 22036480 +chunk_root_level 0 +log_root 0 +log_root_transid 0 +log_root_level 0 +total_bytes 1048576000 +bytes_used 147456 +sectorsize 4096 +nodesize 16384 +leafsize (deprecated) 16384 +stripesize 4096 +root_dir 6 +num_devices 1 +compat_flags 0x0 +compat_ro_flags 0x3 + ( FREE_SPACE_TREE | + FREE_SPACE_TREE_VALID ) +incompat_flags 0x341 + ( MIXED_BACKREF | + EXTENDED_IREF | + SKINNY_METADATA | + NO_HOLES ) +cache_generation 0 +uuid_tree_generation 7 +dev_item.uuid 987c8423-fba3-4168-9892-560a116feb81 +dev_item.fsid 3f53c8f7-3c57-4185-bf1d-b305b42cce97 [match] +dev_item.type 0 +dev_item.total_bytes 1048576000 +dev_item.bytes_used 130023424 +dev_item.io_align 4096 +dev_item.io_width 4096 +dev_item.sector_size 4096 +dev_item.devid 1 +dev_item.dev_group 0 +dev_item.seek_speed 0 +dev_item.bandwidth 0 +dev_item.generation 0 +sys_chunk_array[2048]: + item 0 key (FIRST_CHUNK_TREE CHUNK_ITEM 22020096) + length 8388608 owner 2 stripe_len 65536 type SYSTEM|DUP + io_align 65536 io_width 65536 sector_size 4096 + num_stripes 2 sub_stripes 1 + stripe 0 devid 1 offset 22020096 + dev_uuid 987c8423-fba3-4168-9892-560a116feb81 + stripe 1 devid 1 offset 30408704 + dev_uuid 987c8423-fba3-4168-9892-560a116feb81 +backup_roots[4]: + backup 0: + backup_tree_root: 30441472 gen: 5 level: 0 + backup_chunk_root: 22020096 gen: 5 level: 0 + backup_extent_root: 30474240 gen: 5 level: 0 + backup_fs_root: 30425088 gen: 5 level: 0 + backup_dev_root: 30457856 gen: 5 level: 0 + backup_csum_root: 30490624 gen: 5 level: 0 + backup_total_bytes: 1048576000 + backup_bytes_used: 147456 + backup_num_devices: 1 + + backup 1: + backup_tree_root: 30588928 gen: 6 level: 0 + backup_chunk_root: 22036480 gen: 6 level: 0 + backup_extent_root: 30408704 gen: 6 level: 0 + backup_fs_root: 30425088 gen: 5 level: 0 + backup_dev_root: 30556160 gen: 6 level: 0 + backup_csum_root: 30490624 gen: 5 level: 0 + backup_total_bytes: 1048576000 + backup_bytes_used: 147456 + backup_num_devices: 1 + + backup 2: + backup_tree_root: 30441472 gen: 7 level: 0 + backup_chunk_root: 22036480 gen: 6 level: 0 + backup_extent_root: 30474240 gen: 7 level: 0 + backup_fs_root: 30425088 gen: 5 level: 0 + backup_dev_root: 30457856 gen: 7 level: 0 + backup_csum_root: 30490624 gen: 5 level: 0 + backup_total_bytes: 1048576000 + backup_bytes_used: 147456 + backup_num_devices: 1 + + backup 3: + backup_tree_root: 30408704 gen: 4 level: 0 + backup_chunk_root: 1064960 gen: 4 level: 0 + backup_extent_root: 5341184 gen: 4 level: 0 + backup_fs_root: 5324800 gen: 3 level: 0 + backup_dev_root: 5242880 gen: 4 level: 0 + backup_csum_root: 1130496 gen: 1 level: 0 + backup_total_bytes: 1048576000 + backup_bytes_used: 114688 + backup_num_devices: 1 + +` + cmdOutputNoDataBtrfs := + `superblock: bytenr=65536, device=/dev/loop0 +--------------------------------------------------------- +csum_type 0 (crc32c) +csum_size 4 +csum 0x31693b11 [match] +bytenr 65536 +flags 0x1 + ( WRITTEN ) +magic _BHRfS_M [match] +fsid 3f53c8f7-3c57-4185-bf1d-b305b42cce97 +metadata_uuid 3f53c8f7-3c57-4185-bf1d-b305b42cce97 +label +generation 7 +root 30441472 +sys_array_size 129 +chunk_root_generation 6 +root_level 0 +chunk_root 22036480 +chunk_root_level 0 +log_root 0 +log_root_transid 0 +log_root_level 0 +bytes_used 147456 +nodesize 16384 +leafsize (deprecated) 16384 +stripesize 4096 +root_dir 6 +num_devices 1 +compat_flags 0x0 +compat_ro_flags 0x3 + ( FREE_SPACE_TREE | + FREE_SPACE_TREE_VALID ) +incompat_flags 0x341 + ( MIXED_BACKREF | + EXTENDED_IREF | + SKINNY_METADATA | + NO_HOLES ) +cache_generation 0 +uuid_tree_generation 7 +dev_item.uuid 987c8423-fba3-4168-9892-560a116feb81 +dev_item.fsid 3f53c8f7-3c57-4185-bf1d-b305b42cce97 [match] +dev_item.type 0 +dev_item.total_bytes 1048576000 +dev_item.bytes_used 130023424 +dev_item.io_align 4096 +dev_item.io_width 4096 +dev_item.sector_size 4096 +dev_item.devid 1 +dev_item.dev_group 0 +dev_item.seek_speed 0 +dev_item.bandwidth 0 +dev_item.generation 0 +sys_chunk_array[2048]: + item 0 key (FIRST_CHUNK_TREE CHUNK_ITEM 22020096) + length 8388608 owner 2 stripe_len 65536 type SYSTEM|DUP + io_align 65536 io_width 65536 sector_size 4096 + num_stripes 2 sub_stripes 1 + stripe 0 devid 1 offset 22020096 + dev_uuid 987c8423-fba3-4168-9892-560a116feb81 + stripe 1 devid 1 offset 30408704 + dev_uuid 987c8423-fba3-4168-9892-560a116feb81 +backup_roots[4]: + backup 0: + backup_tree_root: 30441472 gen: 5 level: 0 + backup_chunk_root: 22020096 gen: 5 level: 0 + backup_extent_root: 30474240 gen: 5 level: 0 + backup_fs_root: 30425088 gen: 5 level: 0 + backup_dev_root: 30457856 gen: 5 level: 0 + backup_csum_root: 30490624 gen: 5 level: 0 + backup_total_bytes: 1048576000 + backup_bytes_used: 147456 + backup_num_devices: 1 + + backup 1: + backup_tree_root: 30588928 gen: 6 level: 0 + backup_chunk_root: 22036480 gen: 6 level: 0 + backup_extent_root: 30408704 gen: 6 level: 0 + backup_fs_root: 30425088 gen: 5 level: 0 + backup_dev_root: 30556160 gen: 6 level: 0 + backup_csum_root: 30490624 gen: 5 level: 0 + backup_total_bytes: 1048576000 + backup_bytes_used: 147456 + backup_num_devices: 1 + + backup 2: + backup_tree_root: 30441472 gen: 7 level: 0 + backup_chunk_root: 22036480 gen: 6 level: 0 + backup_extent_root: 30474240 gen: 7 level: 0 + backup_fs_root: 30425088 gen: 5 level: 0 + backup_dev_root: 30457856 gen: 7 level: 0 + backup_csum_root: 30490624 gen: 5 level: 0 + backup_total_bytes: 1048576000 + backup_bytes_used: 147456 + backup_num_devices: 1 + + backup 3: + backup_tree_root: 30408704 gen: 4 level: 0 + backup_chunk_root: 1064960 gen: 4 level: 0 + backup_extent_root: 5341184 gen: 4 level: 0 + backup_fs_root: 5324800 gen: 3 level: 0 + backup_dev_root: 5242880 gen: 4 level: 0 + backup_csum_root: 1130496 gen: 1 level: 0 + backup_total_bytes: 1048576000 + backup_bytes_used: 114688 + backup_num_devices: 1 + ` testcases := []struct { name string @@ -212,6 +430,24 @@ Journal checksum: 0xb7df3c6e expectError: true, fsType: "ext4", }, + { + name: "success parse btrfs info", + devicePath: "/dev/test1", + blocksize: 4096, + blockCount: 256000, + cmdOutput: cmdOutputSuccessBtrfs, + expectError: false, + fsType: "btrfs", + }, + { + name: "block size not present - btrfs", + devicePath: "/dev/test1", + blocksize: 0, + blockCount: 0, + cmdOutput: cmdOutputNoDataBtrfs, + expectError: true, + fsType: "btrfs", + }, } for _, test := range testcases { @@ -238,6 +474,8 @@ Journal checksum: 0xb7df3c6e blockSize, fsSize, err = resizefs.getXFSSize(test.devicePath) case "ext4": blockSize, fsSize, err = resizefs.getExtSize(test.devicePath) + case "btrfs": + blockSize, fsSize, err = resizefs.getBtrfsSize(test.devicePath) } if blockSize != test.blocksize {