All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] New tools lsmem and chmem
@ 2016-10-12 12:00 Heiko Carstens
  2016-10-12 12:00 ` [PATCH 1/4] lib,strutils: add strtoux[16|32|64]_or_err functions Heiko Carstens
                   ` (4 more replies)
  0 siblings, 5 replies; 13+ messages in thread
From: Heiko Carstens @ 2016-10-12 12:00 UTC (permalink / raw)
  To: Karel Zak; +Cc: util-linux, Gerald Schaefer

This small patch series adds the tools lsmem and chmem to util-linux.

The lsmem and chmem tools were originally written in perl and are part
of the s390-tools package which can be found here:
https://www.ibm.com/developerworks/linux/linux390/s390-tools.html

These two simple tools can be used to inspect and modify memory
hotplug status of memory blocks (example below).

Given that the tools are architecture independent, there is no reason
to keep them in an s390 specific repository. They seem to be useful
for other architectures as well. And apparently if new features are
added to any of these tools everybody would benefit from it.

This patch series converts the tools to C and adds them to util-linux,
while both, the command line options as well as the output stay
(mostly) compatible. If these tools get merged into util-linux we will
remove their perl veriant from the s390-tools package.

The perl variant within s390-tools was originally written by Gerald
Schaefer. Clemens von Mann started the conversion to C, but left
before his work was finished. So I took his patches and (hopefully)
finished the conversion.

Example output of the lsmem tool:

# lsmem 
RANGE                                 SIZE STATE   REMOVABLE BLOCK
0x0000000000000000-0x000000005fffffff 1,5G online  yes       0-5
0x0000000060000000-0x000000007fffffff 512M online  no        6-7
0x0000000080000000-0x000000013fffffff   3G online  yes       8-19
0x0000000140000000-0x000000014fffffff 256M offline -         20
0x0000000150000000-0x000000017fffffff 768M online  no        21-23

Memory block size   :     256M
Total online memory :     5,8G
Total offline memory:     256M

Set memory range offline using the chmem tool:

# chmem -v -d 0x0000000130000000-0x000000013fffffff
Memory Block 19 (0x0000000130000000-0x000000013fffffff) disabled


Set the same memory range offline by specifying the block number:

# chmem -v -d -b 19
Memory Block 19 (0x0000000130000000-0x000000013fffffff) disabled


Set memory size (1g) online using the chmem tool:

# chmem -v -e 1g
Memory Block 15 (0x00000000f0000000-0x00000000ffffffff) enabled
Memory Block 16 (0x0000000100000000-0x000000010fffffff) enabled
Memory Block 17 (0x0000000110000000-0x000000011fffffff) enabled
Memory Block 18 (0x0000000120000000-0x000000012fffffff) enabled

Please consider merging these two tools.

Thanks,
Heiko

Heiko Carstens (4):
  lib,strutils: add strtoux[16|32|64]_or_err functions
  lsmem: new tool
  chmem: new tool
  lsmem: add testcase

 .gitignore                               |   2 +
 configure.ac                             |  14 +
 include/strutils.h                       |   3 +
 lib/strutils.c                           |  44 ++-
 sys-utils/Makemodule.am                  |  15 +
 sys-utils/chmem.8                        |  95 ++++++
 sys-utils/chmem.c                        | 325 ++++++++++++++++++++
 sys-utils/lsmem.1                        |  95 ++++++
 sys-utils/lsmem.c                        | 494 +++++++++++++++++++++++++++++++
 tests/commands.sh                        |   1 +
 tests/expected/lsmem/lsmem-s390-zvm-6g   |  91 ++++++
 tests/ts/lsmem/dumps/s390-zvm-6g.tar.bz2 | Bin 0 -> 2459 bytes
 tests/ts/lsmem/lsmem                     |  52 ++++
 tests/ts/lsmem/mk-input.sh               |  22 ++
 14 files changed, 1247 insertions(+), 6 deletions(-)
 create mode 100644 sys-utils/chmem.8
 create mode 100644 sys-utils/chmem.c
 create mode 100644 sys-utils/lsmem.1
 create mode 100644 sys-utils/lsmem.c
 create mode 100644 tests/expected/lsmem/lsmem-s390-zvm-6g
 create mode 100644 tests/ts/lsmem/dumps/s390-zvm-6g.tar.bz2
 create mode 100755 tests/ts/lsmem/lsmem
 create mode 100755 tests/ts/lsmem/mk-input.sh

-- 
2.8.4

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/4] lib,strutils: add strtoux[16|32|64]_or_err functions
  2016-10-12 12:00 [PATCH 0/4] New tools lsmem and chmem Heiko Carstens
@ 2016-10-12 12:00 ` Heiko Carstens
  2016-10-12 12:00 ` [PATCH 2/4] lsmem: new tool Heiko Carstens
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: Heiko Carstens @ 2016-10-12 12:00 UTC (permalink / raw)
  To: Karel Zak; +Cc: util-linux, Gerald Schaefer

Add helper functions which allow to parse hexadecimal numbers.
Based on a patch from Clemens von Mann.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
---
 include/strutils.h |  3 +++
 lib/strutils.c     | 44 ++++++++++++++++++++++++++++++++++++++------
 2 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/include/strutils.h b/include/strutils.h
index 51d9c9ff3553..aa31fc984c75 100644
--- a/include/strutils.h
+++ b/include/strutils.h
@@ -21,12 +21,15 @@ extern uintmax_t strtosize_or_err(const char *str, const char *errmesg);
 
 extern int16_t strtos16_or_err(const char *str, const char *errmesg);
 extern uint16_t strtou16_or_err(const char *str, const char *errmesg);
+extern uint16_t strtox16_or_err(const char *str, const char *errmesg);
 
 extern int32_t strtos32_or_err(const char *str, const char *errmesg);
 extern uint32_t strtou32_or_err(const char *str, const char *errmesg);
+extern uint32_t strtox32_or_err(const char *str, const char *errmesg);
 
 extern int64_t strtos64_or_err(const char *str, const char *errmesg);
 extern uint64_t strtou64_or_err(const char *str, const char *errmesg);
+extern uint64_t strtox64_or_err(const char *str, const char *errmesg);
 
 extern double strtod_or_err(const char *str, const char *errmesg);
 
diff --git a/lib/strutils.c b/lib/strutils.c
index d3b998f023bf..8a52be048210 100644
--- a/lib/strutils.c
+++ b/lib/strutils.c
@@ -264,6 +264,9 @@ char *strndup(const char *s, size_t n)
 }
 #endif
 
+static uint32_t _strtou32_or_err(const char *str, const char *errmesg, int base);
+static uint64_t _strtou64_or_err(const char *str, const char *errmesg, int base);
+
 int16_t strtos16_or_err(const char *str, const char *errmesg)
 {
 	int32_t num = strtos32_or_err(str, errmesg);
@@ -275,9 +278,9 @@ int16_t strtos16_or_err(const char *str, const char *errmesg)
 	return num;
 }
 
-uint16_t strtou16_or_err(const char *str, const char *errmesg)
+static uint16_t _strtou16_or_err(const char *str, const char *errmesg, int base)
 {
-	uint32_t num = strtou32_or_err(str, errmesg);
+	uint32_t num = _strtou32_or_err(str, errmesg, base);
 
 	if (num > UINT16_MAX) {
 		errno = ERANGE;
@@ -286,6 +289,16 @@ uint16_t strtou16_or_err(const char *str, const char *errmesg)
 	return num;
 }
 
+uint16_t strtou16_or_err(const char *str, const char *errmesg)
+{
+	return _strtou16_or_err(str, errmesg, 10);
+}
+
+uint16_t strtox16_or_err(const char *str, const char *errmesg)
+{
+	return _strtou16_or_err(str, errmesg, 16);
+}
+
 int32_t strtos32_or_err(const char *str, const char *errmesg)
 {
 	int64_t num = strtos64_or_err(str, errmesg);
@@ -297,9 +310,9 @@ int32_t strtos32_or_err(const char *str, const char *errmesg)
 	return num;
 }
 
-uint32_t strtou32_or_err(const char *str, const char *errmesg)
+static uint32_t _strtou32_or_err(const char *str, const char *errmesg, int base)
 {
-	uint64_t num = strtou64_or_err(str, errmesg);
+	uint64_t num = _strtou64_or_err(str, errmesg, base);
 
 	if (num > UINT32_MAX) {
 		errno = ERANGE;
@@ -308,6 +321,16 @@ uint32_t strtou32_or_err(const char *str, const char *errmesg)
 	return num;
 }
 
+uint32_t strtou32_or_err(const char *str, const char *errmesg)
+{
+	return _strtou32_or_err(str, errmesg, 10);
+}
+
+uint32_t strtox32_or_err(const char *str, const char *errmesg)
+{
+	return _strtou32_or_err(str, errmesg, 16);
+}
+
 int64_t strtos64_or_err(const char *str, const char *errmesg)
 {
 	int64_t num;
@@ -329,7 +352,7 @@ err:
 	errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
 }
 
-uint64_t strtou64_or_err(const char *str, const char *errmesg)
+static uint64_t _strtou64_or_err(const char *str, const char *errmesg, int base)
 {
 	uintmax_t num;
 	char *end = NULL;
@@ -337,7 +360,7 @@ uint64_t strtou64_or_err(const char *str, const char *errmesg)
 	errno = 0;
 	if (str == NULL || *str == '\0')
 		goto err;
-	num = strtoumax(str, &end, 10);
+	num = strtoumax(str, &end, base);
 
 	if (errno || str == end || (end && *end))
 		goto err;
@@ -350,6 +373,15 @@ err:
 	errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
 }
 
+uint64_t strtou64_or_err(const char *str, const char *errmesg)
+{
+	return _strtou64_or_err(str, errmesg, 10);
+}
+
+uint64_t strtox64_or_err(const char *str, const char *errmesg)
+{
+	return _strtou64_or_err(str, errmesg, 16);
+}
 
 double strtod_or_err(const char *str, const char *errmesg)
 {
-- 
2.8.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/4] lsmem: new tool
  2016-10-12 12:00 [PATCH 0/4] New tools lsmem and chmem Heiko Carstens
  2016-10-12 12:00 ` [PATCH 1/4] lib,strutils: add strtoux[16|32|64]_or_err functions Heiko Carstens
@ 2016-10-12 12:00 ` Heiko Carstens
  2016-11-03 12:00   ` Karel Zak
  2016-10-12 12:00 ` [PATCH 3/4] chmem: " Heiko Carstens
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 13+ messages in thread
From: Heiko Carstens @ 2016-10-12 12:00 UTC (permalink / raw)
  To: Karel Zak; +Cc: util-linux, Gerald Schaefer

Move the s390 specific lsmem tool to util-linux.

The lsmem tool was originally written in perl and is part of the
s390-tools package which can be found here:
https://www.ibm.com/developerworks/linux/linux390/s390-tools.html

Given that the tool is architecture independent, there is no reason to
keep it in an s390 specific repository. It seems to be useful for
other architectures as well.

This patch converts the tool to C and adds it to util-linux, while the
command line options stay compatible. The only exception is the option
"-v" which used to be the short form of "--version". That got changed
to "-V" so it behaves like most other tools contained within
util-linux.

The lsmem tool inspect the contents of /sys/devices/system/memory and
prints a summary output similar to what lscpu does:

RANGE                                 SIZE STATE   REMOVABLE BLOCK
0x0000000000000000-0x000000005fffffff 1,5G online  yes       0-5
0x0000000060000000-0x000000007fffffff 512M online  no        6-7
0x0000000080000000-0x000000013fffffff   3G online  yes       8-19
0x0000000140000000-0x000000014fffffff 256M offline -         20
0x0000000150000000-0x000000017fffffff 768M online  no        21-23

Memory block size   :     256M
Total online memory :     5,8G
Total offline memory:     256M

In order to keep the output small the tool merges subsequent address
ranges where the attributes are identical. To avoid merging of line
the "-a" option can be used.

The lsmem tool also has "--extendend" and "--parsable" option which
can be used to customize the output, e.g.  limit the output to
specified columns. This is quite similar to what the lscpu tool does.

This is based on a patch from Clemens von Mann.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
---
 .gitignore              |   1 +
 configure.ac            |   7 +
 sys-utils/Makemodule.am |   8 +
 sys-utils/lsmem.1       |  95 ++++++++++
 sys-utils/lsmem.c       | 494 ++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 605 insertions(+)
 create mode 100644 sys-utils/lsmem.1
 create mode 100644 sys-utils/lsmem.c

diff --git a/.gitignore b/.gitignore
index 064010b20b46..6ead2f1dddc2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -110,6 +110,7 @@ update.log
 /lscpu
 /lslocks
 /lslogins
+/lsmem
 /lsns
 /mcookie
 /mesg
diff --git a/configure.ac b/configure.ac
index 39600bcd1f05..78dc24564140 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1477,6 +1477,13 @@ UL_BUILD_INIT([flock], [check])
 UL_REQUIRES_HAVE([flock], [timer], [timer_create function])
 AM_CONDITIONAL([BUILD_FLOCK], [test "x$build_flock" = xyes])
 
+AC_ARG_ENABLE([lsmem],
+  AS_HELP_STRING([--disable-lsmem], [do not build lsmem]),
+  [], [UL_DEFAULT_ENABLE([lsmem], [yes])]
+)
+UL_BUILD_INIT([lsmem])
+AM_CONDITIONAL([BUILD_LSMEM], [test "x$build_lsmem" = xyes])
+
 UL_BUILD_INIT([ipcmk], [yes])
 AM_CONDITIONAL([BUILD_IPCMK], [test "x$build_ipcmk" = xyes])
 
diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am
index 94003031f3b2..5de02e1fb108 100644
--- a/sys-utils/Makemodule.am
+++ b/sys-utils/Makemodule.am
@@ -1,3 +1,11 @@
+if BUILD_LSMEM
+usrbin_exec_PROGRAMS += lsmem
+dist_man_MANS += sys-utils/lsmem.1
+lsmem_SOURCES = sys-utils/lsmem.c
+lsmem_LDADD = $(LDADD) libcommon.la libsmartcols.la
+lsmem_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
+endif
+
 if BUILD_FLOCK
 usrbin_exec_PROGRAMS += flock
 dist_man_MANS += sys-utils/flock.1
diff --git a/sys-utils/lsmem.1 b/sys-utils/lsmem.1
new file mode 100644
index 000000000000..bb457dd74e48
--- /dev/null
+++ b/sys-utils/lsmem.1
@@ -0,0 +1,95 @@
+.TH LSMEM 1 "October 2016" "util-linux" "User Commands"
+.SH NAME
+lsmem \- list the ranges of available memory with their online status
+.SH SYNOPSIS
+.B lsmem
+.RB [ \-h "] [" \-V "] [" \-a "] [" \-s " \fIdirectory\fP] [" \-e [=\fIlist\fP]| \-p [=\fIlist\fP]]
+.br
+.SH DESCRIPTION
+The \fBlsmem\fP command lists the ranges of available memory with their online
+status. The listed memory blocks correspond to the memory block representation
+in sysfs. The command also shows the memory block size and the amount of memory
+in online and offline state.
+.sp
+By default \fBlsmem\fP prints a human readable output table with the RANGE,
+SIZE, STATE, REMOVABLE, and BLOCK columns.
+.sp
+Use the \fB--extended\fP or \fB--parse\fP option to customize the output
+table. You can change the table format and limit, extend, or rearrange the
+table columns.
+.sp
+Not all columns are supported on all systems.  If an unsupported column is
+specified, \fBlsmem\fP prints the column but does not provide any data for it.
+
+.SS COLUMNS
+.TP
+.B RANGE
+Start and end address of the memory range.
+.TP
+.B SIZE
+Size of the memory range.
+.TP
+.B STATE
+Indication of the online status of the memory range. State "on->off" means
+that the address range is in transition from online to offline.
+.TP
+.B REMOVABLE
+"yes" if the memory range can be set offline, "no" if it cannot be set offline.
+A dash ("\-") means that the range is already offline.
+.TP
+.B BLOCK
+Memory block number or numbers that correspond to the memory range.
+.TP
+.B NODE
+Numa node of memory.
+.SH OPTIONS
+.TP
+.BR \-a ", " \-\-all
+List each individual memory block, instead of combining memory blocks with
+similar attributes.
+.TP
+.BR \-e , " \-\-extended" [=\fIlist\fP]
+Display extended memory information in human-readable format.
+
+If the \fIlist\fP argument is omitted, all columns for which data is available
+are included in the command output.
+
+The \fIlist\fP argument is a comma-separated list of column labels that specifies
+the columns to be included in the output table and their sequence in the
+table. See \fBCOLUMNS\fP for valid column labels. Column labels are not case
+sensitive. The specification consisting of option, equal sign (=), and \fIlist\fP
+must not contain any white space.
+
+Examples: '\fB-e=range,size,state\fP' or '\fB--extended=NODE,state,size,RANGE\fP'.
+.TP
+.BR \-h ", " \-\-help
+Display help text and exit.
+.TP
+.BR \-p , " \-\-parse" [=\fIlist\fP]
+Optimize the command output for easy parsing.
+
+If the \fIlist\fP argument is omitted, all columns for which data is available
+are included in the command output.
+
+The \fIlist\fP argument is a comma-separated list of column labels that specifies
+the columns to be included in the output table and their sequence in the
+table. See \fBCOLUMNS\fP for valid column labels. Column labels are not case
+sensitive. The specification consisting of option, equal sign (=), and \fIlist\fP
+must not contain any white space.
+
+Examples: '\fB-p=range,size,state\fP' or '\fB--parse=NODE,state,size,RANGE\fP'.
+.TP
+.BR \-s , " \-\-sysroot " \fIdirectory\fP
+Gather memory data for a Linux instance other than the instance from which the
+\fBlsmem\fP command is issued.  The specified \fIdirectory\fP is the system
+root of the Linux instance to be inspected.
+.TP
+.BR \-V ", " \-\-version
+Display version information and exit.
+.SH SEE ALSO
+.BR chmem (8)
+.SH AVAILABILITY
+The \fBlsmem\fP command is part of the util-linux package and is available from
+.UR ftp://\:ftp.kernel.org\:/pub\:/linux\:/utils\:/util-linux/
+Linux Kernel Archive
+.UE .
diff --git a/sys-utils/lsmem.c b/sys-utils/lsmem.c
new file mode 100644
index 000000000000..13e2414d8d36
--- /dev/null
+++ b/sys-utils/lsmem.c
@@ -0,0 +1,494 @@
+/*
+ * lsmem - Show memory configuration
+ *
+ * Copyright IBM Corp. 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <c.h>
+#include <nls.h>
+#include <path.h>
+#include <strutils.h>
+#include <closestream.h>
+#include <xalloc.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <strutils.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <assert.h>
+#include <optutils.h>
+#include <libsmartcols.h>
+
+#define _PATH_SYS_MEMORY		"/sys/devices/system/memory"
+#define _PATH_SYS_MEMORY_BLOCK_SIZE	_PATH_SYS_MEMORY "/block_size_bytes"
+
+#define MEMORY_STATE_ONLINE		0
+#define MEMORY_STATE_OFFLINE		1
+#define MEMORY_STATE_GOING_OFFLINE	2
+#define MEMORY_STATE_UNKNOWN		3
+
+struct memory_block {
+	uint64_t	index;
+	uint64_t	count;
+	int		state;
+	int		node;
+	unsigned int	removable:1;
+};
+
+enum {
+	OUTPUT_READABLE = 0,	/* default */
+	OUTPUT_PARSABLE,	/* -p */
+};
+
+struct lsmem_desc {
+	struct dirent		**dirs;
+	int			ndirs;
+	struct memory_block	*blocks;
+	int			nblocks;
+	unsigned int		have_nodes : 1;
+	uint64_t		block_size;
+	uint64_t		mem_online;
+	uint64_t		mem_offline;
+};
+
+struct lsmem_modifier {
+	int		mode; /* OUTPUT_* */
+	unsigned int	compat : 1;
+	unsigned int	list_all_blocks : 1;
+};
+
+enum {
+	COL_RANGE,
+	COL_SIZE,
+	COL_STATE,
+	COL_REMOVABLE,
+	COL_BLOCK,
+	COL_NODE,
+};
+
+struct lsmem_coldesc {
+	const int flags;
+	const char *name;
+	const char *help;
+};
+
+static struct lsmem_coldesc coldescs[] = {
+	[COL_RANGE]	= { 0,		    "RANGE",	 N_("adress range")},
+	[COL_SIZE]	= { SCOLS_FL_RIGHT, "SIZE",	 N_("size of memory")},
+	[COL_STATE]	= { 0,		    "STATE",	 N_("state of memory")},
+	[COL_REMOVABLE]	= { 0,		    "REMOVABLE", N_("memory is removable")},
+	[COL_BLOCK]	= { 0,		    "BLOCK",	 N_("memory block")},
+	[COL_NODE]	= { 0,		    "NODE",	 N_("node information")},
+};
+
+static int column_name_to_id(const char *name, size_t namesz)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(coldescs); i++) {
+		const char *cn = coldescs[i].name;
+
+		if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
+			return i;
+	}
+	warnx(_("unknown column: %s"), name);
+	return -1;
+}
+
+static char *get_cell_header(int col, char *buf, size_t bufsz)
+{
+	snprintf(buf, bufsz, "%s", coldescs[col].name);
+	return buf;
+}
+
+static char *get_cell_data(struct lsmem_desc *desc, int idx, int col,
+			   struct lsmem_modifier *mod,
+			   char *buf, size_t bufsz)
+{
+	struct memory_block *blk;
+	uint64_t start, size;
+
+	blk = &desc->blocks[idx];
+	start = blk->index * desc->block_size;
+	size = blk->count * desc->block_size;
+
+	switch (col) {
+	case COL_RANGE:
+		snprintf(buf, bufsz, "0x%016"PRIx64"-0x%016"PRIx64, start, start + size - 1);
+		break;
+	case COL_SIZE:
+		if (mod->mode == OUTPUT_PARSABLE)
+			snprintf(buf, bufsz, "%"PRId64, size);
+		else
+			snprintf(buf, bufsz, "%s", size_to_human_string(SIZE_SUFFIX_1LETTER, size));
+		break;
+	case COL_STATE:
+		if (blk->state == MEMORY_STATE_ONLINE)
+			snprintf(buf, bufsz, _("online"));
+		else if (blk->state == MEMORY_STATE_OFFLINE)
+			snprintf(buf, bufsz, _("offline"));
+		else if (blk->state == MEMORY_STATE_GOING_OFFLINE)
+			snprintf(buf, bufsz, _("on->off"));
+		else /* unknown */
+			snprintf(buf, bufsz, "?");
+		break;
+	case COL_REMOVABLE:
+		if (blk->state == MEMORY_STATE_ONLINE)
+			snprintf(buf, bufsz, "%s", blk->removable ? _("yes") : _("no"));
+		else
+			snprintf(buf, bufsz, "-");
+		break;
+	case COL_BLOCK:
+		if (blk->count == 1)
+			snprintf(buf, bufsz, "%"PRId64, blk->index);
+		else
+			snprintf(buf, bufsz, "%"PRId64"-%"PRId64,
+				 blk->index, blk->index + blk->count - 1);
+		break;
+	case COL_NODE:
+		if (desc->have_nodes)
+			snprintf(buf, bufsz, "%d", blk->node);
+		else
+			snprintf(buf, bufsz, "-");
+		break;
+	}
+	return buf;
+}
+
+static void print_parsable(struct lsmem_desc *desc, int *cols, int ncols,
+			   struct lsmem_modifier *mod)
+{
+	char buf[BUFSIZ], *data;
+	int c, i;
+
+	fputs("# ", stdout);
+	for (i = 0; i < ncols; i++) {
+		data = get_cell_header(cols[i], buf, sizeof(buf));
+		if (i > 0)
+			fputc(',', stdout);
+		fputs(data && *data ? data : "", stdout);
+	}
+	fputc('\n', stdout);
+
+	for (i = 0; i < desc->nblocks; i++) {
+		for (c = 0; c < ncols; c++) {
+			if (c > 0)
+				putchar(',');
+			data = get_cell_data(desc, i, cols[c], mod, buf, sizeof(buf));
+			fputs(data && *data ? data : "", stdout);
+		}
+		fputc('\n', stdout);
+	}
+}
+
+static void print_readable_table(struct lsmem_desc *desc, int *cols, int ncols,
+				 struct lsmem_modifier *mod)
+{
+	struct libscols_table *table;
+	char buf[BUFSIZ], *data;
+	int c, i;
+
+	scols_init_debug(0);
+	table = scols_new_table();
+	if (!table)
+		err(EXIT_FAILURE, _("Failed to initialize output table"));
+	for (i = 0; i < ncols; i++) {
+		data = get_cell_header(cols[i], buf, sizeof(buf));
+		if (!scols_table_new_column(table, xstrdup(data), 0, coldescs[i].flags))
+			err(EXIT_FAILURE, _("Failed to initialize output column"));
+	}
+	for (i = 0; i < desc->nblocks; i++) {
+		struct libscols_line *line;
+
+		line = scols_table_new_line(table, NULL);
+		if (!line)
+			err(EXIT_FAILURE, _("Failed to initialize output line"));
+
+		for (c = 0; c < ncols; c++) {
+			data = get_cell_data(desc, i, cols[c], mod, buf, sizeof(buf));
+			if (!data || !*data)
+				data = "-";
+			scols_line_set_data(line, c, data);
+		}
+	}
+	scols_print_table(table);
+	scols_unref_table(table);
+}
+
+static void print_readable(struct lsmem_desc *desc, int *cols, int ncols,
+			   struct lsmem_modifier *mod)
+{
+	print_readable_table(desc, cols, ncols, mod);
+	fputc('\n', stdout);
+	fprintf(stdout, _("Memory block size   : %8s\n"),
+		size_to_human_string(SIZE_SUFFIX_1LETTER, desc->block_size));
+	fprintf(stdout, _("Total online memory : %8s\n"),
+		size_to_human_string(SIZE_SUFFIX_1LETTER, desc->mem_online));
+	fprintf(stdout, _("Total offline memory: %8s\n"),
+		size_to_human_string(SIZE_SUFFIX_1LETTER, desc->mem_offline));
+}
+
+static int memory_block_get_node(char *name)
+{
+	struct dirent *de;
+	char *path;
+	DIR *dir;
+	int node;
+
+	path = path_strdup(_PATH_SYS_MEMORY"/%s", name);
+	dir = opendir(path);
+	free(path);
+	if (!dir)
+		err(EXIT_FAILURE, _("Failed to open %s"), path);
+	node = -1;
+	while ((de = readdir(dir)) != NULL) {
+		if (strncmp("node", de->d_name, 4))
+			continue;
+		if (!isdigit_string(de->d_name + 4))
+			continue;
+		node = strtol(de->d_name + 4, NULL, 10);
+	}
+	closedir(dir);
+	return node;
+}
+
+static void memory_block_read_attrs(struct lsmem_desc *desc, char *name,
+				    struct memory_block *blk)
+{
+	char line[BUFSIZ];
+
+	blk->count = 1;
+	blk->index = strtoumax(name + 6, NULL, 10); /* get <num> of "memory<num>" */
+	blk->removable = path_read_u64(_PATH_SYS_MEMORY"/%s/%s", name, "removable");
+	blk->state = MEMORY_STATE_UNKNOWN;
+	path_read_str(line, sizeof(line), _PATH_SYS_MEMORY"/%s/%s", name, "state");
+	if (strcmp(line, "offline") == 0)
+		blk->state = MEMORY_STATE_OFFLINE;
+	else if (strcmp(line, "online") == 0)
+		blk->state = MEMORY_STATE_ONLINE;
+	else if (strcmp(line, "going-offline") == 0)
+		blk->state = MEMORY_STATE_GOING_OFFLINE;
+	if (desc->have_nodes)
+		blk->node = memory_block_get_node(name);
+}
+
+static int is_mergeable(struct lsmem_desc *desc, char *enabled,
+			struct memory_block *blk,
+			struct lsmem_modifier *mod)
+{
+	struct memory_block *curr;
+
+	if (!desc->nblocks)
+		return 0;
+	curr = &desc->blocks[desc->nblocks - 1];
+	if (mod->list_all_blocks)
+		return 0;
+	if (curr->index + curr->count != blk->index)
+		return 0;
+	if (enabled[COL_STATE] && (curr->state != blk->state))
+		return 0;
+	if (enabled[COL_REMOVABLE] && (curr->removable != blk->removable))
+		return 0;
+	if (enabled[COL_NODE] && desc->have_nodes) {
+		if (curr->node != blk->node)
+			return 0;
+	}
+	return 1;
+}
+
+static void read_info(struct lsmem_desc *desc, int *cols, int ncols,
+		      struct lsmem_modifier *mod)
+{
+	char enabled[ARRAY_SIZE(coldescs)];
+	struct memory_block blk;
+	char line[BUFSIZ];
+	int i;
+
+	path_read_str(line, sizeof(line), _PATH_SYS_MEMORY_BLOCK_SIZE);
+	desc->block_size = strtoumax(line, NULL, 16);
+
+	memset(enabled, 0, sizeof(enabled));
+	for (i = 0; i < ncols; i++)
+		enabled[cols[i]] = 1;
+	for (i = 0; i < desc->ndirs; i++) {
+		memory_block_read_attrs(desc, desc->dirs[i]->d_name, &blk);
+		if (is_mergeable(desc, enabled, &blk, mod)) {
+			desc->blocks[desc->nblocks - 1].count++;
+			continue;
+		}
+		desc->nblocks++;
+		desc->blocks = xrealloc(desc->blocks, desc->nblocks * sizeof(blk));
+		*&desc->blocks[desc->nblocks - 1] = blk;
+	}
+	for (i = 0; i < desc->nblocks; i++) {
+		if (desc->blocks[i].state == MEMORY_STATE_ONLINE)
+			desc->mem_online += desc->block_size * desc->blocks[i].count;
+		else
+			desc->mem_offline += desc->block_size * desc->blocks[i].count;
+	}
+}
+
+static int memory_block_filter(const struct dirent *de)
+{
+	if (strncmp("memory", de->d_name, 6))
+		return 0;
+	return isdigit_string(de->d_name + 6);
+}
+
+static void read_basic_info(struct lsmem_desc *desc)
+{
+	char *dir;
+
+	if (!path_exist(_PATH_SYS_MEMORY_BLOCK_SIZE))
+		errx(EXIT_FAILURE, _("This system does not support memory blocks"));
+
+	dir = path_strdup(_PATH_SYS_MEMORY);
+	desc->ndirs = scandir(dir, &desc->dirs, memory_block_filter, versionsort);
+	free(dir);
+	if (desc->ndirs <= 0)
+		err(EXIT_FAILURE, _("Failed to read %s"), _PATH_SYS_MEMORY);
+
+	if (memory_block_get_node(desc->dirs[0]->d_name) != -1)
+		desc->have_nodes = 1;
+}
+
+static void __attribute__((__noreturn__)) lsmem_usage(FILE *out)
+{
+	unsigned int i;
+
+	fputs(USAGE_HEADER, out);
+	fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
+
+	fputs(USAGE_SEPARATOR, out);
+	fputs(_("List the ranges of available memory with their online status.\n"), out);
+
+	fputs(USAGE_OPTIONS, out);
+	fputs(_(" -a, --all               list each individiual memory block\n"), out);
+	fputs(_(" -e, --extended[=<list>] print customized output in a readable format\n"), out);
+	fputs(_(" -p, --parse[=<list>]    print customized output in a parsable format\n"), out);
+	fputs(_(" -s, --sysroot <dir>     use the specified directory as system root\n"), out);
+	fputs(USAGE_SEPARATOR, out);
+	fputs(USAGE_HELP, out);
+	fputs(USAGE_VERSION, out);
+
+	fputs(_("\nAvailable columns:\n"), out);
+
+	for (i = 0; i < ARRAY_SIZE(coldescs); i++)
+		fprintf(out, " %10s  %s\n", coldescs[i].name, coldescs[i].help);
+
+	fprintf(out, USAGE_MAN_TAIL("lsmem(1)"));
+
+	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+int main(int argc, char **argv)
+{
+	struct lsmem_modifier _mod = { .mode = OUTPUT_READABLE, .compat = 1 }, *mod = &_mod;
+	struct lsmem_desc _desc = { }, *desc = &_desc;
+	int columns[ARRAY_SIZE(coldescs)], ncolumns = 0;
+	int c;
+
+	static const struct option longopts[] = {
+		{"all",		no_argument,		NULL, 'a'},
+		{"extended",	optional_argument,	NULL, 'e'},
+		{"help",	no_argument,		NULL, 'h'},
+		{"parse",	optional_argument,	NULL, 'p'},
+		{"sysroot",	required_argument,	NULL, 's'},
+		{"version",	no_argument,		NULL, 'V'},
+		{NULL,		0,			NULL, 0}
+	};
+	static const ul_excl_t excl[] = {	/* rows and cols in ASCII order */
+		{ 'e','p' },
+		{ 0 }
+	};
+	int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
+
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+	atexit(close_stdout);
+
+	while ((c = getopt_long(argc, argv, "ae::hp::s:V", longopts, NULL)) != -1) {
+
+		err_exclusive_options(c, longopts, excl, excl_st);
+
+		switch (c) {
+		case 'a':
+			mod->list_all_blocks = 1;
+			break;
+		case 'h':
+			lsmem_usage(stdout);
+			break;
+		case 'p':
+		case 'e':
+			if (optarg) {
+				if (*optarg == '=')
+					optarg++;
+				ncolumns = string_to_idarray(optarg,
+							     columns, ARRAY_SIZE(columns),
+							     column_name_to_id);
+				if (ncolumns < 0)
+					return EXIT_FAILURE;
+			}
+			mod->mode = c == 'p' ? OUTPUT_PARSABLE : OUTPUT_READABLE;
+			mod->compat = 0;
+			break;
+		case 's':
+			path_set_prefix(optarg);
+			break;
+		case 'V':
+			printf(UTIL_LINUX_VERSION);
+			return 0;
+		default:
+			lsmem_usage(stderr);
+		}
+	}
+
+	if (argc != optind)
+		lsmem_usage(stderr);
+
+	read_basic_info(desc);
+
+	if (!ncolumns) {
+		/* No list was given. Print the following lines by default */
+		columns[ncolumns++] = COL_RANGE;
+		columns[ncolumns++] = COL_SIZE;
+		columns[ncolumns++] = COL_STATE;
+		columns[ncolumns++] = COL_REMOVABLE;
+		columns[ncolumns++] = COL_BLOCK;
+		if (!mod->compat) {
+			/* Print everything else what is there if the
+			 * extended or parsable mode has been specified */
+			if (desc->have_nodes)
+				columns[ncolumns++] = COL_NODE;
+		}
+	}
+
+	read_info(desc, columns, ncolumns, mod);
+
+	switch (mod->mode) {
+	case OUTPUT_READABLE:
+		print_readable(desc, columns, ncolumns, mod);
+		break;
+	case OUTPUT_PARSABLE:
+		print_parsable(desc, columns, ncolumns, mod);
+		break;
+	}
+	return 0;
+}
-- 
2.8.4


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/4] chmem: new tool
  2016-10-12 12:00 [PATCH 0/4] New tools lsmem and chmem Heiko Carstens
  2016-10-12 12:00 ` [PATCH 1/4] lib,strutils: add strtoux[16|32|64]_or_err functions Heiko Carstens
  2016-10-12 12:00 ` [PATCH 2/4] lsmem: new tool Heiko Carstens
@ 2016-10-12 12:00 ` Heiko Carstens
  2016-10-19 10:40   ` Heiko Carstens
  2016-10-12 12:00 ` [PATCH 4/4] lsmem: add testcase Heiko Carstens
  2016-10-19  9:38 ` [PATCH 0/4] New tools lsmem and chmem Karel Zak
  4 siblings, 1 reply; 13+ messages in thread
From: Heiko Carstens @ 2016-10-12 12:00 UTC (permalink / raw)
  To: Karel Zak; +Cc: util-linux, Gerald Schaefer

Move the s390 specific chmem tool to util-linux.

The chmem tool was originally written in perl and is part of the
s390-tools package which can be found here:
https://www.ibm.com/developerworks/linux/linux390/s390-tools.html

Given that the tool is architecture independent, there is no reason to
keep it in an s390 specific repository. It seems to be useful for
other architectures as well.

This patch converts the tool to C and adds it to util-linux, while the
command line options stay compatible. The only exception is the option
"-v" which used to be the short form of "--version". That got changed
to "-V" so it behaves like most other tools contained within
util-linux.

The chmem tool can be used to set memory online or offline. This can
be achieved by specifying a memory range:

Memory Block 19 (0x0000000130000000-0x000000013fffffff) disabled

or by specifying a size where chmem will automatically select memory
blocks:

Memory Block 21 (0x0000000150000000-0x000000015fffffff) disable failed
Memory Block 18 (0x0000000120000000-0x000000012fffffff) disabled
Memory Block 17 (0x0000000110000000-0x000000011fffffff) disabled
Memory Block 16 (0x0000000100000000-0x000000010fffffff) disabled
Memory Block 15 (0x00000000f0000000-0x00000000ffffffff) disabled

or by specifying memory block numbers instead of address ranges:

Memory Block 15 (0x00000000f0000000-0x00000000ffffffff) disabled
Memory Block 16 (0x0000000100000000-0x000000010fffffff) disabled
Memory Block 17 (0x0000000110000000-0x000000011fffffff) disabled
Memory Block 18 (0x0000000120000000-0x000000012fffffff) disabled

This is based on a patch from Clemens von Mann.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
---
 .gitignore              |   1 +
 configure.ac            |   7 ++
 sys-utils/Makemodule.am |   7 ++
 sys-utils/chmem.8       |  95 ++++++++++++++
 sys-utils/chmem.c       | 325 ++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 435 insertions(+)
 create mode 100644 sys-utils/chmem.8
 create mode 100644 sys-utils/chmem.c

diff --git a/.gitignore b/.gitignore
index 6ead2f1dddc2..2658dcdd1d68 100644
--- a/.gitignore
+++ b/.gitignore
@@ -68,6 +68,7 @@ update.log
 /cfdisk
 /chcpu
 /chfn
+/chmem
 /chrt
 /chsh
 /col
diff --git a/configure.ac b/configure.ac
index 78dc24564140..1ba40d528656 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1484,6 +1484,13 @@ AC_ARG_ENABLE([lsmem],
 UL_BUILD_INIT([lsmem])
 AM_CONDITIONAL([BUILD_LSMEM], [test "x$build_lsmem" = xyes])
 
+AC_ARG_ENABLE([chmem],
+  AS_HELP_STRING([--disable-chmem], [do not build chmem]),
+  [], [UL_DEFAULT_ENABLE([chmem], [yes])]
+)
+UL_BUILD_INIT([chmem])
+AM_CONDITIONAL([BUILD_CHMEM], [test "x$build_chmem" = xyes])
+
 UL_BUILD_INIT([ipcmk], [yes])
 AM_CONDITIONAL([BUILD_IPCMK], [test "x$build_ipcmk" = xyes])
 
diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am
index 5de02e1fb108..be643c965c36 100644
--- a/sys-utils/Makemodule.am
+++ b/sys-utils/Makemodule.am
@@ -6,6 +6,13 @@ lsmem_LDADD = $(LDADD) libcommon.la libsmartcols.la
 lsmem_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
 endif
 
+if BUILD_CHMEM
+usrbin_exec_PROGRAMS += chmem
+dist_man_MANS += sys-utils/chmem.8
+chmem_SOURCES = sys-utils/chmem.c
+chmem_LDADD = $(LDADD) libcommon.la
+endif
+
 if BUILD_FLOCK
 usrbin_exec_PROGRAMS += flock
 dist_man_MANS += sys-utils/flock.1
diff --git a/sys-utils/chmem.8 b/sys-utils/chmem.8
new file mode 100644
index 000000000000..99f9079351a6
--- /dev/null
+++ b/sys-utils/chmem.8
@@ -0,0 +1,95 @@
+.TH CHMEM 8 "October 2016" "util-linux" "System Administration"
+.SH NAME
+chmem \- configure memory
+.SH SYNOPSIS
+.B chmem
+.RB [ \-h "] [" \-V "] [" \-v "] [" \-e | \-d "]"
+[\fISIZE\fP|\fIRANGE\fP|\fB\-b\fP \fIBLOCKRANGE\fP]
+.SH DESCRIPTION
+The chmem command sets a particular size or range of memory online or offline.
+.
+.IP "\(hy" 2
+Specify \fISIZE\fP as <size>[m|M|g|G]. With m or M, <size> specifies the memory
+size in MiB (1024 x 1024 bytes). With g or G, <size> specifies the memory size
+in GiB (1024 x 1024 x 1024 bytes). The default unit is MiB.
+.
+.IP "\(hy" 2
+Specify \fIRANGE\fP in the form 0x<start>-0x<end> as shown in the output of the
+\fBlsmem\fP command. <start> is the hexadecimal address of the first byte and <end>
+is the hexadecimal address of the last byte in the memory range.
+.
+.IP "\(hy" 2
+Specify \fIBLOCKRANGE\fP in the form <first>-<last> or <block> as shown in the
+output of the \fBlsmem\fP command. <first> is the number of the first memory block
+and <last> is the number of the last memory block in the memory
+range. Alternatively a single block can be specified. \fIBLOCKRANGE\fP requires
+the \fB--blocks\fP option.
+.
+.PP
+\fISIZE\fP and \fIRANGE\fP must be aligned to the Linux memory block size, as
+shown in the output of the \fBlsmem\fP command.
+
+Setting memory online can fail for various reasons. On virtualized systems it
+can fail if the hypervisor does not have enough memory left, for example
+because memory was overcommitted. Setting memory offline can fail if Linux
+cannot free the memory. If only part of the requested memory can be set online
+or offline, a message tells you how much memory was set online or offline
+instead of the requested amount.
+
+When setting memory online \fBchmem\fP starts with the lowest memory block
+numbers. When setting memory offline \fBchmem\fP starts with the highest memory
+block numbers.
+.SH OPTIONS
+.TP
+.BR \-b ", " \-\-blocks
+Use a \fIBLOCKRANGE\fP parameter instead of \fIRANGE\fP or \fISIZE\fP for the
+\fB--enable\fP and \fB--disable\fP options.
+.TP
+.BR \-d ", " \-\-disable
+Set the specified \fIRANGE\fP, \fISIZE\fP, or \fIBLOCKRANGE\fP of memory offline.
+.TP
+.BR \-e ", " \-\-enable
+Set the specified \fIRANGE\fP, \fISIZE\fP, or \fIBLOCKRANGE\fP of memory online.
+.TP
+.BR \-h ", " \-\-help
+Print a short help text, then exit.
+.TP
+.BR \-v ", " \-\-verbose
+Verbose mode. Causes \fBchmem\fP to print debugging messages about it's
+progress.
+.TP
+.BR \-V ", " \-\-version
+Print the version number, then exit.
+.SH RETURN CODES
+.B chmem
+has the following return codes:
+.TP
+.BR 0
+success
+.TP
+.BR 1
+failure
+.TP
+.BR 64
+partial success
+.SH EXAMPLES
+.TP
+.B chmem --enable 1024
+This command requests 1024 MiB of memory to be set online.
+.TP
+.B chmem -e 2g
+This command requests 2 GiB of memory to be set online.
+.TP
+.B chmem --disable 0x00000000e4000000-0x00000000f3ffffff
+This command requests the memory range starting with 0x00000000e4000000
+and ending with 0x00000000f3ffffff to be set offline.
+.TP
+.B chmem -b -d 10
+This command requests the memory block number 10 to be set offline.
+.SH SEE ALSO
+.BR lsmem (1)
+.SH AVAILABILITY
+The \fBchmem\fP command is part of the util-linux package and is available from
+.UR ftp://\:ftp.kernel.org\:/pub\:/linux\:/utils\:/util-linux/
+Linux Kernel Archive
+.UE .
diff --git a/sys-utils/chmem.c b/sys-utils/chmem.c
new file mode 100644
index 000000000000..cc681b84c4c5
--- /dev/null
+++ b/sys-utils/chmem.c
@@ -0,0 +1,325 @@
+/*
+ * chmem - Memory configuration tool
+ *
+ * Copyright IBM Corp. 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <assert.h>
+#include <dirent.h>
+
+#include <c.h>
+#include <nls.h>
+#include <path.h>
+#include <strutils.h>
+#include <strv.h>
+#include <optutils.h>
+#include <closestream.h>
+#include <xalloc.h>
+
+/* partial success, otherwise we return regular EXIT_{SUCCESS,FAILURE} */
+#define CHMEM_EXIT_SOMEOK		64
+
+#define _PATH_SYS_MEMORY		"/sys/devices/system/memory"
+#define _PATH_SYS_MEMORY_BLOCK_SIZE	_PATH_SYS_MEMORY "/block_size_bytes"
+
+struct chmem_desc {
+	struct dirent	**dirs;
+	int		ndirs;
+	uint64_t	block_size;
+	uint64_t	start;
+	uint64_t	end;
+	uint64_t	size;
+	unsigned int	use_blocks : 1;
+	unsigned int	is_size	   : 1;
+	unsigned int	verbose	   : 1;
+};
+
+enum {
+	CMD_MEMORY_ENABLE = 0,
+	CMD_MEMORY_DISABLE,
+	CMD_NONE
+};
+
+static void idxtostr(struct chmem_desc *desc, uint64_t idx, char *buf, size_t bufsz)
+{
+	uint64_t start, end;
+
+	start = idx * desc->block_size;
+	end = start + desc->block_size - 1;
+	snprintf(buf, bufsz,
+		 _("Memory Block %"SCNu64" (0x%016"PRIx64"-0x%016"PRIx64")"),
+		 idx, start, end);
+}
+
+static int chmem_size(struct chmem_desc *desc, int enable)
+{
+	char *name, *onoff, line[BUFSIZ], str[BUFSIZ];
+	uint64_t size, index;
+	int i, rc;
+
+	size = desc->size;
+	onoff = enable ? "online" : "offline";
+	i = enable ? 0 : desc->ndirs - 1;
+	for (; i >= 0 && i < desc->ndirs && size; i += enable ? 1 : -1) {
+		name = desc->dirs[i]->d_name;
+		index = strtou64_or_err(name + 6, _("Failed to parse index"));
+		path_read_str(line, sizeof(line), _PATH_SYS_MEMORY "/%s/state", name);
+		if (strcmp(onoff, line) == 0)
+			continue;
+		idxtostr(desc, index, str, sizeof(str));
+		rc = path_write_str(onoff, _PATH_SYS_MEMORY"/%s/state", name);
+		if (rc == -1 && desc->verbose) {
+			if (enable)
+				fprintf(stdout, _("%s enable failed\n"), str);
+			else
+				fprintf(stdout, _("%s disable failed\n"), str);
+		} else if (rc == 0 && desc->verbose) {
+			if (enable)
+				fprintf(stdout, _("%s enabled\n"), str);
+			else
+				fprintf(stdout, _("%s disabled\n"), str);
+		}
+		if (rc == 0)
+			size--;
+	}
+	if (size) {
+		uint64_t bytes;
+		char *sizestr;
+
+		bytes = (desc->size - size) * desc->block_size;
+		sizestr = size_to_human_string(SIZE_SUFFIX_1LETTER, bytes);
+		if (enable)
+			warnx(_("Could only enable %s of memory"), sizestr);
+		else
+			warnx(_("Could only disable %s of memory"), sizestr);
+		free(sizestr);
+	}
+	return size == 0 ? 0 : size == desc->size ? -1 : 1;
+}
+
+static int chmem_range(struct chmem_desc *desc, int enable)
+{
+	char *name, *onoff, line[BUFSIZ], str[BUFSIZ];
+	uint64_t index, todo;
+	int i, rc;
+
+	todo = desc->end - desc->start + 1;
+	onoff = enable ? "online" : "offline";
+	for (i = 0; i < desc->ndirs; i++) {
+		name = desc->dirs[i]->d_name;
+		index = strtou64_or_err(name + 6, _("Failed to parse index"));
+		if (index < desc->start)
+			continue;
+		if (index > desc->end)
+			break;
+		idxtostr(desc, index, str, sizeof(str));
+		path_read_str(line, sizeof(line), _PATH_SYS_MEMORY "/%s/state", name);
+		if (strcmp(onoff, line) == 0) {
+			if (desc->verbose && enable)
+				fprintf(stdout, _("%s already enabled\n"), str);
+			else if (desc->verbose && !enable)
+				fprintf(stdout, _("%s already disabled\n"), str);
+			todo--;
+			continue;
+		}
+		rc = path_write_str(onoff, _PATH_SYS_MEMORY"/%s/state", name);
+		if (rc == -1) {
+			if (enable)
+				warn(_("%s enable failed"), str);
+			else
+				warn(_("%s disable failed"), str);
+		} else if (desc->verbose) {
+			if (enable)
+				fprintf(stdout, _("%s enabled\n"), str);
+			else
+				fprintf(stdout, _("%s disabled\n"), str);
+		}
+		if (rc == 0)
+			todo--;
+	}
+	return todo == 0 ? 0 : todo == desc->end - desc->start + 1 ? -1 : 1;
+}
+
+static int filter(const struct dirent *de)
+{
+	if (strncmp("memory", de->d_name, 6))
+		return 0;
+	return isdigit_string(de->d_name + 6);
+}
+
+static void read_info(struct chmem_desc *desc)
+{
+	char line[BUFSIZ];
+
+	desc->ndirs = scandir(_PATH_SYS_MEMORY, &desc->dirs, filter, versionsort);
+	if (desc->ndirs <= 0)
+		err(EXIT_FAILURE, _("Failed to read %s"), _PATH_SYS_MEMORY);
+	path_read_str(line, sizeof(line), _PATH_SYS_MEMORY_BLOCK_SIZE);
+	desc->block_size = strtoumax(line, NULL, 16);
+}
+
+static void parse_single_param(struct chmem_desc *desc, char *str)
+{
+	if (desc->use_blocks) {
+		desc->start = strtou64_or_err(str, _("Failed to parse block number"));
+		desc->end = desc->start;
+		return;
+	}
+	desc->is_size = 1;
+	desc->size = strtosize_or_err(str, _("Failed to parse size"));
+	if (isdigit(str[strlen(str) - 1]))
+		desc->size *= 1024*1024;
+	if (desc->size % desc->block_size) {
+		errx(EXIT_FAILURE, _("Size must be aligned to memory block size (%s)"),
+		     size_to_human_string(SIZE_SUFFIX_1LETTER, desc->block_size));
+	}
+	desc->size /= desc->block_size;
+}
+
+static void parse_range_param(struct chmem_desc *desc, char *start, char *end)
+{
+	if (desc->use_blocks) {
+		desc->start = strtou64_or_err(start, _("Failed to parse start"));
+		desc->end = strtou64_or_err(end, _("Failed to parse end"));
+		return;
+	}
+	if (strlen(start) < 2 || start[1] != 'x')
+		errx(EXIT_FAILURE, _("Invalid start address format: %s"), start);
+	if (strlen(end) < 2 || end[1] != 'x')
+		errx(EXIT_FAILURE, _("Invalid end address format: %s"), end);
+	desc->start = strtox64_or_err(start, _("Failed to parse start address"));
+	desc->end = strtox64_or_err(end, _("Failed to parse end address"));
+	if (desc->start % desc->block_size || (desc->end + 1) % desc->block_size) {
+		errx(EXIT_FAILURE,
+		     _("Start address and (end address + 1) must be aligned to "
+		       "memory block size (%s)"),
+		     size_to_human_string(SIZE_SUFFIX_1LETTER, desc->block_size));
+	}
+	desc->start /= desc->block_size;
+	desc->end /= desc->block_size;
+}
+
+static void parse_parameter(struct chmem_desc *desc, char *param)
+{
+	char **split;
+
+	split = strv_split(param, "-");
+	if (strv_length(split) > 2)
+		errx(EXIT_FAILURE, _("Invalid parameter: %s"), param);
+	if (strv_length(split) == 1)
+		parse_single_param(desc, split[0]);
+	else
+		parse_range_param(desc, split[0], split[1]);
+	strv_free(split);
+	if (desc->start > desc->end)
+		errx(EXIT_FAILURE, _("Invalid range: %s"), param);
+}
+
+static void __attribute__((__noreturn__)) chmem_usage(FILE *out)
+{
+	fputs(USAGE_HEADER, out);
+	fprintf(out, _(" %s [options] [SIZE|RANGE|BLOCKRANGE]\n"), program_invocation_short_name);
+
+	fputs(USAGE_SEPARATOR, out);
+	fputs(_("Set a particular size or range of memory online or offline.\n"), out);
+
+	fputs(USAGE_OPTIONS, out);
+	fputs(_(" -e, --enable   enable memory\n"), out);
+	fputs(_(" -d, --disable  disable memory\n"), out);
+	fputs(_(" -b, --blocks   use memory blocks\n"), out);
+	fputs(_(" -v, --verbose  verbose output\n"), out);
+	fputs(USAGE_SEPARATOR, out);
+	fputs(USAGE_HELP, out);
+	fputs(USAGE_VERSION, out);
+
+	fprintf(out, USAGE_MAN_TAIL("chmem(8)"));
+
+	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+int main(int argc, char **argv)
+{
+	struct chmem_desc _desc = { }, *desc = &_desc;
+	int cmd = CMD_NONE;
+	int c, rc;
+
+	static const struct option longopts[] = {
+		{"block",	no_argument,		NULL, 'b'},
+		{"disable",	no_argument,		NULL, 'd'},
+		{"enable",	no_argument,		NULL, 'e'},
+		{"help",	no_argument,		NULL, 'h'},
+		{"verbose",	no_argument,		NULL, 'v'},
+		{"version",	no_argument,		NULL, 'V'},
+		{NULL,		0,			NULL, 0}
+	};
+
+	static const ul_excl_t excl[] = {	/* rows and cols in ASCII order */
+		{ 'd','e' },
+		{ 0 }
+	};
+	int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
+
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+	atexit(close_stdout);
+
+	read_info(desc);
+
+	while ((c = getopt_long(argc, argv, "bdehvV", longopts, NULL)) != -1) {
+
+		err_exclusive_options(c, longopts, excl, excl_st);
+
+		switch (c) {
+		case 'd':
+			cmd = CMD_MEMORY_DISABLE;
+			break;
+		case 'e':
+			cmd = CMD_MEMORY_ENABLE;
+			break;
+		case 'b':
+			desc->use_blocks = 1;
+			break;
+		case 'h':
+			chmem_usage(stdout);
+			break;
+		case 'v':
+			desc->verbose = 1;
+			break;
+		case 'V':
+			printf(UTIL_LINUX_VERSION);
+			return EXIT_SUCCESS;
+		}
+	}
+
+	if ((argc == 1) || (argc != optind + 1) || (cmd == CMD_NONE))
+		chmem_usage(stderr);
+
+	parse_parameter(desc, argv[optind]);
+
+	if (desc->is_size)
+		rc = chmem_size(desc, cmd == CMD_MEMORY_ENABLE ? 1 : 0);
+	else
+		rc = chmem_range(desc, cmd == CMD_MEMORY_ENABLE ? 1 : 0);
+
+	return rc == 0 ? EXIT_SUCCESS :
+		rc < 0 ? EXIT_FAILURE : CHMEM_EXIT_SOMEOK;
+}
-- 
2.8.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/4] lsmem: add testcase
  2016-10-12 12:00 [PATCH 0/4] New tools lsmem and chmem Heiko Carstens
                   ` (2 preceding siblings ...)
  2016-10-12 12:00 ` [PATCH 3/4] chmem: " Heiko Carstens
@ 2016-10-12 12:00 ` Heiko Carstens
  2016-10-19  9:38 ` [PATCH 0/4] New tools lsmem and chmem Karel Zak
  4 siblings, 0 replies; 13+ messages in thread
From: Heiko Carstens @ 2016-10-12 12:00 UTC (permalink / raw)
  To: Karel Zak; +Cc: util-linux, Gerald Schaefer

Add a single s390 specific test case to verify that the contents of
various output formats do not change in incompatible way if the
lsmem code is changed.

This is based on a patch from Clemens von Mann.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
---
 tests/commands.sh                        |   1 +
 tests/expected/lsmem/lsmem-s390-zvm-6g   |  91 +++++++++++++++++++++++++++++++
 tests/ts/lsmem/dumps/s390-zvm-6g.tar.bz2 | Bin 0 -> 2459 bytes
 tests/ts/lsmem/lsmem                     |  52 ++++++++++++++++++
 tests/ts/lsmem/mk-input.sh               |  22 ++++++++
 5 files changed, 166 insertions(+)
 create mode 100644 tests/expected/lsmem/lsmem-s390-zvm-6g
 create mode 100644 tests/ts/lsmem/dumps/s390-zvm-6g.tar.bz2
 create mode 100755 tests/ts/lsmem/lsmem
 create mode 100755 tests/ts/lsmem/mk-input.sh

diff --git a/tests/commands.sh b/tests/commands.sh
index e0a9b0d13831..1ec7d258417d 100644
--- a/tests/commands.sh
+++ b/tests/commands.sh
@@ -67,6 +67,7 @@ TS_CMD_LOOK=${TS_CMD_LOOK-"$top_builddir/look"}
 TS_CMD_LOSETUP=${TS_CMD_LOSETUP:-"$top_builddir/losetup"}
 TS_CMD_LSBLK=${TS_CMD_LSBLK-"$top_builddir/lsblk"}
 TS_CMD_LSCPU=${TS_CMD_LSCPU-"$top_builddir/lscpu"}
+TS_CMD_LSMEM=${TS_CMD_LSMEM-"$top_builddir/lsmem"}
 TS_CMD_MCOOKIE=${TS_CMD_MCOOKIE-"$top_builddir/mcookie"}
 TS_CMD_MKCRAMFS=${TS_CMD_MKCRAMFS:-"$top_builddir/mkfs.cramfs"}
 TS_CMD_MKMINIX=${TS_CMD_MKMINIX:-"$top_builddir/mkfs.minix"}
diff --git a/tests/expected/lsmem/lsmem-s390-zvm-6g b/tests/expected/lsmem/lsmem-s390-zvm-6g
new file mode 100644
index 000000000000..be244ad5c488
--- /dev/null
+++ b/tests/expected/lsmem/lsmem-s390-zvm-6g
@@ -0,0 +1,91 @@
+>lsmem
+RANGE                                 SIZE STATE   REMOVABLE BLOCK
+0x0000000000000000-0x000000006fffffff 1.8G online  yes       0-6
+0x0000000070000000-0x000000007fffffff 256M online  no        7
+0x0000000080000000-0x000000009fffffff 512M online  yes       8-9
+0x00000000a0000000-0x00000000bfffffff 512M online  no        10-11
+0x00000000c0000000-0x00000000dfffffff 512M online  yes       12-13
+0x00000000e0000000-0x00000000efffffff 256M offline -         14
+0x00000000f0000000-0x00000000ffffffff 256M online  yes       15
+0x0000000100000000-0x000000011fffffff 512M online  no        16-17
+0x0000000120000000-0x000000013fffffff 512M online  yes       18-19
+0x0000000140000000-0x000000017fffffff   1G offline -         20-23
+
+Memory block size   :     256M
+Total online memory :     4.8G
+Total offline memory:     1.3G
+
+>lsmem -a
+RANGE                                 SIZE STATE   REMOVABLE BLOCK
+0x0000000000000000-0x000000000fffffff 256M online  yes       0
+0x0000000010000000-0x000000001fffffff 256M online  yes       1
+0x0000000020000000-0x000000002fffffff 256M online  yes       2
+0x0000000030000000-0x000000003fffffff 256M online  yes       3
+0x0000000040000000-0x000000004fffffff 256M online  yes       4
+0x0000000050000000-0x000000005fffffff 256M online  yes       5
+0x0000000060000000-0x000000006fffffff 256M online  yes       6
+0x0000000070000000-0x000000007fffffff 256M online  no        7
+0x0000000080000000-0x000000008fffffff 256M online  yes       8
+0x0000000090000000-0x000000009fffffff 256M online  yes       9
+0x00000000a0000000-0x00000000afffffff 256M online  no        10
+0x00000000b0000000-0x00000000bfffffff 256M online  no        11
+0x00000000c0000000-0x00000000cfffffff 256M online  yes       12
+0x00000000d0000000-0x00000000dfffffff 256M online  yes       13
+0x00000000e0000000-0x00000000efffffff 256M offline -         14
+0x00000000f0000000-0x00000000ffffffff 256M online  yes       15
+0x0000000100000000-0x000000010fffffff 256M online  no        16
+0x0000000110000000-0x000000011fffffff 256M online  no        17
+0x0000000120000000-0x000000012fffffff 256M online  yes       18
+0x0000000130000000-0x000000013fffffff 256M online  yes       19
+0x0000000140000000-0x000000014fffffff 256M offline -         20
+0x0000000150000000-0x000000015fffffff 256M offline -         21
+0x0000000160000000-0x000000016fffffff 256M offline -         22
+0x0000000170000000-0x000000017fffffff 256M offline -         23
+
+Memory block size   :     256M
+Total online memory :     4.8G
+Total offline memory:     1.3G
+
+>lsmem -e
+RANGE                                 SIZE STATE   REMOVABLE BLOCK NODE
+0x0000000000000000-0x000000006fffffff 1.8G online  yes       0-6   0
+0x0000000070000000-0x000000007fffffff 256M online  no        7     0
+0x0000000080000000-0x000000009fffffff 512M online  yes       8-9   0
+0x00000000a0000000-0x00000000bfffffff 512M online  no        10-11 0
+0x00000000c0000000-0x00000000dfffffff 512M online  yes       12-13 0
+0x00000000e0000000-0x00000000efffffff 256M offline -         14    0
+0x00000000f0000000-0x00000000ffffffff 256M online  yes       15    0
+0x0000000100000000-0x000000011fffffff 512M online  no        16-17 0
+0x0000000120000000-0x000000013fffffff 512M online  yes       18-19 0
+0x0000000140000000-0x000000017fffffff   1G offline -         20-23 0
+
+Memory block size   :     256M
+Total online memory :     4.8G
+Total offline memory:     1.3G
+
+>lsmem -p -a
+# RANGE,SIZE,STATE,REMOVABLE,BLOCK,NODE
+0x0000000000000000-0x000000000fffffff,268435456,online,yes,0,0
+0x0000000010000000-0x000000001fffffff,268435456,online,yes,1,0
+0x0000000020000000-0x000000002fffffff,268435456,online,yes,2,0
+0x0000000030000000-0x000000003fffffff,268435456,online,yes,3,0
+0x0000000040000000-0x000000004fffffff,268435456,online,yes,4,0
+0x0000000050000000-0x000000005fffffff,268435456,online,yes,5,0
+0x0000000060000000-0x000000006fffffff,268435456,online,yes,6,0
+0x0000000070000000-0x000000007fffffff,268435456,online,no,7,0
+0x0000000080000000-0x000000008fffffff,268435456,online,yes,8,0
+0x0000000090000000-0x000000009fffffff,268435456,online,yes,9,0
+0x00000000a0000000-0x00000000afffffff,268435456,online,no,10,0
+0x00000000b0000000-0x00000000bfffffff,268435456,online,no,11,0
+0x00000000c0000000-0x00000000cfffffff,268435456,online,yes,12,0
+0x00000000d0000000-0x00000000dfffffff,268435456,online,yes,13,0
+0x00000000e0000000-0x00000000efffffff,268435456,offline,-,14,0
+0x00000000f0000000-0x00000000ffffffff,268435456,online,yes,15,0
+0x0000000100000000-0x000000010fffffff,268435456,online,no,16,0
+0x0000000110000000-0x000000011fffffff,268435456,online,no,17,0
+0x0000000120000000-0x000000012fffffff,268435456,online,yes,18,0
+0x0000000130000000-0x000000013fffffff,268435456,online,yes,19,0
+0x0000000140000000-0x000000014fffffff,268435456,offline,-,20,0
+0x0000000150000000-0x000000015fffffff,268435456,offline,-,21,0
+0x0000000160000000-0x000000016fffffff,268435456,offline,-,22,0
+0x0000000170000000-0x000000017fffffff,268435456,offline,-,23,0
diff --git a/tests/ts/lsmem/dumps/s390-zvm-6g.tar.bz2 b/tests/ts/lsmem/dumps/s390-zvm-6g.tar.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..b4dab8ed827fb3633d5803c6f04883c995f25ec2
GIT binary patch
literal 2459
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
K;qGKd>i!41ZDW`K

literal 0
HcmV?d00001

diff --git a/tests/ts/lsmem/lsmem b/tests/ts/lsmem/lsmem
new file mode 100755
index 000000000000..7e6e2f959cda
--- /dev/null
+++ b/tests/ts/lsmem/lsmem
@@ -0,0 +1,52 @@
+#!/bin/bash
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+TS_TOPDIR="${0%/*}/../.."
+. $TS_TOPDIR/functions.sh
+
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_LSMEM"
+
+for dump in $(ls $TS_SELF/dumps/*.tar.bz2 | sort); do
+	name=$(basename $dump .tar.bz2)
+	dumpdir="$TS_OUTDIR/dumps"
+
+	ts_init_subtest $name
+	mkdir -p $dumpdir
+
+	tar -C $dumpdir -jxf $dump
+
+	echo ">lsmem" >>"${TS_OUTPUT}"
+	"${TS_CMD_LSMEM}" -s "${dumpdir}/${name}" >>"${TS_OUTPUT}" 2>&1
+
+	echo >>"${TS_OUTPUT}"
+	echo ">lsmem -a" >>"${TS_OUTPUT}"
+	"${TS_CMD_LSMEM}" -a -s "${dumpdir}/${name}" >>"${TS_OUTPUT}" 2>&1
+
+	echo >>"${TS_OUTPUT}"
+	echo ">lsmem -e" >>"${TS_OUTPUT}"
+	"${TS_CMD_LSMEM}" -e -s "${dumpdir}/${name}" >>"${TS_OUTPUT}" 2>&1
+
+	echo >>"${TS_OUTPUT}"
+	echo ">lsmem -p -a" >>"${TS_OUTPUT}"
+	"${TS_CMD_LSMEM}" -p -a -s "${dumpdir}/${name}" >>"${TS_OUTPUT}" 2>&1
+
+	ts_finalize_subtest
+done
+
+ts_finalize
diff --git a/tests/ts/lsmem/mk-input.sh b/tests/ts/lsmem/mk-input.sh
new file mode 100755
index 000000000000..e9a4e7206b7f
--- /dev/null
+++ b/tests/ts/lsmem/mk-input.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This script makes a copy of relevant files from /sys.
+# The files are useful for lscpu(1) regression tests.
+#
+progname=$(basename $0)
+
+if [ -z "$1" ]; then
+	echo -e "\nusage: $progname <testname>\n"
+	exit 1
+fi
+
+TS_NAME="$1"
+TS_DUMP="$TS_NAME"
+CP="cp -r --parent"
+
+mkdir -p $TS_DUMP/sys/devices/system
+
+$CP /sys/devices/system/memory $TS_DUMP
+
+tar jcvf $TS_NAME.tar.bz2 $TS_DUMP
+rm -rf $TS_DUMP
-- 
2.8.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/4] New tools lsmem and chmem
  2016-10-12 12:00 [PATCH 0/4] New tools lsmem and chmem Heiko Carstens
                   ` (3 preceding siblings ...)
  2016-10-12 12:00 ` [PATCH 4/4] lsmem: add testcase Heiko Carstens
@ 2016-10-19  9:38 ` Karel Zak
  2016-10-19  9:59   ` Heiko Carstens
  4 siblings, 1 reply; 13+ messages in thread
From: Karel Zak @ 2016-10-19  9:38 UTC (permalink / raw)
  To: Heiko Carstens; +Cc: util-linux, Gerald Schaefer

On Wed, Oct 12, 2016 at 02:00:43PM +0200, Heiko Carstens wrote:
> This small patch series adds the tools lsmem and chmem to util-linux.

At first glance, it seems correct. I'm going to merge it later
after v2.29 release. Thanks.

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/4] New tools lsmem and chmem
  2016-10-19  9:38 ` [PATCH 0/4] New tools lsmem and chmem Karel Zak
@ 2016-10-19  9:59   ` Heiko Carstens
  0 siblings, 0 replies; 13+ messages in thread
From: Heiko Carstens @ 2016-10-19  9:59 UTC (permalink / raw)
  To: Karel Zak; +Cc: util-linux, Gerald Schaefer

On Wed, Oct 19, 2016 at 11:38:39AM +0200, Karel Zak wrote:
> On Wed, Oct 12, 2016 at 02:00:43PM +0200, Heiko Carstens wrote:
> > This small patch series adds the tools lsmem and chmem to util-linux.
> 
> At first glance, it seems correct. I'm going to merge it later
> after v2.29 release. Thanks.

Great, thanks!

Heiko

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 3/4] chmem: new tool
  2016-10-12 12:00 ` [PATCH 3/4] chmem: " Heiko Carstens
@ 2016-10-19 10:40   ` Heiko Carstens
  0 siblings, 0 replies; 13+ messages in thread
From: Heiko Carstens @ 2016-10-19 10:40 UTC (permalink / raw)
  To: Karel Zak, util-linux, Gerald Schaefer

On Wed, Oct 12, 2016 at 02:00:46PM +0200, Heiko Carstens wrote:
> Move the s390 specific chmem tool to util-linux.
> 
> The chmem tool was originally written in perl and is part of the
> s390-tools package which can be found here:
> https://www.ibm.com/developerworks/linux/linux390/s390-tools.html
> 
> Given that the tool is architecture independent, there is no reason to
> keep it in an s390 specific repository. It seems to be useful for
> other architectures as well.
> 
> This patch converts the tool to C and adds it to util-linux, while the
> command line options stay compatible. The only exception is the option
> "-v" which used to be the short form of "--version". That got changed
> to "-V" so it behaves like most other tools contained within
> util-linux.
> 
> The chmem tool can be used to set memory online or offline. This can
> be achieved by specifying a memory range:
> 
> Memory Block 19 (0x0000000130000000-0x000000013fffffff) disabled
> 
> or by specifying a size where chmem will automatically select memory
> blocks:
> 
> Memory Block 21 (0x0000000150000000-0x000000015fffffff) disable failed
> Memory Block 18 (0x0000000120000000-0x000000012fffffff) disabled
> Memory Block 17 (0x0000000110000000-0x000000011fffffff) disabled
> Memory Block 16 (0x0000000100000000-0x000000010fffffff) disabled
> Memory Block 15 (0x00000000f0000000-0x00000000ffffffff) disabled
> 
> or by specifying memory block numbers instead of address ranges:
> 
> Memory Block 15 (0x00000000f0000000-0x00000000ffffffff) disabled
> Memory Block 16 (0x0000000100000000-0x000000010fffffff) disabled
> Memory Block 17 (0x0000000110000000-0x000000011fffffff) disabled
> Memory Block 18 (0x0000000120000000-0x000000012fffffff) disabled
> 
> This is based on a patch from Clemens von Mann.
> 
> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

I just realized that the above "examples" don't make sense, since the
commands that were used are missing. That happened because I started the
lines with "#", which apparently git assumed to be a comment and therefore
ignored the lines.

So the correct description, which contains the commands, should be:

> The chmem tool can be used to set memory online or offline. This can
> be achieved by specifying a memory range:
>
> $ chmem -v -d 0x0000000130000000-0x000000013fffffff
> Memory Block 19 (0x0000000130000000-0x000000013fffffff) disabled
>
> or by specifying a size where chmem will automatically select memory
> blocks:
>
> $ chmem -v -d  1g
> Memory Block 21 (0x0000000150000000-0x000000015fffffff) disable failed
> Memory Block 18 (0x0000000120000000-0x000000012fffffff) disabled
> Memory Block 17 (0x0000000110000000-0x000000011fffffff) disabled
> Memory Block 16 (0x0000000100000000-0x000000010fffffff) disabled
> Memory Block 15 (0x00000000f0000000-0x00000000ffffffff) disabled
>
> or by specifying memory block numbers instead of address ranges:
>
> $ chmem -v -d -b 15-18
> Memory Block 15 (0x00000000f0000000-0x00000000ffffffff) disabled
> Memory Block 16 (0x0000000100000000-0x000000010fffffff) disabled
> Memory Block 17 (0x0000000110000000-0x000000011fffffff) disabled
> Memory Block 18 (0x0000000120000000-0x000000012fffffff) disabled


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/4] lsmem: new tool
  2016-10-12 12:00 ` [PATCH 2/4] lsmem: new tool Heiko Carstens
@ 2016-11-03 12:00   ` Karel Zak
  2016-11-03 16:19     ` Heiko Carstens
  0 siblings, 1 reply; 13+ messages in thread
From: Karel Zak @ 2016-11-03 12:00 UTC (permalink / raw)
  To: Heiko Carstens; +Cc: util-linux, Gerald Schaefer

On Wed, Oct 12, 2016 at 02:00:45PM +0200, Heiko Carstens wrote:
> RANGE                                 SIZE STATE   REMOVABLE BLOCK
> 0x0000000000000000-0x000000005fffffff 1,5G online  yes       0-5
> 0x0000000060000000-0x000000007fffffff 512M online  no        6-7
> 0x0000000080000000-0x000000013fffffff   3G online  yes       8-19
> 0x0000000140000000-0x000000014fffffff 256M offline -         20
> 0x0000000150000000-0x000000017fffffff 768M online  no        21-23
> 
> Memory block size   :     256M
> Total online memory :     5,8G
> Total offline memory:     256M

It seems that for backward compatibility we need the summary lines at
the end. Maybe we can add --no-summary and --summary-only for people
who want to use it in the scripts.
 
> The lsmem tool also has "--extendend" and "--parsable" option which
> can be used to customize the output, e.g.  limit the output to
> specified columns. This is quite similar to what the lscpu tool does.

Frankly, I don't like these lscpu options :-) For new tools we have
--pairs/export (NAME=value), --raw, --json and --output=<list>. 

You do not need to re-submit the patches, I'll cleanup the stuff.

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/4] lsmem: new tool
  2016-11-03 12:00   ` Karel Zak
@ 2016-11-03 16:19     ` Heiko Carstens
  2016-11-04 10:39       ` Karel Zak
  0 siblings, 1 reply; 13+ messages in thread
From: Heiko Carstens @ 2016-11-03 16:19 UTC (permalink / raw)
  To: Karel Zak; +Cc: util-linux, Gerald Schaefer

On Thu, Nov 03, 2016 at 01:00:59PM +0100, Karel Zak wrote:
> On Wed, Oct 12, 2016 at 02:00:45PM +0200, Heiko Carstens wrote:
> > RANGE                                 SIZE STATE   REMOVABLE BLOCK
> > 0x0000000000000000-0x000000005fffffff 1,5G online  yes       0-5
> > 0x0000000060000000-0x000000007fffffff 512M online  no        6-7
> > 0x0000000080000000-0x000000013fffffff   3G online  yes       8-19
> > 0x0000000140000000-0x000000014fffffff 256M offline -         20
> > 0x0000000150000000-0x000000017fffffff 768M online  no        21-23
> > 
> > Memory block size   :     256M
> > Total online memory :     5,8G
> > Total offline memory:     256M
> 
> It seems that for backward compatibility we need the summary lines at
> the end. Maybe we can add --no-summary and --summary-only for people
> who want to use it in the scripts.

Scripts should use the --parsable option (or one of the new options you
mentioned below), no?
However it's of course fine with me to make the summary lines optional.

> > The lsmem tool also has "--extendend" and "--parsable" option which
> > can be used to customize the output, e.g.  limit the output to
> > specified columns. This is quite similar to what the lscpu tool does.
> 
> Frankly, I don't like these lscpu options :-) For new tools we have
> --pairs/export (NAME=value), --raw, --json and --output=<list>. 
> 
> You do not need to re-submit the patches, I'll cleanup the stuff.

Also fine with me :) Thank you for taking care of this!


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/4] lsmem: new tool
  2016-11-03 16:19     ` Heiko Carstens
@ 2016-11-04 10:39       ` Karel Zak
  2016-11-04 12:10         ` Heiko Carstens
  0 siblings, 1 reply; 13+ messages in thread
From: Karel Zak @ 2016-11-04 10:39 UTC (permalink / raw)
  To: Heiko Carstens; +Cc: util-linux, Gerald Schaefer

On Thu, Nov 03, 2016 at 05:19:48PM +0100, Heiko Carstens wrote:
> On Thu, Nov 03, 2016 at 01:00:59PM +0100, Karel Zak wrote:
> > On Wed, Oct 12, 2016 at 02:00:45PM +0200, Heiko Carstens wrote:
> > > RANGE                                 SIZE STATE   REMOVABLE BLOCK
> > > 0x0000000000000000-0x000000005fffffff 1,5G online  yes       0-5
> > > 0x0000000060000000-0x000000007fffffff 512M online  no        6-7
> > > 0x0000000080000000-0x000000013fffffff   3G online  yes       8-19
> > > 0x0000000140000000-0x000000014fffffff 256M offline -         20
> > > 0x0000000150000000-0x000000017fffffff 768M online  no        21-23
> > > 
> > > Memory block size   :     256M
> > > Total online memory :     5,8G
> > > Total offline memory:     256M
> > 
> > It seems that for backward compatibility we need the summary lines at
> > the end. Maybe we can add --no-summary and --summary-only for people
> > who want to use it in the scripts.
> 
> Scripts should use the --parsable option (or one of the new options you
> mentioned below), no?

Yes, good point.

> However it's of course fine with me to make the summary lines optional.

I have added --summary[=never,always,only]

    never  - disable summary lines at all (forced for parsable  outputs)
    always - default for standard output
    only   - prints only summary, no table with blocks, default when
             --summary specified without argument

> Also fine with me :) Thank you for taking care of this!

    https://github.com/karelzak/util-linux/tree/mem-tools

This branch contains the new lsmem; the next week I'll cleanup chmem 
and merge it to the master branch (after v2.29 release, probably
Monday).

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/4] lsmem: new tool
  2016-11-04 10:39       ` Karel Zak
@ 2016-11-04 12:10         ` Heiko Carstens
  2016-11-09  9:16           ` Karel Zak
  0 siblings, 1 reply; 13+ messages in thread
From: Heiko Carstens @ 2016-11-04 12:10 UTC (permalink / raw)
  To: Karel Zak; +Cc: util-linux, Gerald Schaefer

On Fri, Nov 04, 2016 at 11:39:31AM +0100, Karel Zak wrote:
> > However it's of course fine with me to make the summary lines optional.
> 
> I have added --summary[=never,always,only]
> 
>     never  - disable summary lines at all (forced for parsable  outputs)
>     always - default for standard output
>     only   - prints only summary, no table with blocks, default when
>              --summary specified without argument
> 
> > Also fine with me :) Thank you for taking care of this!
> 
>     https://github.com/karelzak/util-linux/tree/mem-tools
> 
> This branch contains the new lsmem; the next week I'll cleanup chmem 
> and merge it to the master branch (after v2.29 release, probably
> Monday).

Looks all good to me. Just two comments:

- you changed the alignment of nearly all columns from left to right,
except for STATE and RANGE. For RANGE it does make sense to keep it aligned
to the left, however for STATE it looks a bit inconsistent. Not sure if you
missed to make it also align to the right?

- the updated man page now says that the default output is subject to
change; but it should not change in order to be compatible with the old
lsmem tool within s390-tools.

Also you might consider applying the simple patch below ;)

>From 270714b84caae0977e12afd7f59f88e051463e66 Mon Sep 17 00:00:00 2001
From: Heiko Carstens <heiko.carstens@de.ibm.com>
Date: Fri, 4 Nov 2016 12:56:08 +0100
Subject: [PATCH] lsmem: improve node lookup

Break the loop as soon as we found the node a memory block belongs to,
it doesn't make sense to continue scanning.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
---
 sys-utils/lsmem.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys-utils/lsmem.c b/sys-utils/lsmem.c
index 1dcf8a8e405d..10afc3cb6c8c 100644
--- a/sys-utils/lsmem.c
+++ b/sys-utils/lsmem.c
@@ -265,6 +265,7 @@ static int memory_block_get_node(char *name)
 		if (!isdigit_string(de->d_name + 4))
 			continue;
 		node = strtol(de->d_name + 4, NULL, 10);
+		break;
 	}
 	closedir(dir);
 	return node;
-- 
2.8.4


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/4] lsmem: new tool
  2016-11-04 12:10         ` Heiko Carstens
@ 2016-11-09  9:16           ` Karel Zak
  0 siblings, 0 replies; 13+ messages in thread
From: Karel Zak @ 2016-11-09  9:16 UTC (permalink / raw)
  To: Heiko Carstens; +Cc: util-linux, Gerald Schaefer

On Fri, Nov 04, 2016 at 01:10:06PM +0100, Heiko Carstens wrote:
> - you changed the alignment of nearly all columns from left to right,
> except for STATE and RANGE. For RANGE it does make sense to keep it aligned
> to the left, however for STATE it looks a bit inconsistent. Not sure if you
> missed to make it also align to the right?

Fixed, STATE is aligned to the right too.

> - the updated man page now says that the default output is subject to
> change; but it should not change in order to be compatible with the old
> lsmem tool within s390-tools.

Well, I'd like to force users to use --output in scripts for our
ls-like tools, but you're right. We should be friendly to the current
s390-tools users.  I have a little bit changed the sentence, and now
it recommends --output and there is also note about compatibility with
s390-tools.

>  sys-utils/lsmem.c | 1 +
>  1 file changed, 1 insertion(+)

Applied, thanks. All merged to the master branch now. 


Thanks to IBM that you don't play on your own playground only and you
consolidate things in more generic way!

    Karel



-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2016-11-09  9:16 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-12 12:00 [PATCH 0/4] New tools lsmem and chmem Heiko Carstens
2016-10-12 12:00 ` [PATCH 1/4] lib,strutils: add strtoux[16|32|64]_or_err functions Heiko Carstens
2016-10-12 12:00 ` [PATCH 2/4] lsmem: new tool Heiko Carstens
2016-11-03 12:00   ` Karel Zak
2016-11-03 16:19     ` Heiko Carstens
2016-11-04 10:39       ` Karel Zak
2016-11-04 12:10         ` Heiko Carstens
2016-11-09  9:16           ` Karel Zak
2016-10-12 12:00 ` [PATCH 3/4] chmem: " Heiko Carstens
2016-10-19 10:40   ` Heiko Carstens
2016-10-12 12:00 ` [PATCH 4/4] lsmem: add testcase Heiko Carstens
2016-10-19  9:38 ` [PATCH 0/4] New tools lsmem and chmem Karel Zak
2016-10-19  9:59   ` Heiko Carstens

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.