summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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