File s390-tools-sles11sp2-lsmem-chmem-memory_hole.patch of Package s390-tools

Description: lsmem/chmem: Fix handling of memory holes
Symptom:     When using memory holes, lsmem doesn't show the memory after a
             hole and chmem doesn't work.
Problem:     Wrong assumption that memory block numbers are contiguous.
Solution:    Make it work with non-contiguous memory block numbers.
Problem-ID:  75392
---
 zconf/chmem |   40 ++++++++++++++------------
 zconf/lsmem |   89 +++++++++++++++++++++++++++++++++---------------------------
 2 files changed, 72 insertions(+), 57 deletions(-)

--- a/zconf/chmem
+++ b/zconf/chmem
@@ -2,7 +2,7 @@
 ###############################################################################
 # chmem - script to show memory hotplug status.
 #
-# Copyright IBM Corp. 2010
+# Copyright IBM Corp. 2010, 2011
 # Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com>
 ###############################################################################
 
@@ -22,6 +22,7 @@ my $dev_size;
 my $blocks_per_dev = 0;
 my $devs_per_block = 0;
 my $ret = 0;
+my @entries;
 
 sub chmem_usage()
 {
@@ -60,24 +61,24 @@ HERE
 sub chmem_version()
 {
 	print "$script_name: version %S390_TOOLS_VERSION%\n";
-	print "Copyright IBM Corp. 2010\n";
+	print "Copyright IBM Corp. 2010, 2011\n";
 }
 
 sub chmem_get_dev_size()
 {
-	my $i = 0;
-	my $device = 0;
-	my $old_device = 0;
+	my ($device, $old_device, $block, $old_block) = (0, 0, 0, 0);
 
-	while (-d "$memdir/memory$i") {
-		$device = `cat $memdir/memory$i/phys_device`;
+	foreach (@entries) {
+		$_ =~ /memory(\d+)/;
+		$block = $1;
+		$device = `cat $_/phys_device`;
 		chomp($device);
 		if ($device > $old_device) {
-			$dev_size = int($dev_size / ($device - $old_device));
+			$dev_size = int((($block - $old_block) * $block_size) /
+				    ($device - $old_device));
 			last;
 		}
-		$dev_size += $block_size;
-		$i++;
+		$old_block = $block;
 	}
 }
 
@@ -109,14 +110,16 @@ sub chmem_read_attr($$$)
 
 sub chmem_read_devices()
 {
-	my $i = 0;
+	my $block = 0;
 	my $device = 0;
 	my $old_device = 0;
 	my $blocks = 0;
 	my $state;
 
-	while (-d "$memdir/memory$i") {
-		chmem_read_attr($state, $device, $i);
+	foreach (@entries) {
+		$_ =~ /memory(\d+)/;
+		$block = $1;
+		chmem_read_attr($state, $device, $block);
 		if ($device != $old_device) {
 			$devices->{$old_device}->{'id'} = $old_device;
 			$devices->{$old_device}->{'blocks'} = $blocks;
@@ -126,7 +129,6 @@ sub chmem_read_devices()
 		if ($state eq "online") {
 			$blocks++;
 		}
-		$i++;
 	}
 	$devices->{$old_device}->{'blocks'} = $blocks;
 	$devices->{$old_device}->{'id'} = $old_device;
@@ -244,9 +246,6 @@ sub chmem_range($$)
 
 sub chmem_check()
 {
-	unless (-d $memdir) {
-		die "chmem: No memory hotplug interface in sysfs ($memdir).\n";
-	}
 	$block_size = `cat $memdir/block_size_bytes`;
 	chomp($block_size);
 	if ($block_size =~ /(?:0x)?([[:xdigit:]]+)/) {
@@ -263,7 +262,7 @@ sub chmem_check()
 		die "chmem: You cannot specify both options -e and -d.\n";
 	}
 
-	while (-d "$memdir/memory$total_blocks") {
+	foreach (@entries) {
 		$total_blocks++;
 	}
 	chmem_get_dev_size();
@@ -319,6 +318,11 @@ unless (GetOptions('v|version' => sub {c
 	die "Try '$script_name --help' for more information.\n";
 };
 
+@entries = (sort {length($a) <=> length($b) || $a cmp $b} <$memdir/memory*>);
+if (@entries == 0) {
+	die "chmem: No memory hotplug interface in sysfs ($memdir).\n";
+}
+
 chmem_read_devices();
 chmem_check();
 chmem_action();
--- a/zconf/lsmem
+++ b/zconf/lsmem
@@ -2,7 +2,7 @@
 ###############################################################################
 # lsmem - script to show memory hotplug status.
 #
-# Copyright IBM Corp. 2010
+# Copyright IBM Corp. 2010, 2011
 # Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com>
 ###############################################################################
 
@@ -16,6 +16,7 @@ my $memdir = "/sys/devices/system/memory
 my $block_size = 0;
 my $list_all = 0;
 my $dev_size = 0;
+my @entries;
 
 
 sub lsmem_read_attr($$$$)
@@ -30,36 +31,31 @@ sub lsmem_read_attr($$$$)
 
 sub lsmem_get_dev_size()
 {
-	my $i = 0;
-	my ($device, $old_device) = (0, 0);
+	my ($device, $old_device, $block, $old_block) = (0, 0, 0, 0);
 
-	while (-d "$memdir/memory$i") {
-		$device = `cat $memdir/memory$i/phys_device`;
+	foreach (@entries) {
+		$_ =~ /memory(\d+)/;
+		$block = $1;
+		$device = `cat $_/phys_device`;
 		chomp($device);
 		if ($device > $old_device) {
-			$dev_size = int($dev_size / ($device - $old_device));
+			$dev_size = int((($block - $old_block) * $block_size) /
+				    ($device - $old_device));
 			last;
 		}
-		$dev_size += $block_size;
-		$i++;
+		$old_block = $block;
 	}
 }
 
 sub lsmem_list()
 {
-	my $i = 0;
+	my $block = 0;
 	my ($start, $end, $size) = (0, 0, 0);
-	my ($state, $old_state) = (0, 0);
-	my ($rem, $old_rem) = (0, 0);
-	my ($device, $old_device) = (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 ($last_block, $end_dev) = (0, 0);
-
-	if (-d "$memdir/memory0") {
-		lsmem_read_attr($old_state, $old_rem, $old_device, 0);
-	} else {
-		die "lsmem: No memory hotplug interface in sysfs ($memdir).\n";
-	}
+	my $mem_hole;
 
 	$block_size = `cat $memdir/block_size_bytes`;
 	chomp($block_size);
@@ -71,43 +67,54 @@ sub lsmem_list()
 		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 <<HERE;
 Address Range                          Size (MB)  State    Removable  Device
 ===============================================================================
 HERE
-	while (-d "$memdir/memory$i") {
-		$i++;
-		if (-d "$memdir/memory$i") {
-			lsmem_read_attr($state, $rem, $device, $i);
+	foreach (@entries) {
+		$_ =~ /memory(\d+)/;
+		$block = $1;
+		if ($mem_hole) {
+			lsmem_read_attr($state, $rem, $device, $block);
+			$start = ($block) * ($block_size << 20);
+			$mem_hole = 0;
+		}
+		# check next block or memory hole
+		$block++;
+		if (-d "$memdir/memory".$block) {
+			lsmem_read_attr($next_state, $next_rem, $next_device,
+					$block);
 		} else {
-			$last_block = 1;
+			$mem_hole = 1
 		}
-		if ($state ne $old_state || $rem != $old_rem || $list_all ||
-		    $last_block) {
-			$end = $i * ($block_size << 20) - 1;
+		if ($state ne $next_state || $rem != $next_rem || $list_all ||
+		    $mem_hole) {
+			$end = ($block) * ($block_size << 20) - 1;
 			$size = ($end - $start + 1) >> 20;
-			if ($old_state eq "going-offline") {
-				$old_state = "on->off";
+			if ($state eq "going-offline") {
+				$state = "on->off";
 			}
 			printf("0x%016x-0x%016x %10lu  %-7s ", $start, $end,
-				$size, $old_state);
-			if ($old_state eq "online") {
-				printf(" %-9s  ", $old_rem ? "yes" : "no");
+				$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 ($old_device == $end_dev) {
-				printf("%d\n", $old_device);
+			if ($device == $end_dev) {
+				printf("%d\n", $device);
 			} else {
-				printf("%d-%d\n", $old_device, $end_dev);
+				printf("%d-%d\n", $device, $end_dev);
 			}
-			$old_state = $state;
-			$old_rem = $rem;
-			$old_device = $device;
+			$state = $next_state;
+			$rem = $next_rem;
+			$device = $end_dev + 1;
 			$start = $end + 1;
 		}
 	}
@@ -144,7 +151,7 @@ HERE
 sub lsmem_version()
 {
 	print "$script_name: version %S390_TOOLS_VERSION%\n";
-	print "Copyright IBM Corp. 2010\n";
+	print "Copyright IBM Corp. 2010, 2011\n";
 }
 
 
@@ -155,4 +162,8 @@ unless (GetOptions('v|version' => sub {l
 	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();