Skip to content

Commit

Permalink
only process memory cell/block subdirs in sysfs
Browse files Browse the repository at this point in the history
The `/sys/devices/system/memory` and `/sys/devices/system/node/nodeX`
subdirectories contains one or more subdirectories that begin with the
word "memory" and end in a 0-based cell/block index for that memory.
e.g. `/sys/devices/system/node/node0/memory63` is a directory containing
information files about the 64th memory block in NUMA node 0.

Previously, code that gathered total physical memory by looking at these
subdirectories was using a simple glob on `memory*` to determine those
memory block subdirectories. However, in some recent Linux kernels a
`/sys/devices/system/memory/memory_failure` file causes that simple glob
to backfire. This patch replaces the simple glob with a read of the
`/sys/devices/system/memory` or `/sys/devices/system/node/nodeX`
directory and regex matches on `memory\d$` to determine if the
subdirectory is a memory block one.

Fixes Issue #341

Signed-off-by: Jay Pipes <[email protected]>
  • Loading branch information
jaypipes committed May 6, 2023
1 parent 3ff88ab commit 22be3f7
Showing 1 changed file with 28 additions and 16 deletions.
44 changes: 28 additions & 16 deletions pkg/memory/memory_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ var (
// System log lines will look similar to the following:
// ... kernel: [0.000000] Memory: 24633272K/25155024K ...
_REGEX_SYSLOG_MEMLINE = regexp.MustCompile(`Memory:\s+\d+K\/(\d+)K`)
// regexMemoryBlockDirname matches a subdirectory in either
// /sys/devices/system/memory or /sys/devices/system/node/nodeX that
// represents information on a specific memory cell/block
regexMemoryBlockDirname = regexp.MustCompile(`memory\d+$`)
)

func (i *Info) load() error {
Expand Down Expand Up @@ -137,29 +141,37 @@ func memTotalPhysicalBytes(paths *linuxpath.Paths) (total int64) {
return total
}

// memoryTotalPhysicalBytesFromPath accepts a directory -- either
// /sys/devices/system/memory (for the entire system) or
// /sys/devices/system/node/nodeX (for a specific NUMA node) -- and a block
// size in bytes and iterates over the sysfs memory block subdirectories,
// accumulating blocks that are "online" to determine a total physical memory
// size in bytes
func memoryTotalPhysicalBytesFromPath(dir string, blockSizeBytes uint64) (int64, error) {
// iterate over memory's block /sys/.../memory*,
// if the memory block state is 'online' we increment the total
// with the memory block size to determine the amount of physical
// memory available on this system.
// This works for both system-wide:
// /sys/devices/system/memory/memory*
// and for per-numa-node report:
// /sys/devices/system/node/node*/memory*

sysMemory, err := filepath.Glob(filepath.Join(dir, "memory*"))
var total int64
files, err := ioutil.ReadDir(dir)
if err != nil {
return -1, err
} else if sysMemory == nil {
return -1, fmt.Errorf("cannot find memory entries in %q", dir)
}

var total int64
for _, path := range sysMemory {
s, err := ioutil.ReadFile(filepath.Join(path, "state"))
// There are many subdirectories of /sys/devices/system/memory or
// /sys/devices/system/node/nodeX that are named memory{cell} where {cell}
// is a 0-based index of the memory block. These subdirectories contain a
// state file (e.g. /sys/devices/system/memory/memory64/state that will
// contain the string "online" if that block is active.
for _, file := range files {
fname := file.Name()
// NOTE(jaypipes): we cannot rely on file.IsDir() here because the
// memory{cell} sysfs directories are not actual directories.
if !regexMemoryBlockDirname.MatchString(fname) {
continue
}
s, err := ioutil.ReadFile(filepath.Join(dir, fname, "state"))
if err != nil {
return -1, err
}
// if the memory block state is 'online' we increment the total with
// the memory block size to determine the amount of physical
// memory available on this system.
if strings.TrimSpace(string(s)) != "online" {
continue
}
Expand Down

0 comments on commit 22be3f7

Please sign in to comment.