@@ -16,13 +16,13 @@ package blockdevice
1616import (
1717 "bufio"
1818 "fmt"
19- "github.com/prometheus/procfs/internal/util"
2019 "io"
2120 "io/ioutil"
2221 "os"
2322 "strings"
2423
2524 "github.com/prometheus/procfs/internal/fs"
25+ "github.com/prometheus/procfs/internal/util"
2626)
2727
2828// Info contains identifying information for a block device such as a disk drive.
@@ -178,12 +178,37 @@ type BlockQueueStats struct {
178178 WriteZeroesMaxBytes uint64
179179}
180180
181+ // DeviceMapperInfo models the devicemapper files that are located in the sysfs tree for each block device
182+ // and described in the kernel documentation:
183+ // https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-block-dm
184+ type DeviceMapperInfo struct {
185+ // Name is the string containing mapped device name.
186+ Name string
187+ // RqBasedSeqIOMergeDeadline determines how long (in microseconds) a request that is a reasonable merge
188+ // candidate can be queued on the request queue.
189+ RqBasedSeqIOMergeDeadline uint64
190+ // Suspended indicates if the device is suspended (1 is on, 0 is off).
191+ Suspended uint64
192+ // UseBlkMQ indicates if the device is using the request-based blk-mq I/O path mode (1 is on, 0 is off).
193+ UseBlkMQ uint64
194+ // UUID is the DM-UUID string or empty string if DM-UUID is not set.
195+ UUID string
196+ }
197+
198+ // UnderlyingDevices models the list of devices that this device is built from.
199+ type UnderlyingDeviceInfo struct {
200+ // DeviceNames is the list of devices names
201+ DeviceNames []string
202+ }
203+
181204const (
182205 procDiskstatsPath = "diskstats"
183206 procDiskstatsFormat = "%d %d %s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d"
184207 sysBlockPath = "block"
185208 sysBlockStatFormat = "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d"
186209 sysBlockQueue = "queue"
210+ sysBlockDM = "dm"
211+ sysUnderlyingDev = "slaves"
187212)
188213
189214// FS represents the pseudo-filesystems proc and sys, which provides an
@@ -317,7 +342,7 @@ func (fs FS) SysBlockDeviceStat(device string) (IOStats, int, error) {
317342// SysBlockDeviceQueueStats returns stats for /sys/block/xxx/queue where xxx is a device name.
318343func (fs FS ) SysBlockDeviceQueueStats (device string ) (BlockQueueStats , error ) {
319344 stat := BlockQueueStats {}
320- // files with uint64 fields
345+ // Files with uint64 fields
321346 for file , p := range map [string ]* uint64 {
322347 "add_random" : & stat .AddRandom ,
323348 "dax" : & stat .DAX ,
@@ -355,7 +380,7 @@ func (fs FS) SysBlockDeviceQueueStats(device string) (BlockQueueStats, error) {
355380 }
356381 * p = val
357382 }
358- // files with int64 fields
383+ // Files with int64 fields
359384 for file , p := range map [string ]* int64 {
360385 "io_poll_delay" : & stat .IOPollDelay ,
361386 "wbt_lat_usec" : & stat .WBTLatUSec ,
@@ -366,7 +391,7 @@ func (fs FS) SysBlockDeviceQueueStats(device string) (BlockQueueStats, error) {
366391 }
367392 * p = val
368393 }
369- // files with string fields
394+ // Files with string fields
370395 for file , p := range map [string ]* string {
371396 "write_cache" : & stat .WriteCache ,
372397 "zoned" : & stat .Zoned ,
@@ -398,3 +423,44 @@ func (fs FS) SysBlockDeviceQueueStats(device string) (BlockQueueStats, error) {
398423 }
399424 return stat , nil
400425}
426+
427+ func (fs FS ) SysBlockDeviceMapperInfo (device string ) (DeviceMapperInfo , error ) {
428+ info := DeviceMapperInfo {}
429+ // Files with uint64 fields
430+ for file , p := range map [string ]* uint64 {
431+ "rq_based_seq_io_merge_deadline" : & info .RqBasedSeqIOMergeDeadline ,
432+ "suspended" : & info .Suspended ,
433+ "use_blk_mq" : & info .UseBlkMQ ,
434+ } {
435+ val , err := util .ReadUintFromFile (fs .sys .Path (sysBlockPath , device , sysBlockDM , file ))
436+ if err != nil {
437+ return DeviceMapperInfo {}, err
438+ }
439+ * p = val
440+ }
441+ // Files with string fields
442+ for file , p := range map [string ]* string {
443+ "name" : & info .Name ,
444+ "uuid" : & info .UUID ,
445+ } {
446+ val , err := util .SysReadFile (fs .sys .Path (sysBlockPath , device , sysBlockDM , file ))
447+ if err != nil {
448+ return DeviceMapperInfo {}, err
449+ }
450+ * p = val
451+ }
452+ return info , nil
453+ }
454+
455+ func (fs FS ) SysBlockDeviceUnderlyingDevices (device string ) (UnderlyingDeviceInfo , error ) {
456+ underlyingDir , err := os .Open (fs .sys .Path (sysBlockPath , device , sysUnderlyingDev ))
457+ if err != nil {
458+ return UnderlyingDeviceInfo {}, err
459+ }
460+ underlying , err := underlyingDir .Readdirnames (0 )
461+ if err != nil {
462+ return UnderlyingDeviceInfo {}, err
463+ }
464+ return UnderlyingDeviceInfo {DeviceNames : underlying }, nil
465+
466+ }
0 commit comments