1import os 2import subprocess 3 4import infra.basetest 5 6 7class TestLvm2(infra.basetest.BRTest): 8 # The lvm2 package has _LINUX_CONFIG_FIXUPS, so we cannot use 9 # the runtime test pre-built Kernel. We need to compile a Kernel 10 # to make sure it will include the required configuration. 11 config = \ 12 """ 13 BR2_aarch64=y 14 BR2_TOOLCHAIN_EXTERNAL=y 15 BR2_TARGET_GENERIC_GETTY_PORT="ttyAMA0" 16 BR2_LINUX_KERNEL=y 17 BR2_LINUX_KERNEL_CUSTOM_VERSION=y 18 BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.1.77" 19 BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y 20 BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/qemu/aarch64-virt/linux.config" 21 BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y 22 BR2_PACKAGE_E2FSPROGS=y 23 BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y 24 BR2_PACKAGE_LVM2=y 25 BR2_TARGET_ROOTFS_CPIO=y 26 BR2_TARGET_ROOTFS_CPIO_GZIP=y 27 # BR2_TARGET_ROOTFS_TAR is not set 28 """ 29 30 def get_free_disk_space(self, path): 31 out, ret = self.emulator.run(f"df -k {path}") 32 self.assertEqual(ret, 0) 33 return int(out[1].split()[3]) 34 35 def test_run(self): 36 # Test configuration: 37 storage_devs = ["/dev/vda", "/dev/vdb", "/dev/vdc"] 38 storage_size = 16 # Mega Bytes 39 lvm_vg = "br_vg" # Volume Group name 40 lvm_lv = "br_lv" # Logical Volume name 41 lv_dev = f"/dev/{lvm_vg}/{lvm_lv}" # Logical Volume dev name 42 mnt_pt = "/mnt/lvm2-storage" 43 data_file = f"{mnt_pt}/data.bin" 44 45 qemu_storage_opts = [] 46 for i in range(len(storage_devs)): 47 disk_file = os.path.join(self.builddir, "images", f"disk{i}.img") 48 self.emulator.logfile.write(f"Creating disk image: {disk_file}\n") 49 self.emulator.logfile.flush() 50 subprocess.check_call( 51 ["dd", "if=/dev/zero", f"of={disk_file}", 52 "bs=1M", f"count={storage_size}"], 53 stdout=self.emulator.logfile, 54 stderr=self.emulator.logfile) 55 opts = ["-drive", f"file={disk_file},if=virtio,format=raw"] 56 qemu_storage_opts += opts 57 58 img = os.path.join(self.builddir, "images", "rootfs.cpio.gz") 59 kern = os.path.join(self.builddir, "images", "Image") 60 self.emulator.boot(arch="aarch64", 61 kernel=kern, 62 kernel_cmdline=["console=ttyAMA0"], 63 options=["-M", "virt", "-cpu", "cortex-a57", "-m", "256M", 64 "-initrd", img] + qemu_storage_opts) 65 self.emulator.login() 66 67 # Test the program can execute. 68 self.assertRunOk("lvm version") 69 70 # We did not created any Physical Volume yet. We should NOT 71 # see any of our storage devices in a pvscan. 72 out, ret = self.emulator.run("pvscan") 73 self.assertEqual(ret, 0) 74 for dev in storage_devs: 75 self.assertNotIn(dev, "\n".join(out)) 76 77 # We initialize our Physical Volumes (PVs). 78 pv_devs = " ".join(storage_devs) 79 self.assertRunOk(f"pvcreate {pv_devs}") 80 81 # We run few diagnostic commands related to PVs. 82 self.assertRunOk(f"pvck {pv_devs}") 83 self.assertRunOk(f"pvdisplay {pv_devs}") 84 self.assertRunOk("pvs") 85 86 # Now we initialized the PVs, we should see them in a pvscan. 87 out, ret = self.emulator.run("pvscan") 88 self.assertEqual(ret, 0) 89 for dev in storage_devs: 90 self.assertIn(dev, "\n".join(out)) 91 92 # We create a Volume Group (VG) including two of our three 93 # PVs. 94 cmd = f"vgcreate {lvm_vg} {storage_devs[0]} {storage_devs[1]}" 95 self.assertRunOk(cmd) 96 97 # We run few diagnostic commands related to VGs. 98 self.assertRunOk(f"vgck {lvm_vg}") 99 self.assertRunOk(f"vgdisplay {lvm_vg}") 100 self.assertRunOk("vgscan") 101 self.assertRunOk("vgs") 102 103 # We create a Logical Volume (LV) in our VG. 104 self.assertRunOk(f"lvcreate -l 100%FREE -n {lvm_lv} {lvm_vg}") 105 106 # We check LVM created the LV device. 107 self.assertRunOk(f"ls -al {lv_dev}") 108 109 # We run few diagnostic commands related to LVs. 110 self.assertRunOk("lvscan") 111 self.assertRunOk("lvs") 112 113 # We create a ext4 filesystem on our LV. 114 self.assertRunOk(f"mkfs.ext4 {lv_dev}") 115 116 # We create a mount point directory and mount the device. 117 self.assertRunOk(f"mkdir -p {mnt_pt}") 118 self.assertRunOk(f"mount {lv_dev} {mnt_pt}") 119 120 # We create a data file in our new filesystem. Note: this file 121 # is slightly larger than a single PV. This data file should 122 # span over the two PVs in the VG. 123 data_size = storage_size + 4 124 cmd = f"dd if=/dev/urandom of={data_file} bs=1M count={data_size}" 125 self.assertRunOk(cmd) 126 127 # We compute the hash of our data, and save it for later. 128 hash_cmd = f"sha256sum {data_file}" 129 out, ret = self.emulator.run(hash_cmd) 130 self.assertEqual(ret, 0) 131 data_sha256 = out[0] 132 133 # We compute the free space of the mount point. 134 fs_free_space = self.get_free_disk_space(mnt_pt) 135 136 # We extend of VG with our third PV. 137 self.assertRunOk(f"vgextend {lvm_vg} {storage_devs[2]}") 138 139 # We grow the LV to use all the space of the VG. 140 self.assertRunOk(f"lvresize -l +100%FREE {lvm_vg}/{lvm_lv}") 141 142 # We resize the filesystem to use all the LV space. 143 self.assertRunOk(f"resize2fs {lv_dev}") 144 145 # Now we grew the LV and resized the filesystem, we recompute 146 # the free space and check we have more. 147 fs2_free_space = self.get_free_disk_space(mnt_pt) 148 self.assertGreater(fs2_free_space, fs_free_space) 149 150 # With all those on-the-fly operations on the mounted 151 # filesystem, the data file should be intact. We should 152 # recompute the same data checksum as before. 153 out, ret = self.emulator.run(hash_cmd) 154 self.assertEqual(ret, 0) 155 self.assertEqual(out[0], data_sha256) 156 157 # Finally, we unmount the filesystem. It should not contain 158 # any error. 159 self.assertRunOk(f"umount {mnt_pt}") 160 self.assertRunOk(f"e2fsck -f -n {lv_dev}") 161