sysfs相关知识介绍和硬件采集的应用

237 阅读3分钟

背景

在做硬件采集的时候,需要采集设备的基础信息,例如:厂商、型号等等,那我们就要考虑是否有统一的方法来获取这些信息呢?显然肯定是有的,在此我将介绍具体实现方法。文章介绍了sysfs相关知识,例如modalias,以及硬件采集的具体应用。

sysfs介绍

man7.org/linux/man-p…

linux内核开始使用sysfs文件系统,它的作用是将设备和驱动程序的信息导出到用户空间,方便了用户读取设备信息,同时支持修改和调整。

/sys/block/

记录每个块设备的一个符号链接,符号链接指向/sys/devices/下,例如


$ ls -l /sys/block/

lrwxrwxrwx 1 root root 0 Nov  3 16:11 sda -> ../devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:0:11/0:0:11:0/block/sda

lrwxrwxrwx 1 root root 0 Nov  3 16:11 sdb -> ../devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:0:30/0:0:30:0/block/sdb

……

lrwxrwxrwx 1 root root 0 Nov  3 16:11 sdt -> ../devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:0:28/0:0:28:0/block/sdt

lrwxrwxrwx 1 root root 0 Nov  3 16:11 sdu -> ../devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:0:29/0:0:29:0/block/sdu

lsscsi

lsscsi我们再熟悉不过了,在更换磁盘的时候经常会用来确定磁盘和VD的对应关系,我们口口相传倒数第二条是VD号,谁也没说清是为什么。其实这些条目分别是H:C:T:L,target对应的就是VD号。

<h:c:t:l>      filter output list (def: '*:*:*:*' (all)). Meaning:
                  <host_num:controller:target:lun> or for NVMe:
                  <'N':ctl_num:cntlid:namespace_id>

同样的,lsscsi的第三段会看到许多不一样的结果,这些是传输协议,例如ATA、SATA、DELL等等


$ lsscsi
[0:0:0:0]    disk    ATA      INTEL SSDSC2KB01 0121  /dev/sda # JBOD
[0:0:1:0]    disk    ATA      INTEL SSDSC2KB01 0121  /dev/sdb
……
[0:2:0:0]    disk    DELL     PERC H730 Mini   4.25  /dev/sdu # RAID1

$ lsscsi
[0:0:1:0]    disk    ATA      SAMSUNG MZ7L3480 104Q  -        # 同一个NVME会出现多次?
[0:0:2:0]    disk    ATA      SAMSUNG MZ7L3480 104Q  -        # 同一个NVME会出现多次?
[0:1:0:0]    disk    LSI      Logical Volume   3000  /dev/sda
[N:0:6:1]    disk    SAMSUNG MZQL21T9HCJR-00B7C__1              /dev/nvme0n1  # 同一个NVME会出现多次?

常见的传输协议有:IEEE 1394, ATA, FC, iSCSI, SAS, SATA, SPI and USB

什么是 ATA 和 SATA

ATA 也称为 IDE(集成驱动器电子系统),是一种较老的接口标准,于 20 世纪 80 年代推出。它在早期 PC 开发中发挥了关键作用,用于连接硬盘和光驱等存储设备。ATA 使用并行数据传输,使用多条数据线同时传输数据。存储设备通过 16 位并行连接与计算机主板相连。在标准设置中,每个通道启用两个设备。ATA 使用主从配置,最多允许四个设备。

SATA是串行 ATA 的缩写,是 21 世纪初推出的一种较新的接口标准。它取代了高级技术附件或 IDE 等较旧的接口标准。SATA 解决了以前并行数据传输方法的局限性,从而提高了性能、电缆管理和效率。使用串行连接可以实现比 ATA 更快的数据传输速率,速度高达 6 Gb/s。SATA 接口的每个通道都支持单个设备。但是,大多数现代主板上都有多个 SATA 端口,可以连接多个设备。

代码实现

那么我们如何获取到HCTL呢?

$ ls /sys/block/sd*/device/bsg/
0:2:0:0

vd和block关联

// vd和block关联
func (m *Megacli) virtualDiskToBlockDevice(pci, vd string) (*block.Block, error) {
	var err error
	if m.Block == nil {
		m.Block, err = block.Blocks()
		if err != nil {
			return nil, err
		}
	}
	for _, b := range m.Block {
		vendor := b.Vendor
		if vendor == "ATA" {
			// ATA设备不是RAID设备
			continue
		}
		bus_path := b.BusPath
		hctl := b.HCTL
		parts := strings.Split(hctl, ":")
		if len(parts) == 4 {
			if string(parts[2]) == vd && strings.Contains(bus_path, pci) {
				return b, nil
			}
		}
	}
	return nil, nil
}

sysfs-modalias 硬件信息

wiki.archlinux.org/title/Modal…

Modalias是一个sysfs小技巧,它将硬件信息导出到一个名为modalias的文件中。


$ cat /sys/devices/pci0000:00/0000:00:1f.1/modalias

pci:v00008086d000024DBsv0000103Csd0000006Abc01sc01i8A

路径解释

  • pci0000:00: PCI ID

  • 0000:00:1f.1 :PCI总线上的索引,位于总线0000:00上,索引为1f.1,例如:

    • 
      $ lspci |grep 1f.1
      
      00:1f.1 IDE interface: Intel Corp.: Unknown device 24db (rev 02)
      
      

内容解释

根据供应商id和设备id可以在devicehunt.com/查找到相关信息


v  00008086 # vendor id 供应商id

d  000024DB # device id 设备id

sv 0000103C # subsystem vendor id 子系统供应商id (通常被忽略)

sd 0000006A # subsystem device id 子系统设备id (通常被忽略)

bc 01 # base class 基类

sc 01 # sub class 子类

i  8A # 编程接口

对应lspci


$ lspci -n |grep 1f.1

00:1f.1 Class 0101: 8086:24db (rev 02) # Class 0101对应IDE Interface

																			 # 8086对应Intel

																			 # 24db对应Unknown device,其实就是lspci的内容

运行depmod时,它会在/lib/modules/$(uname -r)/中构建一系列“映射”文件(如何构建的呢?就是从内核驱动中获取的),这些文件告诉modprobe如何处理它需要做的某些事情。


$ sudo grep megaraid_sas /lib/modules/$(uname -r)/modules.alias

alias pci:v00001000d0000001Csv*sd*bc*sc*i* megaraid_sas

alias pci:v00001000d0000001Bsv*sd*bc*sc*i* megaraid_sas

alias pci:v00001000d00000017sv*sd*bc*sc*i* megaraid_sas

alias pci:v00001000d00000016sv*sd*bc*sc*i* megaraid_sas

alias pci:v00001000d00000014sv*sd*bc*sc*i* megaraid_sas

alias pci:v00001000d00000053sv*sd*bc*sc*i* megaraid_sas

# 这些信息就是从驱动里面动态载入的

$ sudo modinfo megaraid_sas

filename:       /lib/modules/4.9.0-8-amd64/kernel/drivers/scsi/megaraid/megaraid_sas.ko

description:    Avago MegaRAID SAS Driver

author:         megaraidlinux.pdl@avagotech.com

version:        07.700.00.00-rc1

license:        GPL

srcversion:     470A16FC7EEFFB94387E241

alias:          pci:v00001000d0000001Csv*sd*bc*sc*i*

alias:          pci:v00001000d0000001Bsv*sd*bc*sc*i*

alias:          pci:v00001000d00000017sv*sd*bc*sc*i*

alias:          pci:v00001000d00000016sv*sd*bc*sc*i*

alias:          pci:v00001000d00000014sv*sd*bc*sc*i*

alias:          pci:v00001000d00000053sv*sd*bc*sc*i*

alias:          pci:v00001000d00000052sv*sd*bc*sc*i*

代码实现

编程时,我们有了modalias信息,就可以通过一些库来获取到设备信息,而不用使用各种cli来获取,一次io操作提高效率,例如:pcidb


type PCIDB struct {

	// hash of class ID -> class information

	Classes map[string]*Class `json:"classes"`

	// hash of vendor ID -> vendor information

	Vendors map[string]*Vendor `json:"vendors"`

	// hash of vendor ID + product/device ID -> product information

	Products map[string]*Product `json:"products"`

}

var db *pcidb.PCIDB

vendor := db.Vendors[vendorID]

fmt.Println(vendor.Name) // 厂商

product := db.Products[vendorID+productID]

fmt.Println(product.Name) // 产品