Repository: prometheus/procfs
Pull request #299 (2020-05-20 08:47:22)

parse sys/block/xxx/queue
Signed-off-by: binjip978 <binjip978@gmail.com>

binjip978: should fix https://github.com/prometheus/procfs/issues/266

Patch:
diff --git a/blockdevice/stats.go b/blockdevice/stats.go
index 1381d6c..1e826f8 100644
--- a/blockdevice/stats.go
+++ b/blockdevice/stats.go
@@ -16,6 +16,7 @@ package blockdevice
 import (
 	"bufio"
 	"fmt"
+	"github.com/prometheus/procfs/internal/util"
 	"io"
 	"io/ioutil"
 	"os"
@@ -86,11 +87,103 @@ type Diskstats struct {
 	IoStatsCount int
 }
 
+// BlockQueueStats models the queue files that are located in the sysfs tree for each block device
+// and described in the kernel documentation:
+// https://www.kernel.org/doc/Documentation/block/queue-sysfs.txt
+// https://www.kernel.org/doc/html/latest/block/queue-sysfs.html
+type BlockQueueStats struct {
+	// AddRandom is the status of a disk entropy (1 is on, 0 is off).
+	AddRandom uint64
+	// Dax indicates whether the device supports Direct Access (DAX) (1 is on, 0 is off).
+	DAX uint64
+	// DiscardGranularity is the size of internal allocation of the device in bytes, 0 means device
+	// does not support the discard functionality.
+	DiscardGranularity uint64
+	// DiscardMaxHWBytes is the hardware maximum number of bytes that can be discarded in a single operation,
+	// 0 means device does not support the discard functionality.
+	DiscardMaxHWBytes uint64
+	// DiscardMaxBytes is the software maximum number of bytes that can be discarded in a single operation.
+	DiscardMaxBytes uint64
+	// HWSectorSize is the sector size of the device, in bytes.
+	HWSectorSize uint64
+	// IOPoll indicates if polling is enabled (1 is on, 0 is off).
+	IOPoll uint64
+	// IOPollDelay indicates how polling will be performed, -1 for classic polling, 0 for hybrid polling,
+	// with greater than 0 the kernel will put process issuing IO to sleep for this amount of time in
+	// microseconds before entering classic polling.
+	IOPollDelay int64
+	// IOTimeout is the request timeout in milliseconds.
+	IOTimeout uint64
+	// IOStats indicates if iostats accounting is used for the disk (1 is on, 0 is off).
+	IOStats uint64
+	// LogicalBlockSize is the logical block size of the device, in bytes.
+	LogicalBlockSize uint64
+	// MaxHWSectorsKB is the maximum number of kilobytes supported in a single data transfer.
+	MaxHWSectorsKB uint64
+	// MaxIntegritySegments is the max limit of integrity segments as set by block layer which a hardware controller
+	// can handle.
+	MaxIntegritySegments uint64
+	// MaxSectorsKB is the maximum number of kilobytes that the block layer will allow for a filesystem request.
+	MaxSectorsKB uint64
+	// MaxSegments is the number of segments on the device.
+	MaxSegments uint64
+	// MaxSegmentsSize is the maximum segment size of the device.
+	MaxSegmentSize uint64
+	// MinimumIOSize is the smallest preferred IO size reported by the device.
+	MinimumIOSize uint64
+	// NoMerges shows the lookup logic involved with IO merging requests in the block layer. 0 all merges are
+	// enabled, 1 only simple one hit merges are tried, 2 no merge algorithms will be tried.
+	NoMerges uint64
+	// NRRequests is the number of how many requests may be allocated in the block layer for read or write requests.
+	NRRequests uint64
+	// OptimalIOSize is the optimal IO size reported by the device.
+	OptimalIOSize uint64
+	// PhysicalBlockSize is the physical block size of device, in bytes.
+	PhysicalBlockSize uint64
+	// ReadAHeadKB is the maximum number of kilobytes to read-ahead for filesystems on this block device.
+	ReadAHeadKB uint64
+	// Rotational indicates if the device is of rotational type or non-rotational type.
+	Rotational uint64
+	// RQAffinity indicates affinity policy of device, if 1 the block layer will migrate request completions to the
+	// cpu “group” that originally submitted the request, if 2 forces the completion to run on the requesting cpu.
+	RQAffinity uint64
+	// SchedulerList contains list of available schedulers for this block device.
+	SchedulerList []string
+	// SchedulerCurrent is the current scheduler for this block device.
+	SchedulerCurrent string
+	// WriteCache shows the type of cache for block device, "write back" or "write through".
+	WriteCache string
+	// WriteSameMaxBytes is the number of bytes the device can write in a single write-same command.
+	// A value of ‘0’ means write-same is not supported by this device.
+	WriteSameMaxBytes uint64
+	// WBTLatUSec is the target minimum read latency, 0 means feature is disables.
+	WBTLatUSec int64
+	// ThrottleSampleTime is the time window that blk-throttle samples data, in millisecond. Optional
+	// exists only if CONFIG_BLK_DEV_THROTTLING_LOW is enabled.
+	ThrottleSampleTime *uint64
+	// Zoned indicates if the device is a zoned block device and the zone model of the device if it is indeed zoned.
+	// Possible values are: none, host-aware, host-managed for zoned block devices.
+	Zoned string
+	// NRZones indicates the total number of zones of the device, always zero for regular block devices.
+	NRZones uint64
+	// ChunksSectors for RAID is the size in 512B sectors of the RAID volume stripe segment,
+	// for zoned host device is the size in 512B sectors.
+	ChunkSectors uint64
+	// FUA indicates whether the device supports Force Unit Access for write requests.
+	FUA uint64
+	// MaxDiscardSegments is the maximum number of DMA entries in a discard request.
+	MaxDiscardSegments uint64
+	// WriteZeroesMaxBytes the maximum number of bytes that can be zeroed at once.
+	// The value 0 means that REQ_OP_WRITE_ZEROES is not supported.
+	WriteZeroesMaxBytes uint64
+}
+
 const (
 	procDiskstatsPath   = "diskstats"
 	procDiskstatsFormat = "%d %d %s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d"
 	sysBlockPath        = "block"
 	sysBlockStatFormat  = "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d"
+	sysBlockQueue       = "queue"
 )
 
 // FS represents the pseudo-filesystems proc and sys, which provides an
@@ -220,3 +313,88 @@ func (fs FS) SysBlockDeviceStat(device string) (IOStats, int, error) {
 	}
 	return stat, count, err
 }
+
+// SysBlockDeviceQueueStats returns stats for /sys/block/xxx/queue where xxx is a device name.
+func (fs FS) SysBlockDeviceQueueStats(device string) (BlockQueueStats, error) {
+	stat := BlockQueueStats{}
+	// files with uint64 fields
+	for file, p := range map[string]*uint64{
+		"add_random":             &stat.AddRandom,
+		"dax":                    &stat.DAX,
+		"discard_granularity":    &stat.DiscardGranularity,
+		"discard_max_hw_bytes":   &stat.DiscardMaxHWBytes,
+		"discard_max_bytes":      &stat.DiscardMaxBytes,
+		"hw_sector_size":         &stat.HWSectorSize,
+		"io_poll":                &stat.IOPoll,
+		"io_timeout":             &stat.IOTimeout,
+		"iostats":                &stat.IOStats,
+		"logical_block_size":     &stat.LogicalBlockSize,
+		"max_hw_sectors_kb":      &stat.MaxHWSectorsKB,
+		"max_integrity_segments": &stat.MaxIntegritySegments,
+		"max_sectors_kb":         &stat.MaxSectorsKB,
+		"max_segments":           &stat.MaxSegments,
+		"max_segment_size":       &stat.MaxSegmentSize,
+		"minimum_io_size":        &stat.MinimumIOSize,
+		"nomerges":               &stat.NoMerges,
+		"nr_requests":            &stat.NRRequests,
+		"optimal_io_size":        &stat.OptimalIOSize,
+		"physical_block_size":    &stat.PhysicalBlockSize,
+		"read_ahead_kb":          &stat.ReadAHeadKB,
+		"rotational":             &stat.Rotational,
+		"rq_affinity":            &stat.RQAffinity,
+		"write_same_max_bytes":   &stat.WriteSameMaxBytes,
+		"nr_zones":               &stat.NRZones,
+		"chunk_sectors":          &stat.ChunkSectors,
+		"fua":                    &stat.FUA,
+		"max_discard_segments":   &stat.MaxDiscardSegments,
+		"write_zeroes_max_bytes": &stat.WriteZeroesMaxBytes,
+	} {
+		val, err := util.ReadUintFromFile(fs.sys.Path(sysBlockPath, device, sysBlockQueue, file))
+		if err != nil {
+			return BlockQueueStats{}, err
+		}
+		*p = val
+	}
+	// files with int64 fields
+	for file, p := range map[string]*int64{
+		"io_poll_delay": &stat.IOPollDelay,
+		"wbt_lat_usec":  &stat.WBTLatUSec,
+	} {
+		val, err := util.ReadIntFromFile(fs.sys.Path(sysBlockPath, device, sysBlockQueue, file))
+		if err != nil {
+			return BlockQueueStats{}, err
+		}
+		*p = val
+	}
+	// files with string fields
+	for file, p := range map[string]*string{
+		"write_cache": &stat.WriteCache,
+		"zoned":       &stat.Zoned,
+	} {
+		val, err := util.SysReadFile(fs.sys.Path(sysBlockPath, device, sysBlockQueue, file))
+		if err != nil {
+			return BlockQueueStats{}, err
+		}
+		*p = val
+	}
+	scheduler, err := util.SysReadFile(fs.sys.Path(sysBlockPath, device, sysBlockQueue, "scheduler"))
+	if err != nil {
+		return BlockQueueStats{}, err
+	}
+	var schedulers []string
+	xs := strings.Split(scheduler, " ")
+	for _, s := range xs {
+		if strings.HasPrefix(s, "[") && strings.HasSuffix(s, "]") {
+			s = s[1 : len(s)-1]
+			stat.SchedulerCurrent = s
+		}
+		schedulers = append(schedulers, s)
+	}
+	stat.SchedulerList = schedulers
+	// optional
+	throttleSampleTime, err := util.ReadUintFromFile(fs.sys.Path(sysBlockPath, device, sysBlockQueue, "throttle_sample_time"))
+	if err == nil {
+		stat.ThrottleSampleTime = &throttleSampleTime
+	}
+	return stat, nil
+}
diff --git a/cpuinfo.go b/cpuinfo.go
index bb3be99..d19ce85 100644
--- a/cpuinfo.go
+++ b/cpuinfo.go
@@ -190,15 +190,26 @@ func parseCPUInfoARM(info []byte) ([]CPUInfo, error) {
 	scanner := bufio.NewScanner(bytes.NewReader(info))
 
 	firstLine := firstNonEmptyLine(scanner)
-	if !strings.HasPrefix(firstLine, "Processor") || !strings.Contains(firstLine, ":") {
+	match, _ := regexp.MatchString("^[Pp]rocessor", firstLine)
+	if !match || !strings.Contains(firstLine, ":") {
 		return nil, errors.New("invalid cpuinfo file: " + firstLine)
 	}
 	field := strings.SplitN(firstLine, ": ", 2)
-	commonCPUInfo := CPUInfo{VendorID: field[1]}
-
 	cpuinfo := []CPUInfo{}
-	i := -1
 	featuresLine := ""
+	commonCPUInfo := CPUInfo{}
+	i := 0
+	if strings.TrimSpace(field[0]) == "Processor" {
+		commonCPUInfo = CPUInfo{ModelName: field[1]}
+		i = -1
+	} else {
+		v, err := strconv.ParseUint(field[1], 0, 32)
+		if err != nil {
+			return nil, err
+		}
+		firstcpu := CPUInfo{Processor: uint(v)}
+		cpuinfo = []CPUInfo{firstcpu}
+	}
 
 	for scanner.Scan() {
 		line := scanner.Text()
@@ -216,6 +227,11 @@ func parseCPUInfoARM(info []byte) ([]CPUInfo, error) {
 			}
 			cpuinfo[i].Processor = uint(v)
 		case "BogoMIPS":
+			if i == -1 {
+				cpuinfo = append(cpuinfo, commonCPUInfo) // There is only one processor
+				i++
+				cpuinfo[i].Processor = 0
+			}
 			v, err := strconv.ParseFloat(field[1], 64)
 			if err != nil {
 				return nil, err
@@ -223,6 +239,8 @@ func parseCPUInfoARM(info []byte) ([]CPUInfo, error) {
 			cpuinfo[i].BogoMips = v
 		case "Features":
 			featuresLine = line
+		case "model name":
+			cpuinfo[i].ModelName = field[1]
 		}
 	}
 	fields := strings.SplitN(featuresLine, ": ", 2)
@@ -230,6 +248,7 @@ func parseCPUInfoARM(info []byte) ([]CPUInfo, error) {
 		cpuinfo[i].Flags = strings.Fields(fields[1])
 	}
 	return cpuinfo, nil
+
 }
 
 func parseCPUInfoS390X(info []byte) ([]CPUInfo, error) {
diff --git a/fixtures.ttar b/fixtures.ttar
index 8555871..97f1f92 100644
--- a/fixtures.ttar
+++ b/fixtures.ttar
@@ -2847,6 +2847,237 @@ Mode: 664
 Directory: fixtures/sys/block/sda
 Mode: 775
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/block/sda/queue
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/add_random
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/chunk_sectors
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/dax
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/discard_granularity
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/discard_max_bytes
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/discard_max_hw_bytes
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/discard_zeroes_data
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/fua
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/hw_sector_size
+Lines: 1
+512
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/io_poll
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/io_poll_delay
+Lines: 1
+-1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/io_timeout
+Lines: 1
+30000
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/block/sda/queue/iosched
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/iosched/back_seek_max
+Lines: 1
+16384
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/iosched/back_seek_penalty
+Lines: 1
+2
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/iosched/fifo_expire_async
+Lines: 1
+250
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/iosched/fifo_expire_sync
+Lines: 1
+125
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/iosched/low_latency
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/iosched/max_budget
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/iosched/slice_idle
+Lines: 1
+8
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/iosched/slice_idle_us
+Lines: 1
+8000
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/iosched/strict_guarantees
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/iosched/timeout_sync
+Lines: 1
+125
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/iostats
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/logical_block_size
+Lines: 1
+512
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/max_discard_segments
+Lines: 1
+1
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/max_hw_sectors_kb
+Lines: 1
+32767
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/max_integrity_segments
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/max_sectors_kb
+Lines: 1
+1280
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/max_segment_size
+Lines: 1
+65536
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/max_segments
+Lines: 1
+168
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/minimum_io_size
+Lines: 1
+512
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/nomerges
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/nr_requests
+Lines: 1
+64
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/nr_zones
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/optimal_io_size
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/physical_block_size
+Lines: 1
+512
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/read_ahead_kb
+Lines: 1
+128
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/rotational
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/rq_affinity
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/scheduler
+Lines: 1
+mq-deadline kyber [bfq] none
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/wbt_lat_usec
+Lines: 1
+75000
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/write_cache
+Lines: 1
+write back
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/write_same_max_bytes
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/write_zeroes_max_bytes
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/queue/zoned
+Lines: 1
+none
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Path: fixtures/sys/block/sda/stat
 Lines: 1
 9652963   396792 759304206   412943  8422549  6731723 286915323 13947418        0  5658367 19174573 1 2 3 12


Test patch:
diff --git a/blockdevice/stats_test.go b/blockdevice/stats_test.go
index d90b668..c0a5768 100644
--- a/blockdevice/stats_test.go
+++ b/blockdevice/stats_test.go
@@ -14,6 +14,7 @@
 package blockdevice
 
 import (
+	"reflect"
 	"testing"
 )
 
@@ -104,4 +105,50 @@ func TestBlockDevice(t *testing.T) {
 	if device1stats.DiscardTicks != 12 {
 		t.Errorf(failMsgFormat, "Incorrect discard ticks", 12, device1stats.DiscardTicks)
 	}
+	blockQueueStatExpected := BlockQueueStats{
+		AddRandom:            1,
+		DAX:                  0,
+		DiscardGranularity:   0,
+		DiscardMaxHWBytes:    0,
+		DiscardMaxBytes:      0,
+		HWSectorSize:         512,
+		IOPoll:               0,
+		IOPollDelay:          -1,
+		IOTimeout:            30000,
+		IOStats:              1,
+		LogicalBlockSize:     512,
+		MaxHWSectorsKB:       32767,
+		MaxIntegritySegments: 0,
+		MaxSectorsKB:         1280,
+		MaxSegments:          168,
+		MaxSegmentSize:       65536,
+		MinimumIOSize:        512,
+		NoMerges:             0,
+		NRRequests:           64,
+		OptimalIOSize:        0,
+		PhysicalBlockSize:    512,
+		ReadAHeadKB:          128,
+		Rotational:           1,
+		RQAffinity:           1,
+		SchedulerList:        []string{"mq-deadline", "kyber", "bfq", "none"},
+		SchedulerCurrent:     "bfq",
+		WriteCache:           "write back",
+		WriteSameMaxBytes:    0,
+		WBTLatUSec:           75000,
+		ThrottleSampleTime:   nil,
+		Zoned:                "none",
+		NRZones:              0,
+		ChunkSectors:         0,
+		FUA:                  0,
+		MaxDiscardSegments:   1,
+		WriteZeroesMaxBytes:  0,
+	}
+
+	blockQueueStat, err := blockdevice.SysBlockDeviceQueueStats(devices[1])
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !reflect.DeepEqual(blockQueueStat, blockQueueStatExpected) {
+		t.Errorf("Incorrect BlockQueueStat, expected: \n%+v, got: \n%+v", blockQueueStatExpected, blockQueueStat)
+	}
 }
diff --git a/cpuinfo_test.go b/cpuinfo_test.go
index b6869ac..17eefbe 100644
--- a/cpuinfo_test.go
+++ b/cpuinfo_test.go
@@ -18,7 +18,7 @@ package procfs
 import "testing"
 
 const (
-	cpuinfoArm7 = `
+	cpuinfoArm7Legacy = `
 Processor : ARMv7 Processor rev 5 (v7l)
 processor : 0
 BogoMIPS : 2400.00
@@ -37,6 +37,65 @@ Hardware : sun8i
 Revision : 0000
 Serial : 5400503583203c3c040e`
 
+	cpuinfoArm7LegacyV1 = `
+Processor       : ARMv6-compatible processor rev 5 (v6l)
+BogoMIPS        : 791.34
+Features        : swp half thumb fastmult vfp edsp java 
+CPU implementer : 0x41
+CPU architecture: 6TEJ
+CPU variant     : 0x1
+CPU part        : 0xb36
+CPU revision    : 5
+
+Hardware        : IMAPX200
+Revision        : 0000
+Serial          : 0000000000000000`
+
+	cpuinfoArm7 = `
+processor : 0
+model name : ARMv7 Processor rev 3 (v7l)
+BogoMIPS : 108.00
+Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
+CPU implementer : 0x41
+CPU architecture: 7
+CPU variant : 0x0
+CPU part : 0xd08
+CPU revision : 3
+
+processor : 1
+model name : ARMv7 Processor rev 3 (v7l)
+BogoMIPS : 108.00
+Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
+CPU implementer : 0x41
+CPU architecture: 7
+CPU variant : 0x0
+CPU part : 0xd08
+CPU revision : 3
+
+processor : 2
+model name : ARMv7 Processor rev 3 (v7l)
+BogoMIPS : 108.00
+Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
+CPU implementer : 0x41
+CPU architecture: 7
+CPU variant : 0x0
+CPU part : 0xd08
+CPU revision : 3
+
+processor : 3
+model name : ARMv7 Processor rev 3 (v7l)
+BogoMIPS : 108.00
+Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
+CPU implementer : 0x41
+CPU architecture: 7
+CPU variant : 0x0
+CPU part : 0xd08
+CPU revision : 3
+
+Hardware : BCM2835
+Revision : c03111
+`
+
 	cpuinfoS390x = `
 vendor_id       : IBM/S390
 # processors    : 4
@@ -153,15 +212,15 @@ func TestCPUInfoX86(t *testing.T) {
 	}
 }
 
-func TestCPUInfoParseARM(t *testing.T) {
-	cpuinfo, err := parseCPUInfoARM([]byte(cpuinfoArm7))
+func TestCPUInfoParseARMLegacy(t *testing.T) {
+	cpuinfo, err := parseCPUInfoARM([]byte(cpuinfoArm7Legacy))
 	if err != nil || cpuinfo == nil {
 		t.Fatalf("unable to parse arm cpu info: %v", err)
 	}
 	if want, have := 2, len(cpuinfo); want != have {
 		t.Errorf("want number of processors %v, have %v", want, have)
 	}
-	if want, have := "ARMv7 Processor rev 5 (v7l)", cpuinfo[0].VendorID; want != have {
+	if want, have := "ARMv7 Processor rev 5 (v7l)", cpuinfo[0].ModelName; want != have {
 		t.Errorf("want vendor %v, have %v", want, have)
 	}
 	if want, have := "thumb", cpuinfo[1].Flags[2]; want != have {
@@ -169,6 +228,38 @@ func TestCPUInfoParseARM(t *testing.T) {
 	}
 }
 
+func TestCPUInfoParseARMLegacyV1(t *testing.T) {
+	cpuinfo, err := parseCPUInfoARM([]byte(cpuinfoArm7LegacyV1))
+	if err != nil || cpuinfo == nil {
+		t.Fatalf("unable to parse arm cpu info: %v", err)
+	}
+	if want, have := 1, len(cpuinfo); want != have {
+		t.Errorf("want number of processors %v, have %v", want, have)
+	}
+	if want, have := "ARMv6-compatible processor rev 5 (v6l)", cpuinfo[0].ModelName; want != have {
+		t.Errorf("want vendor %v, have %v", want, have)
+	}
+	if want, have := "thumb", cpuinfo[0].Flags[2]; want != have {
+		t.Errorf("want flag %v, have %v", want, have)
+	}
+}
+
+func TestCPUInfoParseARM(t *testing.T) {
+	cpuinfo, err := parseCPUInfoARM([]byte(cpuinfoArm7))
+	if err != nil || cpuinfo == nil {
+		t.Fatalf("unable to parse arm cpu info: %v", err)
+	}
+	if want, have := 4, len(cpuinfo); want != have {
+		t.Errorf("want number of processors %v, have %v", want, have)
+	}
+	if want, have := "ARMv7 Processor rev 3 (v7l)", cpuinfo[0].ModelName; want != have {
+		t.Errorf("want vendor %v, have %v", want, have)
+	}
+	if want, have := "thumb", cpuinfo[1].Flags[1]; want != have {
+		t.Errorf("want flag %v, have %v", want, have)
+	}
+}
+
 func TestCPUInfoParseS390X(t *testing.T) {
 	cpuinfo, err := parseCPUInfoS390X([]byte(cpuinfoS390x))
 	if err != nil || cpuinfo == nil {