From ab4afe57b4d708a0c6af433edb592068a7eaea7d Mon Sep 17 00:00:00 2001 From: Avishay Traeger Date: Mon, 31 Jan 2022 16:55:02 +0200 Subject: [PATCH] Properly detect dm devices Fixes: https://github.com/jaypipes/ghw/issues/298 Signed-off-by: Avishay Traeger --- pkg/block/block.go | 4 ++++ pkg/block/block_linux.go | 19 +++++++++++++++- pkg/block/block_linux_test.go | 42 +++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/pkg/block/block.go b/pkg/block/block.go index 8914893d..757f33cd 100644 --- a/pkg/block/block.go +++ b/pkg/block/block.go @@ -30,6 +30,7 @@ const ( DRIVE_TYPE_ODD // Optical disk drive DRIVE_TYPE_SSD // Solid-state drive DRIVE_TYPE_ISCSI // iSCSI drive + DRIVE_TYPE_MAPPER // Mapper device ) var ( @@ -40,6 +41,7 @@ var ( DRIVE_TYPE_ODD: "ODD", DRIVE_TYPE_SSD: "SSD", DRIVE_TYPE_ISCSI: "ISCSI", + DRIVE_TYPE_MAPPER: "Mapper", } // NOTE(fromani): the keys are all lowercase and do not match @@ -54,6 +56,7 @@ var ( "odd": DRIVE_TYPE_ODD, "ssd": DRIVE_TYPE_SSD, "iscsi": DRIVE_TYPE_ISCSI, + "mapper": DRIVE_TYPE_MAPPER, } ) @@ -166,6 +169,7 @@ type Disk struct { SerialNumber string `json:"serial_number"` WWN string `json:"wwn"` Partitions []*Partition `json:"partitions"` + Members []string `json:"members"` // TODO(jaypipes): Add PCI field for accessing PCI device information // PCI *PCIDevice `json:"pci"` } diff --git a/pkg/block/block_linux.go b/pkg/block/block_linux.go index fa9a1010..aeb36dd3 100644 --- a/pkg/block/block_linux.go +++ b/pkg/block/block_linux.go @@ -252,6 +252,19 @@ func diskIsRemovable(paths *linuxpath.Paths, disk string) bool { return removable == "1" } +func diskMembers(ctx *context.Context, paths *linuxpath.Paths, disk string) []string { + out := make([]string, 0) + path := filepath.Join(paths.SysBlock, disk, "slaves") + files, err := ioutil.ReadDir(path) + if err != nil { + return out + } + for _, file := range files { + out = append(out, file.Name()) + } + return out +} + func disks(ctx *context.Context, paths *linuxpath.Paths) []*Disk { // In Linux, we could use the fdisk, lshw or blockdev commands to list disk // information, however all of these utilities require root privileges to @@ -271,7 +284,7 @@ func disks(ctx *context.Context, paths *linuxpath.Paths) []*Disk { driveType, storageController := diskTypes(dname) // TODO(jaypipes): Move this into diskTypes() once abstracting // diskIsRotational for ease of unit testing - if !diskIsRotational(ctx, paths, dname) { + if driveType != DRIVE_TYPE_MAPPER && !diskIsRotational(ctx, paths, dname) { driveType = DRIVE_TYPE_SSD } size := diskSizeBytes(paths, dname) @@ -286,6 +299,7 @@ func disks(ctx *context.Context, paths *linuxpath.Paths) []*Disk { serialNo := diskSerialNumber(paths, dname) wwn := diskWWN(paths, dname) removable := diskIsRemovable(paths, dname) + members := diskMembers(ctx, paths, dname) d := &Disk{ Name: dname, @@ -300,6 +314,7 @@ func disks(ctx *context.Context, paths *linuxpath.Paths) []*Disk { Model: model, SerialNumber: serialNo, WWN: wwn, + Members: members, } parts := diskPartitions(ctx, paths, dname) @@ -348,6 +363,8 @@ func diskTypes(dname string) ( } else if strings.HasPrefix(dname, "mmc") { driveType = DRIVE_TYPE_SSD storageController = STORAGE_CONTROLLER_MMC + } else if strings.HasPrefix(dname, "dm-") { + driveType = DRIVE_TYPE_MAPPER } return driveType, storageController diff --git a/pkg/block/block_linux_test.go b/pkg/block/block_linux_test.go index 562bf836..95361e9c 100644 --- a/pkg/block/block_linux_test.go +++ b/pkg/block/block_linux_test.go @@ -218,3 +218,45 @@ func TestISCSI(t *testing.T) { t.Fatalf("Got drive type %s, but expected ISCSI", diskInventory[0].DriveType) } } + +func TestMapper(t *testing.T) { + if _, ok := os.LookupEnv("GHW_TESTING_SKIP_BLOCK"); ok { + t.Skip("Skipping block tests.") + } + + baseDir, _ := ioutil.TempDir("", "test") + defer os.RemoveAll(baseDir) + ctx := context.New() + ctx.Chroot = baseDir + paths := linuxpath.New(ctx) + + _ = os.MkdirAll(paths.SysBlock, 0755) + _ = os.MkdirAll(paths.RunUdevData, 0755) + // Emulate a mapper device with no members + _ = os.Mkdir(filepath.Join(paths.SysBlock, "dm-0"), 0755) + _ = ioutil.WriteFile(filepath.Join(paths.SysBlock, "dm-0", "size"), []byte("419430400\n"), 0644) + _ = os.Mkdir(filepath.Join(paths.SysBlock, "dm-0", "queue"), 0755) + _ = ioutil.WriteFile(filepath.Join(paths.SysBlock, "dm-0", "queue", "rotational"), []byte("0\n"), 0644) + _ = ioutil.WriteFile(filepath.Join(paths.SysBlock, "dm-0", "queue", "physical_block_size"), []byte("512\n"), 0644) + + diskInventory := disks(ctx, paths) + if diskInventory[0].DriveType != DRIVE_TYPE_MAPPER { + t.Fatalf("Got drive type %s, but expected Mapper", diskInventory[0].DriveType) + } + if len(diskInventory[0].Members) > 0 { + t.Fatalf("Got %d members but didn't expect any", len(diskInventory[0].Members)) + } + + // Add members (we create regular files here for brevity even though in reality they are symlinks) + _ = os.Mkdir(filepath.Join(paths.SysBlock, "dm-0", "slaves"), 0755) + _ = ioutil.WriteFile(filepath.Join(paths.SysBlock, "dm-0", "slaves", "sda"), []byte(""), 0644) + _ = ioutil.WriteFile(filepath.Join(paths.SysBlock, "dm-0", "slaves", "sdb"), []byte(""), 0644) + + diskInventory = disks(ctx, paths) + if diskInventory[0].DriveType != DRIVE_TYPE_MAPPER { + t.Fatalf("Got drive type %s, but expected Mapper", diskInventory[0].DriveType) + } + if len(diskInventory[0].Members) != 2 { + t.Fatalf("Got %d members but expected 2", len(diskInventory[0].Members)) + } +}