@tony-yin
        
        2019-01-14T06:20:55.000000Z
        字数 4609
        阅读 2338
    Megaraid

早前写过一篇【利用Raid卡工具获取逻辑盘是否为SSD】的文章,大概讲述了如何通过raid卡工具判断一个逻辑磁盘对应物理磁盘是否为SSD,当时主要提到了megacli和sas3ircu这两种工具,核心是如何通过raid卡工具定位到逻辑磁盘对应的物理磁盘的位置,当时的方式现在看来在有些场景会存在缺陷。
当时的方案主要是先通过lspci获取raid卡型号,然后找到对应的raid卡型号,紧接着通过lsscsi命令获取逻辑磁盘的targetid,再通过raid卡工具根据targetid定位到对应的物理盘。当时的方案在多controller的场景下存在问题,可能会出现重复target id的情况,所以这时候只能再借助controller id来定位唯一的磁盘了。总而言之,想真正定位逻辑磁盘对应的物理磁盘,就必须要获取到磁盘的controller id,enclosure id和slot number,有了这三个参数,便可以获取该磁盘的信息,或者对该物理磁盘进行点灯、响音和做raid等操作。
那么,具体如何定位逻辑磁盘的物理位置呢?且看下文分析
通过lspci命令可以获取到操作系统上所有raid卡信息,我们可以看到每个raid卡最前面都有一串数字,比如第一行是02:00.0,第二行是03:00.0,这里的02和03表示的是raid卡的busid,即raid卡控制器在pci总线上的id。
[root@tony ~]# lspci | grep "LSI Logic"02:00.0 RAID bus controller: LSI Logic / Symbios Logic MegaRAID SAS-3 3008 [Fury] (rev 02)03:00.0 RAID bus controller: LSI Logic / Symbios Logic MegaRAID SAS-3 3108 [Invader] (rev 02)
在linux中,一切皆文件,每个文件都有自己的唯一标识,对于磁盘而言,pcipath就是它的唯一标识,pci总线上面有很多控制器,比如scsi控制器,而磁盘又存在于scsi控制器上,所以我们可以在lsscsi命令获取到的scsi设备列表中查看到操作系统上的磁盘信息。
以sda为例,我们可以在/dev/disk/by-path目录下查看到磁盘的pcipath
[root@tony ~]# ll /dev/disk/by-path/total 4lrwxrwxrwx 1 root root 9 May 11 10:30 pci-0000:02:00.0-scsi-0:2:0:0 -> ../../sdalrwxrwxrwx 1 root root 10 May 11 10:30 pci-0000:02:00.0-scsi-0:2:0:0-part1 -> ../../sda1lrwxrwxrwx 1 root root 10 May 11 10:30 pci-0000:02:00.0-scsi-0:2:0:0-part2 -> ../../sda2lrwxrwxrwx 1 root root 9 May 11 16:22 pci-0000:02:00.0-scsi-0:2:1:0 -> ../../sdblrwxrwxrwx 1 root root 9 May 11 16:22 pci-0000:02:00.0-scsi-0:2:10:0 -> ../../sdk
由于在linux中,udev是用户态的设备管理,所以我们也可以通过udev获取。
[root@tony ~]# udevadm info --query=symlink --name=sdadisk/by-id/scsi-36509a4c0ac86790022337b9105005435 disk/by-id/wwn-0x6509a4c0ac86790022337b9105005435 disk/by-path/pci-0000:02:00.0-scsi-0:2:0:0
这边我们可以得到磁盘sda的pcipath为pci-0000:02:00.0-scsi-0:2:0:0,02就是磁盘的raid卡的bus id,后面的00表示channel id,再后面的0:2:0:0就和lsscsi获取的一样了,其中2就表示target id。
所以通过bud id,我们可以获取到磁盘对应的raid卡型号,根据对应的raid卡工具操作磁盘。这边我们只讨论megaraid,所以工具也就是megacli了。
上面我们获取到了磁盘的target id和对应raid卡的bus id,而对于megacli工具而言,每个raid卡都有一个与之对应的controller。
[root@tony ~]# /opt/MegaRAID/MegaCli/MegaCli64 -AdpGetPciInfo -aall -NoLogPCI information for Controller 0--------------------------------Bus Number : 2Device Number : 0Function Number : 0PCI information for Controller 1--------------------------------Bus Number : 3Device Number : 0Function Number : 0Exit Code: 0x00
这边我们可以看到megacli获取到了两个controller,也就对应上面lspci获取到的两张raid卡。细心的朋友可以发现这边有一个Bus Number,分别为2和3,而我们上面获取到了raid卡的bus id分别为02和03,没错,这边的Bus Number和bus id是对应的,只是Bus number没有自动填补成两位数,所以我们可以通过bus id得到sda所对应的controller为0。
注意:
原本系统中版本8.07.07的megacli工具获取raid卡信息的时候会存在问题,每次Bus Number都会变化,我们只要升级megacli即可,我这边是把megacli升级到了8.07.14版本。安装包地址:https://github.com/tony-yin/Megaraid_location/blob/master/MegaCli-8.07.14-1.noarch.rpm
此时,我们拥有了controller id,可以获取该controller下所有的磁盘组信息。
[root@tony ~]# /opt/MegaRAID_new/MegaCli/MegaCli64 -LdPdInfo -a0 -NoLogAdapter #0Number of Virtual Disks: 13Virtual Drive: 0 (Target Id: 0)Name :RAID Level : Primary-1, Secondary-0, RAID Level Qualifier-0Size : 558.375 GBSector Size : 512Is VD emulated : NoMirror Data : 558.375 GBState : OptimalStrip Size : 64 KBNumber Of Drives : 2Span Depth : 1Default Cache Policy: WriteThrough, ReadAheadNone, Direct, No Write Cache if Bad BBUCurrent Cache Policy: WriteThrough, ReadAheadNone, Direct, No Write Cache if Bad BBUDefault Access Policy: Read/WriteCurrent Access Policy: Read/WriteDisk Cache Policy : Disk's DefaultEncryption Type : NoneDefault Power Savings Policy: Controller DefinedCurrent Power Savings Policy: NoneCan spin up in 1 minute: YesLD has drives that support T10 power conditions: YesLD's IO profile supports MAX power savings with cached writes: NoBad Blocks Exist: NoIs VD Cached: NoNumber of Spans: 1Span: 0 - Number of PDs: 2PD: 0 InformationEnclosure Device ID: 32Slot Number: 12Drive's position: DiskGroup: 0, Span: 0, Arm: 0Enclosure position: 1Device Id: 12WWN: 50000398181A974CSequence Number: 2Media Error Count: 0Other Error Count: 0Predictive Failure Count: 0Last Predictive Failure Event Seq Number: 0PD Type: SAS......
然后我们可以根据target id获取对应的磁盘组信息,target id与上面的Target Id所对应,这样我们可以过滤得到唯一的磁盘组信息。这边我们可以看到sda对应Target Id为0的磁盘组,该raid类型为raid1,虚拟磁盘组中有两块物理盘,然后我们可以获取这两块物理盘的enclosure id和slot number,这样再加上前文的controller id,我们就可以完完全全地定位到具体一块磁盘的物理位置。
针对这种需求,本人根据以上逻辑写了一个简单的脚本可以一键获取磁盘的定位。
[root@tony ~]# ./get_disk_location.py sda['0:32:12', '0:32:13']
这边0:32:12分别表示磁盘的controller id,enclosure id和slot number。
之前的做法大部分场景可行,但是在一些场合偶尔会发现问题,总感觉还是不够靠谱,还有通过sda,sdb这种排列顺序来查找和megacli中显示磁盘的对应关系的,也不靠谱。linux操作系统是可以识别到具体硬件设备的,所以是肯定存在方法识别硬件对应的逻辑设备的,本文通过pcipath获取到设备的唯一标识,然后根据pcipath中的bus id和megacli中的cobtroller建立连接,最后通过target id锁定唯一磁盘组中的磁盘信息。
通过这种方式,我们不需要肉眼判断,也不需要顾虑部分场景方案不适用,这完全就是操作系统使用的方式,使用这种最基础,最底层的方式实现,真是让人豁然开朗。这跟看源码类似,了解一个功能的背后具体实现,你才知道最正确的姿势,不用去碰,去凑,这种感觉真好。
给大家推荐一本书《Linux设备驱动程序》,这本书详细讲解了linux中各种设备与驱动的细节,很底层也很枯燥,不过看完后应该会很有收获。希望大家在使用各种已有工具和框架的基础上,多去了解背后的实现机制,这样可以帮助我们更好地实现更深层次的需求。