summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Zak2017-10-20 12:31:09 +0200
committerKarel Zak2017-10-20 12:37:04 +0200
commitd12e945dbf7758e43ec4aaadd0c8c28c1269236e (patch)
treea0aecdad06053c8e857e425518b711b709cd8551
parentlsmem: add hint about block merges to the man page (diff)
downloadkernel-qcow2-util-linux-d12e945dbf7758e43ec4aaadd0c8c28c1269236e.tar.gz
kernel-qcow2-util-linux-d12e945dbf7758e43ec4aaadd0c8c28c1269236e.tar.xz
kernel-qcow2-util-linux-d12e945dbf7758e43ec4aaadd0c8c28c1269236e.zip
lsmem: add --split
Now the way how lsmem lists memory ranges is affected by used output columns. It makes it very difficult to use in scripts where you want to use for example only one column ranges=$(lsmem -oRANGE) and in this case all is merged to the one (or two) huge ranges and all attributes are ignored. The --split allows to control this behavior ranges=$(lsmem -oRANGE --split=STATE,ZONES) forces lsmem to list ranges by STATE and ZONES differences. Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r--sys-utils/chmem.83
-rw-r--r--sys-utils/lsmem.127
-rw-r--r--sys-utils/lsmem.c79
3 files changed, 74 insertions, 35 deletions
diff --git a/sys-utils/chmem.8 b/sys-utils/chmem.8
index b37ee8382..dae7413d4 100644
--- a/sys-utils/chmem.8
+++ b/sys-utils/chmem.8
@@ -17,8 +17,7 @@ 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. Note that the range
-as shown by \fBlsmem\fP command maybe be influenced by zones (\fBlsmem -o +ZONES\fP).
+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
diff --git a/sys-utils/lsmem.1 b/sys-utils/lsmem.1
index c664273f0..af65c2abb 100644
--- a/sys-utils/lsmem.1
+++ b/sys-utils/lsmem.1
@@ -10,19 +10,29 @@ 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.
-The default output compatible with original implementaion from s390-tools, but
+The default output compatible with original implementation from s390-tools, but
it's strongly recommended to avoid using default outputs in your scripts.
Always explicitly define expected columns by using the \fB\-\-output\fR option
together with a columns list in environments where a stable output is required.
+The \fBlsmem\fP command lists a new memory range always when the current memory
+block distinguish from the previous block by STATE, REMOVABLE, NODE or ZONES
+attribute. This default behavior is possible to override by the
+\fB\-\-split\fR option (e.g. \fBlsmem \-\-split=STATE,ZONES\fR). The special
+word "none" may be used to ignore all differences between memory blocks and to
+create as large as possible continuous ranges. The opposite semantic is
+\fB\-\-all\fR to list individual memory blocks. The default split policy is
+subject to change. Always explicitly use \fB\-\-split\fR in environments where
+a stable output is required.
+
+Note that some output columns may provide inaccurate information if a split policy
+forces \fBlsmem\fP to ignore diffrences in some attributes. For example if you
+merge removable and non-removable memory blocks to the one range than all
+the range will be marked as non-removable on \fBlsmem\fP output.
+
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.
-The number of output entries (memory ranges) maybe be influenced by specified
-columns. The lsmem command shows larger memory ranges if the blocks in the
-range do not distinguish in output columns. For example RANGE maybe be
-different if the command output contains column ZONES (lsmem -o +ZONES).
-
Use the \fB\-\-help\fR option to see the columns description.
.SH OPTIONS
@@ -57,6 +67,11 @@ All potentially unsafe characters are hex-escaped (\\x<code>).
Produce output in raw format. All potentially unsafe characters are hex-escaped
(\\x<code>).
.TP
+.BR \-S , " \-\-split " \fIlist\fP
+Specify which columns (attributes) use to split memory blocks to ranges. The
+supported columns are STATE, REMOVABLE, NODE and ZONES, or "none". The another columns are
+silently ignored. For more details see DESCRIPTION above.
+.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
diff --git a/sys-utils/lsmem.c b/sys-utils/lsmem.c
index 6def429ec..97376de38 100644
--- a/sys-utils/lsmem.c
+++ b/sys-utils/lsmem.c
@@ -82,15 +82,16 @@ struct lsmem {
summary : 1,
list_all : 1,
bytes : 1,
- want_node : 1,
- want_state : 1,
- want_removable : 1,
want_summary : 1,
want_table : 1,
- want_zones : 1,
+ split_by_node : 1,
+ split_by_state : 1,
+ split_by_removable : 1,
+ split_by_zones : 1,
have_zones : 1;
};
+
enum {
COL_RANGE,
COL_SIZE,
@@ -194,14 +195,12 @@ static inline struct coldesc *get_column_desc(int num)
return &coldescs[ get_column_id(num) ];
}
-static inline int has_column(int id)
+static inline void reset_split_policy(struct lsmem *l, int enable)
{
- size_t i;
-
- for (i = 0; i < ncolumns; i++)
- if (columns[i] == id)
- return 1;
- return 0;
+ l->split_by_state = enable;
+ l->split_by_node = enable;
+ l->split_by_removable = enable;
+ l->split_by_zones = enable;
}
static void add_scols_line(struct lsmem *lsmem, struct memory_block *blk)
@@ -380,15 +379,15 @@ static int is_mergeable(struct lsmem *lsmem, struct memory_block *blk)
return 0;
if (curr->index + curr->count != blk->index)
return 0;
- if (lsmem->want_state && curr->state != blk->state)
+ if (lsmem->split_by_state && curr->state != blk->state)
return 0;
- if (lsmem->want_removable && curr->removable != blk->removable)
+ if (lsmem->split_by_removable && curr->removable != blk->removable)
return 0;
- if (lsmem->want_node && lsmem->have_nodes) {
+ if (lsmem->split_by_node && lsmem->have_nodes) {
if (curr->node != blk->node)
return 0;
}
- if (lsmem->want_zones && lsmem->have_zones) {
+ if (lsmem->split_by_zones && lsmem->have_zones) {
if (curr->nr_zones != blk->nr_zones)
return 0;
for (i = 0; i < curr->nr_zones; i++) {
@@ -455,8 +454,6 @@ static void read_basic_info(struct lsmem *lsmem)
/* The valid_zones sysfs attribute was introduced with kernel 3.18 */
if (path_exist(_PATH_SYS_MEMORY "/memory0/valid_zones"))
lsmem->have_zones = 1;
- else if (lsmem->want_zones)
- warnx(_("Cannot read zones, no valid_zones sysfs attribute present"));
}
static void __attribute__((__noreturn__)) usage(void)
@@ -478,6 +475,7 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_(" -n, --noheadings don't print headings\n"), out);
fputs(_(" -o, --output <list> output columns\n"), out);
fputs(_(" -r, --raw use raw output format\n"), out);
+ fputs(_(" -S, --split <list> split ranges by specified columns\n"), out);
fputs(_(" -s, --sysroot <dir> use the specified directory as system root\n"), out);
fputs(_(" --summary[=when] print summary information (never,always or only)\n"), out);
@@ -500,7 +498,7 @@ int main(int argc, char **argv)
.want_summary = 1
}, *lsmem = &_lsmem;
- const char *outarg = NULL;
+ const char *outarg = NULL, *splitarg = NULL;
int c;
size_t i;
@@ -518,12 +516,14 @@ int main(int argc, char **argv)
{"pairs", no_argument, NULL, 'P'},
{"raw", no_argument, NULL, 'r'},
{"sysroot", required_argument, NULL, 's'},
+ {"split", required_argument, NULL, 'S'},
{"version", no_argument, NULL, 'V'},
{"summary", optional_argument, NULL, LSMEM_OPT_SUMARRY },
{NULL, 0, NULL, 0}
};
static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
{ 'J', 'P', 'r' },
+ { 'S', 'a' },
{ 0 }
};
int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
@@ -533,7 +533,7 @@ int main(int argc, char **argv)
textdomain(PACKAGE);
atexit(close_stdout);
- while ((c = getopt_long(argc, argv, "abhJno:Prs:V", longopts, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "abhJno:PrS:s:V", longopts, NULL)) != -1) {
err_exclusive_options(c, longopts, excl, excl_st);
@@ -569,6 +569,9 @@ int main(int argc, char **argv)
if(path_set_prefix(optarg))
err(EXIT_FAILURE, _("invalid argument to %s"), "--sysroot");
break;
+ case 'S':
+ splitarg = optarg;
+ break;
case 'V':
printf(UTIL_LINUX_VERSION);
return 0;
@@ -642,14 +645,36 @@ int main(int argc, char **argv)
err(EXIT_FAILURE, _("Failed to initialize output column"));
}
- if (has_column(COL_STATE))
- lsmem->want_state = 1;
- if (has_column(COL_NODE))
- lsmem->want_node = 1;
- if (has_column(COL_REMOVABLE))
- lsmem->want_removable = 1;
- if (has_column(COL_ZONES))
- lsmem->want_zones = 1;
+ if (splitarg) {
+ int split[ARRAY_SIZE(coldescs)] = { 0 };
+ static size_t nsplits = 0;
+
+ reset_split_policy(lsmem, 0); /* disable all */
+
+ if (strcasecmp(splitarg, "none") == 0)
+ ;
+ else if (string_add_to_idarray(splitarg, split, ARRAY_SIZE(split),
+ &nsplits, column_name_to_id) < 0)
+ return EXIT_FAILURE;
+
+ for (i = 0; i < nsplits; i++) {
+ switch (split[i]) {
+ case COL_STATE:
+ lsmem->split_by_state = 1;
+ break;
+ case COL_NODE:
+ lsmem->split_by_node = 1;
+ break;
+ case COL_REMOVABLE:
+ lsmem->split_by_removable = 1;
+ break;
+ case COL_ZONES:
+ lsmem->split_by_zones = 1;
+ break;
+ }
+ }
+ } else
+ reset_split_policy(lsmem, 1); /* enable all */
/*
* Read data and print output