#!/usr/bin/perl # # lsmem - Tool to show memory hotplug status # # Copyright IBM Corp. 2010, 2017 # # s390-tools is free software; you can redistribute it and/or modify # it under the terms of the MIT license. See LICENSE for details. # use strict; use warnings; use Getopt::Long qw(:config no_ignore_case no_auto_abbrev); use File::Basename; my $script_name = fileparse($0); my $memdir = "/sys/devices/system/memory"; my $block_size = 0; my $list_all = 0; my $dev_size = 0; my @entries; sub lsmem_read_attr($$$$) # parameters: state, rem, device, block_nr { my @attributes = qw(state removable phys_device); foreach (0..2) { $_[$_] = `cat $memdir/memory$_[3]/$attributes[$_]`; chomp($_[$_]); } } sub lsmem_get_dev_size() { my ($device, $old_device, $block, $old_block) = (0, 0, 0, 0); foreach (@entries) { $_ =~ /memory(\d+)/; $block = $1; $device = `cat $_/phys_device`; chomp($device); if ($device > $old_device) { $dev_size = int((($block - $old_block) * $block_size) / ($device - $old_device)); last; } $dev_size += $block_size; $old_block = $block; } } sub lsmem_list() { my $block = 0; my ($start, $end, $size) = (0, 0, 0); my ($state, $next_state) = (0, 0); my ($rem, $next_rem) = (0, 0); my ($device, $next_device, $end_dev) = (0, 0, 0); my ($mem_online, $mem_offline) = (0, 0); my $mem_hole; $block_size = `cat $memdir/block_size_bytes`; chomp($block_size); if ($block_size =~ /(?:0x)?([[:xdigit:]]+)/) { $block_size = unpack("Q", pack("H16", substr("0" x 16 . $1, -16))); $block_size = $block_size >> 20; } else { die "lsmem: Unknown block size format in sysfs.\n"; } lsmem_get_dev_size(); # Start with $mem_hole = 1 to initialize $start, $state, $rem, $device $mem_hole = 1; print <> 20; if ($state eq "going-offline") { $state = "on->off"; } printf("0x%016x-0x%016x %10lu %-7s ", $start, $end, $size, $state); if ($state eq "online") { printf(" %-9s ", $rem ? "yes" : "no"); $mem_online += $size; } else { printf(" %-9s ", "-"); $mem_offline += $size; } $end_dev = ($end / $dev_size) >> 20; if ($device == $end_dev) { printf("%d\n", $device); } else { printf("%d-%d\n", $device, $end_dev); } $state = $next_state; $rem = $next_rem; $device = $end_dev + 1; $start = $end + 1; } } printf("\n"); printf("Memory device size : %lu MB\n", $dev_size); printf("Memory block size : %lu MB\n", $block_size); printf("Total online memory : %lu MB\n", $mem_online); printf("Total offline memory: %lu MB\n", $mem_offline); } sub lsmem_usage() { print < sub {lsmem_version(); exit 0;}, 'h|help' => sub {lsmem_usage(); exit 0;}, 'a|all' => \$list_all)) { die "Try '$script_name --help' for more information.\n"; }; @entries = (sort {length($a) <=> length($b) || $a cmp $b} <$memdir/memory*>); if (@entries == 0) { die "lsmem: No memory hotplug interface in sysfs ($memdir).\n"; } lsmem_list();