From e8c56ae2d77e27b444d35d29b168e2212077e71c Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Thu, 15 Apr 2021 18:03:57 +0900 Subject: [PATCH 01/26] lsns: print namespace tree based on the relationship (parent/child or owner/owned) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce new option -T[parent|owner]|--nstree[=parent|=owner]. With this change, lsns prints parent/child relationship tree if "-T parent" is given and owner/owned relationship tree if "-T owner is given. Passing only "-T" is same as passing "-Towner." Example sessions: # ./lsns -Tparent -ons,type,pns| head -20 NS TYPE PNS 4026531837 user 0 ├─4026532508 user 4026531837 ├─4026532609 user 4026531837 ├─4026532610 user 4026531837 ├─4026532629 user 4026531837 ├─4026532705 user 4026531837 ├─4026532901 user 4026531837 ├─4026533090 user 4026531837 ├─4026533185 user 4026531837 ├─4026533280 user 4026531837 └─4026533468 user 4026531837 4026531835 cgroup 0 4026531836 pid 0 └─4026533038 pid 4026531836 ├─4026532934 pid 4026533038 ├─4026533715 pid 4026533038 ├─4026533716 pid 4026533038 ... # ./lsns -Towner -ons,type,ons| head -20 NS TYPE ONS 4026531837 user 0 ├─4026531835 cgroup 4026531837 ├─4026531836 pid 4026531837 ├─4026531838 uts 4026531837 ├─4026531839 ipc 4026531837 ├─4026531840 mnt 4026531837 ├─4026531861 mnt 4026531837 ├─4026532001 net 4026531837 ├─4026532219 mnt 4026531837 ├─4026532357 mnt 4026531837 ├─4026532383 net 4026531837 ├─4026532475 mnt 4026531837 ├─4026532476 mnt 4026531837 ├─4026532504 mnt 4026531837 ├─4026532508 user 4026531837 │ ├─4026532509 ipc 4026532508 │ └─4026532511 net 4026532508 ├─4026532573 mnt 4026531837 ├─4026532574 mnt 4026531837 Signed-off-by: Masatake YAMATO --- sys-utils/lsns.8.adoc | 6 +++ sys-utils/lsns.c | 89 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 90 insertions(+), 5 deletions(-) diff --git a/sys-utils/lsns.8.adoc b/sys-utils/lsns.8.adoc index ab7e7aea8..77875223b 100644 --- a/sys-utils/lsns.8.adoc +++ b/sys-utils/lsns.8.adoc @@ -63,6 +63,12 @@ Do not truncate text in columns. *-W*, *--nowrap*:: Do not use multi-line text in columns. +*-T*, *--nstree* _rel_:: +Print namespace tree(s). +If *parent* is given as _rel_, print tree(s) constructed by the parent/child relationship. +If *owner* is given, print tree(s) constructed by the owner/owned relationship. +The result can be forests because *lsns* cannot track a namespace having no process. + *-V*, *--version*:: Display version information and exit. diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c index 8e25ff183..23a2eabac 100644 --- a/sys-utils/lsns.c +++ b/sys-utils/lsns.c @@ -152,6 +152,10 @@ struct lsns_namespace { struct lsns_process *proc; + struct lsns_namespace *parentns; + struct lsns_namespace *ownerns; + struct libscols_line *ns_outline; + struct list_head namespaces; /* lsns->processes member */ struct list_head processes; /* head of lsns_process *siblings */ }; @@ -177,6 +181,11 @@ struct lsns_process { int netnsid; }; +enum { + LSNS_NSTREE_OWNER = 1, + LSNS_NSTREE_PARENT, +}; + struct lsns { struct list_head processes; struct list_head namespaces; @@ -192,7 +201,9 @@ struct lsns { list : 1, no_trunc : 1, no_headings: 1, - no_wrap : 1; + no_wrap : 1, + nstree : 2; + struct libmnt_table *tab; }; @@ -684,6 +695,30 @@ static int read_namespaces(struct lsns *ls) } } + if (ls->nstree) { + list_for_each(p, &ls->namespaces) { + struct lsns_namespace *ns = list_entry(p, struct lsns_namespace, namespaces); + struct list_head *pp; + list_for_each(pp, &ls->namespaces) { + struct lsns_namespace *pns = list_entry(pp, struct lsns_namespace, namespaces); + if (ns->type == LSNS_ID_USER + || ns->type == LSNS_ID_PID) { + if (ns->parentid == pns->id) + ns->parentns = pns; + if (ns->ownerid == pns->id) + ns->ownerns = pns; + if (ns->parentns && ns->ownerns) + break; + } else { + if (ns->ownerid == pns->id) { + ns->ownerns = pns; + break; + } + } + } + } + } + list_sort(&ls->namespaces, cmp_namespaces, NULL); return 0; @@ -774,7 +809,10 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table, assert(table); line = scols_table_new_line(table, - ls->tree && proc->parent ? proc->parent->outline : NULL); + ls->tree && proc->parent ? proc->parent->outline: + ls->nstree == LSNS_NSTREE_PARENT && ns->parentns ? ns->parentns->ns_outline: + ls->nstree == LSNS_NSTREE_OWNER && ns->ownerns ? ns->ownerns->ns_outline: + NULL); if (!line) { warn(_("failed to add line to output")); return; @@ -834,7 +872,10 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table, err_oom(); } - proc->outline = line; + if (ls->nstree) + ns->ns_outline = line; + else + proc->outline = line; } static struct libscols_table *init_scols_table(struct lsns *ls) @@ -866,6 +907,10 @@ static struct libscols_table *init_scols_table(struct lsns *ls) flags |= SCOLS_FL_TREE; if (ls->no_wrap) flags &= ~SCOLS_FL_WRAP; + if (ls->nstree && get_column_id(i) == COL_NS) { + flags |= SCOLS_FL_TREE; + flags &= ~SCOLS_FL_RIGHT; + } cl = scols_table_new_column(tab, col->name, col->whint, flags); if (cl == NULL) { @@ -890,6 +935,28 @@ err: return NULL; } +static void show_namespace(struct lsns *ls, struct libscols_table *tab, + struct lsns_namespace *ns, struct lsns_process *proc) +{ + /* + * create a tree from owner->owned and/or parent->child relation + */ + if (ls->nstree == LSNS_NSTREE_OWNER + && ns->ownerns + && !ns->ownerns->ns_outline) + show_namespace(ls, tab, ns->ownerns, proc); + else if (ls->nstree == LSNS_NSTREE_PARENT) { + if (ns->parentns) { + if (!ns->parentns->ns_outline) + show_namespace(ls, tab, ns->parentns, proc); + } + else if (ns->ownerns && !ns->ownerns->ns_outline) + show_namespace(ls, tab, ns->ownerns, proc); + } + + add_scols_line(ls, tab, ns, proc); +} + static int show_namespaces(struct lsns *ls) { struct libscols_table *tab; @@ -906,7 +973,8 @@ static int show_namespaces(struct lsns *ls) if (ls->fltr_pid != 0 && !namespace_has_process(ns, ls->fltr_pid)) continue; - add_scols_line(ls, tab, ns, ns->proc); + if (!ns->ns_outline) + show_namespace(ls, tab, ns, ns->proc); } scols_print_table(tab); @@ -977,6 +1045,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -u, --notruncate don't truncate text in columns\n"), out); fputs(_(" -W, --nowrap don't use multi-line representation\n"), out); fputs(_(" -t, --type namespace type (mnt, net, ipc, user, pid, uts, cgroup, time)\n"), out); + fputs(_(" -T, --nstree print namespace tree based on the relationship (parent or owner)\n"), out); fputs(USAGE_SEPARATOR, out); printf(USAGE_HELP_OPTIONS(24)); @@ -1013,6 +1082,7 @@ int main(int argc, char *argv[]) { "list", no_argument, NULL, 'l' }, { "raw", no_argument, NULL, 'r' }, { "type", required_argument, NULL, 't' }, + { "nstree", optional_argument, NULL, 'T' }, { NULL, 0, NULL, 0 } }; @@ -1036,7 +1106,7 @@ int main(int argc, char *argv[]) INIT_LIST_HEAD(&netnsids_cache); while ((c = getopt_long(argc, argv, - "Jlp:o:nruhVt:W", long_opts, NULL)) != -1) { + "Jlp:o:nruhVt:T::W", long_opts, NULL)) != -1) { err_exclusive_options(c, long_opts, excl, excl_st); @@ -1080,6 +1150,15 @@ int main(int argc, char *argv[]) case 'W': ls.no_wrap = 1; break; + case 'T': + ls.nstree = LSNS_NSTREE_OWNER; + if (optarg) { + if (strcmp (optarg, "parent") == 0) + ls.nstree = LSNS_NSTREE_PARENT; + else if (strcmp (optarg, "owner") != 0) + errx(EXIT_FAILURE, _("unknown nstree type: %s"), optarg); + } + break; case 'h': usage(); From 8d27b60530d96c35bce534c24a395c3264f1f9e8 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Tue, 20 Apr 2021 17:09:02 +0900 Subject: [PATCH 02/26] lsns: unify the code and option for printing process based tree and namespace based trees Suggested by Karel Zak. `--tree` option is introduced as replacement for `--nstree`. In addition to `parent` and `owner`, `--tree` take `process` as the option argument. Signed-off-by: Masatake YAMATO --- sys-utils/lsns.8.adoc | 9 ++++++--- sys-utils/lsns.c | 47 +++++++++++++++++++++++++------------------ 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/sys-utils/lsns.8.adoc b/sys-utils/lsns.8.adoc index 77875223b..6bfbdb644 100644 --- a/sys-utils/lsns.8.adoc +++ b/sys-utils/lsns.8.adoc @@ -64,10 +64,13 @@ Do not truncate text in columns. Do not use multi-line text in columns. *-T*, *--nstree* _rel_:: -Print namespace tree(s). -If *parent* is given as _rel_, print tree(s) constructed by the parent/child relationship. +Use list output format. +If *process* is gnve as _rel_, print proecss tree(s) in each name space. +If *parent* is given, print tree(s) constructed by the parent/child relationship. If *owner* is given, print tree(s) constructed by the owner/owned relationship. -The result can be forests because *lsns* cannot track a namespace having no process. +*owner* is used as default when _rel_ is omitted. +The result of *parent* and *owner* can be forests because *lsns* cannot track a namespace having no process. + *-V*, *--version*:: Display version information and exit. diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c index 23a2eabac..a143509cd 100644 --- a/sys-utils/lsns.c +++ b/sys-utils/lsns.c @@ -181,9 +181,12 @@ struct lsns_process { int netnsid; }; + enum { - LSNS_NSTREE_OWNER = 1, - LSNS_NSTREE_PARENT, + LSNS_TREE_LIST, + LSNS_TREE_PROCESS, + LSNS_TREE_OWNER, + LSNS_TREE_PARENT, }; struct lsns { @@ -197,12 +200,11 @@ struct lsns { unsigned int raw : 1, json : 1, - tree : 1, + tree : 2, list : 1, no_trunc : 1, no_headings: 1, - no_wrap : 1, - nstree : 2; + no_wrap : 1; struct libmnt_table *tab; @@ -695,7 +697,7 @@ static int read_namespaces(struct lsns *ls) } } - if (ls->nstree) { + if (ls->tree == LSNS_TREE_OWNER || ls->tree == LSNS_TREE_PARENT) { list_for_each(p, &ls->namespaces) { struct lsns_namespace *ns = list_entry(p, struct lsns_namespace, namespaces); struct list_head *pp; @@ -809,9 +811,9 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table, assert(table); line = scols_table_new_line(table, - ls->tree && proc->parent ? proc->parent->outline: - ls->nstree == LSNS_NSTREE_PARENT && ns->parentns ? ns->parentns->ns_outline: - ls->nstree == LSNS_NSTREE_OWNER && ns->ownerns ? ns->ownerns->ns_outline: + (ls->tree == LSNS_TREE_PROCESS) && proc->parent ? proc->parent->outline: + (ls->tree == LSNS_TREE_PARENT) && ns->parentns ? ns->parentns->ns_outline: + (ls->tree == LSNS_TREE_OWNER) && ns->ownerns ? ns->ownerns->ns_outline: NULL); if (!line) { warn(_("failed to add line to output")); @@ -872,7 +874,7 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table, err_oom(); } - if (ls->nstree) + if (ls->tree == LSNS_TREE_OWNER || ls->tree == LSNS_TREE_PARENT) ns->ns_outline = line; else proc->outline = line; @@ -903,11 +905,12 @@ static struct libscols_table *init_scols_table(struct lsns *ls) if (ls->no_trunc) flags &= ~SCOLS_FL_TRUNC; - if (ls->tree && get_column_id(i) == COL_COMMAND) + if (ls->tree == LSNS_TREE_PROCESS && get_column_id(i) == COL_COMMAND) flags |= SCOLS_FL_TREE; if (ls->no_wrap) flags &= ~SCOLS_FL_WRAP; - if (ls->nstree && get_column_id(i) == COL_NS) { + if ((ls->tree == LSNS_TREE_OWNER || ls->tree == LSNS_TREE_PARENT) + && get_column_id(i) == COL_NS) { flags |= SCOLS_FL_TREE; flags &= ~SCOLS_FL_RIGHT; } @@ -941,11 +944,11 @@ static void show_namespace(struct lsns *ls, struct libscols_table *tab, /* * create a tree from owner->owned and/or parent->child relation */ - if (ls->nstree == LSNS_NSTREE_OWNER + if (ls->tree == LSNS_TREE_OWNER && ns->ownerns && !ns->ownerns->ns_outline) show_namespace(ls, tab, ns->ownerns, proc); - else if (ls->nstree == LSNS_NSTREE_PARENT) { + else if (ls->tree == LSNS_TREE_PARENT) { if (ns->parentns) { if (!ns->parentns->ns_outline) show_namespace(ls, tab, ns->parentns, proc); @@ -989,7 +992,7 @@ static void show_process(struct lsns *ls, struct libscols_table *tab, * create a tree from parent->child relation, but only if the parent is * within the same namespace */ - if (ls->tree + if (ls->tree == LSNS_TREE_PROCESS && proc->parent && !proc->parent->outline && proc->parent->ns_ids[ns->type] == proc->ns_ids[ns->type]) @@ -1045,7 +1048,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -u, --notruncate don't truncate text in columns\n"), out); fputs(_(" -W, --nowrap don't use multi-line representation\n"), out); fputs(_(" -t, --type namespace type (mnt, net, ipc, user, pid, uts, cgroup, time)\n"), out); - fputs(_(" -T, --nstree print namespace tree based on the relationship (parent or owner)\n"), out); + fputs(_(" -T, --tree use tree format (parent, owner, or process)\n"), out); fputs(USAGE_SEPARATOR, out); printf(USAGE_HELP_OPTIONS(24)); @@ -1082,7 +1085,7 @@ int main(int argc, char *argv[]) { "list", no_argument, NULL, 'l' }, { "raw", no_argument, NULL, 'r' }, { "type", required_argument, NULL, 't' }, - { "nstree", optional_argument, NULL, 'T' }, + { "tree", optional_argument, NULL, 'T' }, { NULL, 0, NULL, 0 } }; @@ -1151,10 +1154,14 @@ int main(int argc, char *argv[]) ls.no_wrap = 1; break; case 'T': - ls.nstree = LSNS_NSTREE_OWNER; + ls.tree = LSNS_TREE_OWNER; if (optarg) { + if (*optarg == '=') + optarg++; if (strcmp (optarg, "parent") == 0) - ls.nstree = LSNS_NSTREE_PARENT; + ls.tree = LSNS_TREE_PARENT; + else if (strcmp (optarg, "process") == 0) + ls.tree = LSNS_TREE_PROCESS; else if (strcmp (optarg, "owner") != 0) errx(EXIT_FAILURE, _("unknown nstree type: %s"), optarg); } @@ -1180,7 +1187,7 @@ int main(int argc, char *argv[]) if (ls.fltr_pid) errx(EXIT_FAILURE, _("--task is mutually exclusive with ")); ls.fltr_ns = strtou64_or_err(argv[optind], _("invalid namespace argument")); - ls.tree = ls.list ? 0 : 1; + ls.tree = ls.list ? LSNS_TREE_LIST : LSNS_TREE_PROCESS; if (!ncolumns) { columns[ncolumns++] = COL_PID; From 179dd17a6aa5a698e0f425eb014c53d191f9eb8c Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Fri, 23 Apr 2021 19:55:46 +0900 Subject: [PATCH 03/26] lsns: fix passing wrong process lists when showing ownerns and parentns Signed-off-by: Masatake YAMATO --- sys-utils/lsns.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c index a143509cd..a8daab95e 100644 --- a/sys-utils/lsns.c +++ b/sys-utils/lsns.c @@ -947,14 +947,14 @@ static void show_namespace(struct lsns *ls, struct libscols_table *tab, if (ls->tree == LSNS_TREE_OWNER && ns->ownerns && !ns->ownerns->ns_outline) - show_namespace(ls, tab, ns->ownerns, proc); + show_namespace(ls, tab, ns->ownerns, ns->ownerns->proc); else if (ls->tree == LSNS_TREE_PARENT) { if (ns->parentns) { if (!ns->parentns->ns_outline) - show_namespace(ls, tab, ns->parentns, proc); + show_namespace(ls, tab, ns->parentns, ns->parentns->proc); } else if (ns->ownerns && !ns->ownerns->ns_outline) - show_namespace(ls, tab, ns->ownerns, proc); + show_namespace(ls, tab, ns->ownerns, ns->ownerns->proc); } add_scols_line(ls, tab, ns, proc); From 3387ad72a621334527c3a75c6a924cac03e7a992 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 28 Apr 2021 13:04:16 +0200 Subject: [PATCH 04/26] lsns: make --tree default, update man-page * make --tree=process default for 'lsns' and 'lsns ' * remove 'list' from struct lsns * update man page Addresses: https://github.com/karelzak/util-linux/pull/1281 Signed-off-by: Karel Zak --- sys-utils/lsns.8.adoc | 6 +++--- sys-utils/lsns.c | 14 +++++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/sys-utils/lsns.8.adoc b/sys-utils/lsns.8.adoc index 6bfbdb644..738f87106 100644 --- a/sys-utils/lsns.8.adoc +++ b/sys-utils/lsns.8.adoc @@ -23,7 +23,7 @@ lsns - list namespaces *lsns* lists information about all the currently accessible namespaces or about the given _namespace_. The _namespace_ identifier is an inode number. -The default output is subject to change. So whenever possible, you should avoid using default outputs in your scripts. Always explicitly define expected columns by using the *--output* option together with a columns list in environments where a stable output is required. +The default output is subject to change. So whenever possible, you should avoid using default outputs in your scripts. Always explicitly define expected output mode (*--tree* or *--list*) and columns by using the *--output* option together with a columns list in environments where a stable output is required. The *NSFS* column, printed when *net* is specified for the *--type* option, is special; it uses multi-line cells. Use the option *--nowrap* to switch to ","-separated single-line representation. @@ -63,9 +63,9 @@ Do not truncate text in columns. *-W*, *--nowrap*:: Do not use multi-line text in columns. -*-T*, *--nstree* _rel_:: +*-T*, *--tree* _rel_:: Use list output format. -If *process* is gnve as _rel_, print proecss tree(s) in each name space. +If *process* is given as _rel_, print proecss tree(s) in each name space. This is default when *--tree* is not specified. If *parent* is given, print tree(s) constructed by the parent/child relationship. If *owner* is given, print tree(s) constructed by the owner/owned relationship. *owner* is used as default when _rel_ is omitted. diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c index a8daab95e..1ea2dd594 100644 --- a/sys-utils/lsns.c +++ b/sys-utils/lsns.c @@ -183,7 +183,7 @@ struct lsns_process { enum { - LSNS_TREE_LIST, + LSNS_TREE_NONE, LSNS_TREE_PROCESS, LSNS_TREE_OWNER, LSNS_TREE_PARENT, @@ -201,7 +201,6 @@ struct lsns { unsigned int raw : 1, json : 1, tree : 2, - list : 1, no_trunc : 1, no_headings: 1, no_wrap : 1; @@ -1066,7 +1065,7 @@ static void __attribute__((__noreturn__)) usage(void) int main(int argc, char *argv[]) { struct lsns ls; - int c; + int c, force_list = 0; int r = 0; char *outarg = NULL; enum { @@ -1091,6 +1090,7 @@ int main(int argc, char *argv[]) static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ { 'J','r' }, + { 'l','T' }, { 0 } }; int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; @@ -1118,7 +1118,7 @@ int main(int argc, char *argv[]) ls.json = 1; break; case 'l': - ls.list = 1; + force_list = 1; break; case 'o': outarg = optarg; @@ -1187,7 +1187,8 @@ int main(int argc, char *argv[]) if (ls.fltr_pid) errx(EXIT_FAILURE, _("--task is mutually exclusive with ")); ls.fltr_ns = strtou64_or_err(argv[optind], _("invalid namespace argument")); - ls.tree = ls.list ? LSNS_TREE_LIST : LSNS_TREE_PROCESS; + if (!ls.tree && !force_list) + ls.tree = LSNS_TREE_PROCESS; if (!ncolumns) { columns[ncolumns++] = COL_PID; @@ -1208,6 +1209,9 @@ int main(int argc, char *argv[]) columns[ncolumns++] = COL_NSFS; } columns[ncolumns++] = COL_COMMAND; + + if (!ls.tree && !force_list) + ls.tree = LSNS_TREE_PROCESS; } if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns), From b250fbbf5666d0b7289c223c276edd301cd8c653 Mon Sep 17 00:00:00 2001 From: Naohiro Aota Date: Mon, 26 Apr 2021 14:50:34 +0900 Subject: [PATCH 05/26] libblkid: implement zone-aware probing This patch makes libblkid zone-aware. It can probe the magic located at some offset from the beginning of some specific zone of a device. This patch introduces some new fields to struct blkid_idmag. They indicate the magic location is placed related to a zone and the offset in the zone. Also, this commit introduces `zone_size` to struct blkid_struct_probe. It stores the size of zones of a device. Signed-off-by: Naohiro Aota --- libblkid/src/blkidP.h | 5 +++++ libblkid/src/probe.c | 30 ++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/libblkid/src/blkidP.h b/libblkid/src/blkidP.h index a3fe6748a..e3a160aa9 100644 --- a/libblkid/src/blkidP.h +++ b/libblkid/src/blkidP.h @@ -150,6 +150,10 @@ struct blkid_idmag const char *hoff; /* hint which contains byte offset to kboff */ long kboff; /* kilobyte offset of superblock */ unsigned int sboff; /* byte offset within superblock */ + + int is_zoned; /* indicate magic location is calcluated based on zone position */ + long zonenum; /* zone number which has superblock */ + long kboff_inzone; /* kilobyte offset of superblock in a zone */ }; /* @@ -206,6 +210,7 @@ struct blkid_struct_probe dev_t disk_devno; /* devno of the whole-disk or 0 */ unsigned int blkssz; /* sector size (BLKSSZGET ioctl) */ mode_t mode; /* struct stat.sb_mode */ + uint64_t zone_size; /* zone size (BLKGETZONESZ ioctl) */ int flags; /* private library flags */ int prob_flags; /* always zeroized by blkid_do_*() */ diff --git a/libblkid/src/probe.c b/libblkid/src/probe.c index a47a8720d..219cceea0 100644 --- a/libblkid/src/probe.c +++ b/libblkid/src/probe.c @@ -94,6 +94,9 @@ #ifdef HAVE_LINUX_CDROM_H #include #endif +#ifdef HAVE_LINUX_BLKZONED_H +#include +#endif #ifdef HAVE_SYS_STAT_H #include #endif @@ -177,6 +180,7 @@ blkid_probe blkid_clone_probe(blkid_probe parent) pr->disk_devno = parent->disk_devno; pr->blkssz = parent->blkssz; pr->flags = parent->flags; + pr->zone_size = parent->zone_size; pr->parent = parent; pr->flags &= ~BLKID_FL_PRIVATE_FD; @@ -897,6 +901,7 @@ int blkid_probe_set_device(blkid_probe pr, int fd, pr->wipe_off = 0; pr->wipe_size = 0; pr->wipe_chain = NULL; + pr->zone_size = 0; if (fd < 0) return 1; @@ -996,6 +1001,15 @@ int blkid_probe_set_device(blkid_probe pr, int fd, #endif free(dm_uuid); +# ifdef HAVE_LINUX_BLKZONED_H + if (S_ISBLK(sb.st_mode)) { + uint32_t zone_size_sector; + + if (!ioctl(pr->fd, BLKGETZONESZ, &zone_size_sector)) + pr->zone_size = zone_size_sector << 9; + } +# endif + DBG(LOWPROBE, ul_debug("ready for low-probing, offset=%"PRIu64", size=%"PRIu64"", pr->off, pr->size)); DBG(LOWPROBE, ul_debug("whole-disk: %s, regfile: %s", @@ -1064,12 +1078,24 @@ int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id, /* try to detect by magic string */ while(mag && mag->magic) { unsigned char *buf; + uint64_t kboff; uint64_t hint_offset; if (!mag->hoff || blkid_probe_get_hint(pr, mag->hoff, &hint_offset) < 0) hint_offset = 0; - off = hint_offset + ((mag->kboff + (mag->sboff >> 10)) << 10); + /* If the magic is for zoned device, skip non-zoned device */ + if (mag->is_zoned && !pr->zone_size) { + mag++; + continue; + } + + if (!mag->is_zoned) + kboff = mag->kboff; + else + kboff = ((mag->zonenum * pr->zone_size) >> 10) + mag->kboff_inzone; + + off = hint_offset + ((kboff + (mag->sboff >> 10)) << 10); buf = blkid_probe_get_buffer(pr, off, 1024); if (!buf && errno) @@ -1079,7 +1105,7 @@ int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id, buf + (mag->sboff & 0x3ff), mag->len)) { DBG(LOWPROBE, ul_debug("\tmagic sboff=%u, kboff=%ld", - mag->sboff, mag->kboff)); + mag->sboff, kboff)); if (offset) *offset = off + (mag->sboff & 0x3ff); if (res) From 6be38dccae0c6f8d8246bc60aac177e783eeac43 Mon Sep 17 00:00:00 2001 From: Naohiro Aota Date: Mon, 26 Apr 2021 14:50:35 +0900 Subject: [PATCH 06/26] libblkid: add magic and probing for zoned btrfs This commit adds zone-aware magics and probing functions for zoned btrfs. The superblock (and its copies) are the only data structure in btrfs with a fixed location on a device. Since we cannot do overwrites in a sequential write required zone, we cannot place the superblock in the zone. Thus, zoned btrfs uses superblock log writing to update superblocks on sequential write required zones. It uses two zones as a circular buffer to write updated superblocks. Once the first zone is filled up, start writing into the second buffer. When both zones are filled up, and before starting to write to the first zone again, it reset the first zone. We can determine the position of the latest superblock by reading the write pointer information from a device. One corner case is when both zones are full. For this situation, we read out the last superblock of each zone and compare them to determine which zone is older. The magics can detect a superblock magic ("_BHRfs_M") at the beginning of zone #0 or zone #1 to see if it is zoned btrfs. When both zones are filled up, zoned btrfs resets the first zone to write a new superblock. If btrfs crashes at the moment, we do not see a superblock at zone #0. Thus, we need to check not only zone #0 but also zone #1. It also supports the temporary magic ("!BHRfS_M") in zone #0. Mkfs.btrfs first writes the temporary superblock to the zone during the mkfs process. It will survive there until the zones are filled up and reset. So, we also need to detect this temporary magic. Finally, this commit extends probe_btrfs() to load the latest superblock determined by the write pointers. Signed-off-by: Naohiro Aota --- include/blkdev.h | 9 ++ lib/blkdev.c | 29 ++++++ libblkid/src/superblocks/btrfs.c | 159 ++++++++++++++++++++++++++++++- 3 files changed, 196 insertions(+), 1 deletion(-) diff --git a/include/blkdev.h b/include/blkdev.h index 6cbecbb65..43a5f5224 100644 --- a/include/blkdev.h +++ b/include/blkdev.h @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef HAVE_SYS_MKDEV_H # include /* major and minor on Solaris */ @@ -147,5 +148,13 @@ int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s); const char *blkdev_scsi_type_to_name(int type); int blkdev_lock(int fd, const char *devname, const char *lockmode); +#ifdef HAVE_LINUX_BLKZONED_H +struct blk_zone_report *blkdev_get_zonereport(int fd, uint64_t sector, uint32_t nzones); +#else +static inline struct blk_zone_report *blkdev_get_zonereport(int fd, uint64_t sector, uint32_t nzones) +{ + return NULL; +} +#endif #endif /* BLKDEV_H */ diff --git a/lib/blkdev.c b/lib/blkdev.c index c22853ddc..9de851291 100644 --- a/lib/blkdev.c +++ b/lib/blkdev.c @@ -15,6 +15,10 @@ #include #endif +#ifdef HAVE_LINUX_BLKZONED_H +#include +#endif + #ifdef HAVE_SYS_DISKLABEL_H #include #endif @@ -412,6 +416,31 @@ int blkdev_lock(int fd, const char *devname, const char *lockmode) return rc; } +#ifdef HAVE_LINUX_BLKZONED_H +struct blk_zone_report *blkdev_get_zonereport(int fd, uint64_t sector, uint32_t nzones) +{ + struct blk_zone_report *rep; + size_t rep_size; + int ret; + + rep_size = sizeof(struct blk_zone_report) + sizeof(struct blk_zone) * 2; + rep = calloc(1, rep_size); + if (!rep) + return NULL; + + rep->sector = sector; + rep->nr_zones = nzones; + + ret = ioctl(fd, BLKREPORTZONE, rep); + if (ret || rep->nr_zones != nzones) { + free(rep); + return NULL; + } + + return rep; +} +#endif + #ifdef TEST_PROGRAM_BLKDEV #include diff --git a/libblkid/src/superblocks/btrfs.c b/libblkid/src/superblocks/btrfs.c index f0fde700d..03aa7e979 100644 --- a/libblkid/src/superblocks/btrfs.c +++ b/libblkid/src/superblocks/btrfs.c @@ -9,6 +9,12 @@ #include #include #include +#include +#include + +#ifdef HAVE_LINUX_BLKZONED_H +#include +#endif #include "superblocks.h" @@ -59,11 +65,157 @@ struct btrfs_super_block { uint8_t label[256]; } __attribute__ ((__packed__)); +#define BTRFS_SUPER_INFO_SIZE 4096 + +/* Number of superblock log zones */ +#define BTRFS_NR_SB_LOG_ZONES 2 + +/* Introduce some macros and types to unify the code with kernel side */ +#define SECTOR_SHIFT 9 + +typedef uint64_t sector_t; + +#ifdef HAVE_LINUX_BLKZONED_H +static int sb_write_pointer(blkid_probe pr, struct blk_zone *zones, uint64_t *wp_ret) +{ + bool empty[BTRFS_NR_SB_LOG_ZONES]; + bool full[BTRFS_NR_SB_LOG_ZONES]; + sector_t sector; + + assert(zones[0].type != BLK_ZONE_TYPE_CONVENTIONAL && + zones[1].type != BLK_ZONE_TYPE_CONVENTIONAL); + + empty[0] = zones[0].cond == BLK_ZONE_COND_EMPTY; + empty[1] = zones[1].cond == BLK_ZONE_COND_EMPTY; + full[0] = zones[0].cond == BLK_ZONE_COND_FULL; + full[1] = zones[1].cond == BLK_ZONE_COND_FULL; + + /* + * Possible states of log buffer zones + * + * Empty[0] In use[0] Full[0] + * Empty[1] * x 0 + * In use[1] 0 x 0 + * Full[1] 1 1 C + * + * Log position: + * *: Special case, no superblock is written + * 0: Use write pointer of zones[0] + * 1: Use write pointer of zones[1] + * C: Compare super blcoks from zones[0] and zones[1], use the latest + * one determined by generation + * x: Invalid state + */ + + if (empty[0] && empty[1]) { + /* Special case to distinguish no superblock to read */ + *wp_ret = zones[0].start << SECTOR_SHIFT; + return -ENOENT; + } else if (full[0] && full[1]) { + /* Compare two super blocks */ + struct btrfs_super_block *super[BTRFS_NR_SB_LOG_ZONES]; + int i; + + for (i = 0; i < BTRFS_NR_SB_LOG_ZONES; i++) { + uint64_t bytenr; + + bytenr = ((zones[i].start + zones[i].len) + << SECTOR_SHIFT) - BTRFS_SUPER_INFO_SIZE; + + super[i] = (struct btrfs_super_block *) + blkid_probe_get_buffer(pr, bytenr, BTRFS_SUPER_INFO_SIZE); + if (!super[i]) + return -EIO; + } + + if (super[0]->generation > super[1]->generation) + sector = zones[1].start; + else + sector = zones[0].start; + } else if (!full[0] && (empty[1] || full[1])) { + sector = zones[0].wp; + } else if (full[0]) { + sector = zones[1].wp; + } else { + return -EUCLEAN; + } + *wp_ret = sector << SECTOR_SHIFT; + return 0; +} + +static int sb_log_offset(blkid_probe pr, uint64_t *bytenr_ret) +{ + uint32_t zone_num = 0; + uint32_t zone_size_sector; + struct blk_zone_report *rep; + struct blk_zone *zones; + int ret; + int i; + uint64_t wp; + + + zone_size_sector = pr->zone_size >> SECTOR_SHIFT; + rep = blkdev_get_zonereport(pr->fd, zone_num * zone_size_sector, 2); + if (!rep) { + ret = -errno; + goto out; + } + zones = (struct blk_zone *)(rep + 1); + + /* + * Use the head of the first conventional zone, if the zones + * contain one. + */ + for (i = 0; i < BTRFS_NR_SB_LOG_ZONES; i++) { + if (zones[i].type == BLK_ZONE_TYPE_CONVENTIONAL) { + *bytenr_ret = zones[i].start << SECTOR_SHIFT; + ret = 0; + goto out; + } + } + + ret = sb_write_pointer(pr, zones, &wp); + if (ret != -ENOENT && ret) { + ret = 1; + goto out; + } + if (ret != -ENOENT) { + if (wp == zones[0].start << SECTOR_SHIFT) + wp = (zones[1].start + zones[1].len) << SECTOR_SHIFT; + wp -= BTRFS_SUPER_INFO_SIZE; + } + *bytenr_ret = wp; + + ret = 0; +out: + free(rep); + + return ret; +} +#endif + static int probe_btrfs(blkid_probe pr, const struct blkid_idmag *mag) { struct btrfs_super_block *bfs; - bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block); + if (pr->zone_size) { +#ifdef HAVE_LINUX_BLKZONED_H + uint64_t offset = 0; + int ret; + + ret = sb_log_offset(pr, &offset); + if (ret) + return ret; + bfs = (struct btrfs_super_block *) + blkid_probe_get_buffer(pr, offset, + sizeof(struct btrfs_super_block)); +#else + /* Nothing can be done */ + return 1; +#endif + } else { + bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block); + } if (!bfs) return errno ? -errno : 1; @@ -88,6 +240,11 @@ const struct blkid_idinfo btrfs_idinfo = .magics = { { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 64 }, + /* For zoned btrfs */ + { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, + .is_zoned = 1, .zonenum = 0, .kboff_inzone = 0 }, + { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, + .is_zoned = 1, .zonenum = 1, .kboff_inzone = 0 }, { NULL } } }; From db221158757e93912a36a58a5403201bf82edee5 Mon Sep 17 00:00:00 2001 From: Naohiro Aota Date: Mon, 26 Apr 2021 14:50:36 +0900 Subject: [PATCH 07/26] libblkid: support zone reset for wipefs We cannot overwrite superblock magic in a sequential required zone. So, wipefs cannot work as it is. Instead, this commit implements the wiping by zone resetting. Zone resetting must be done only for a sequential write zone. This is checked by is_conventional(). Signed-off-by: Naohiro Aota --- libblkid/src/probe.c | 69 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/libblkid/src/probe.c b/libblkid/src/probe.c index 219cceea0..d4ca47c6d 100644 --- a/libblkid/src/probe.c +++ b/libblkid/src/probe.c @@ -1229,6 +1229,39 @@ int blkid_do_probe(blkid_probe pr) return rc; } +#ifdef HAVE_LINUX_BLKZONED_H +static int is_conventional(blkid_probe pr, uint64_t offset) +{ + struct blk_zone_report *rep = NULL; + int ret; + uint64_t zone_mask; + + if (!pr->zone_size) + return 1; + + zone_mask = ~(pr->zone_size - 1); + rep = blkdev_get_zonereport(blkid_probe_get_fd(pr), + (offset & zone_mask) >> 9, 1); + if (!rep) + return -1; + + if (rep->zones[0].type == BLK_ZONE_TYPE_CONVENTIONAL) + ret = 1; + else + ret = 0; + + free(rep); + + return ret; +} +#else +static inline int is_conventional(blkid_probe pr __attribute__((__unused__)), + uint64_t offset __attribute__((__unused__))) +{ + return 1; +} +#endif + /** * blkid_do_wipe: * @pr: prober @@ -1268,6 +1301,7 @@ int blkid_do_wipe(blkid_probe pr, int dryrun) const char *off = NULL; size_t len = 0; uint64_t offset, magoff; + int conventional; char buf[BUFSIZ]; int fd, rc = 0; struct blkid_chain *chn; @@ -1303,6 +1337,11 @@ int blkid_do_wipe(blkid_probe pr, int dryrun) if (len > sizeof(buf)) len = sizeof(buf); + rc = is_conventional(pr, offset); + if (rc < 0) + return rc; + conventional = rc == 1; + DBG(LOWPROBE, ul_debug( "do_wipe [offset=0x%"PRIx64" (%"PRIu64"), len=%zu, chain=%s, idx=%d, dryrun=%s]\n", offset, offset, len, chn->driver->name, chn->idx, dryrun ? "yes" : "not")); @@ -1310,13 +1349,31 @@ int blkid_do_wipe(blkid_probe pr, int dryrun) if (lseek(fd, offset, SEEK_SET) == (off_t) -1) return -1; - memset(buf, 0, len); - if (!dryrun && len) { - /* wipen on device */ - if (write_all(fd, buf, len)) - return -1; - fsync(fd); + if (conventional) { + memset(buf, 0, len); + + /* wipen on device */ + if (write_all(fd, buf, len)) + return -1; + fsync(fd); + } else { +#ifdef HAVE_LINUX_BLKZONED_H + uint64_t zone_mask = ~(pr->zone_size - 1); + struct blk_zone_range range = { + .sector = (offset & zone_mask) >> 9, + .nr_sectors = pr->zone_size >> 9, + }; + + rc = ioctl(fd, BLKRESETZONE, &range); + if (rc < 0) + return -1; +#else + /* Should not reach here */ + assert(0); +#endif + } + pr->flags &= ~BLKID_FL_MODIF_BUFF; /* be paranoid */ return blkid_probe_step_back(pr); From e749d51a9c8b307fcbc78e64167ff8ef2ab9a122 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Fri, 23 Apr 2021 04:24:24 +0900 Subject: [PATCH 08/26] lsns: make namespace having no process printable This is a preparation change for planed "tree interpolation" patch. Signed-off-by: Masatake YAMATO --- sys-utils/lsns.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c index 1ea2dd594..d9b46a528 100644 --- a/sys-utils/lsns.c +++ b/sys-utils/lsns.c @@ -810,7 +810,7 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table, assert(table); line = scols_table_new_line(table, - (ls->tree == LSNS_TREE_PROCESS) && proc->parent ? proc->parent->outline: + (ls->tree == LSNS_TREE_PROCESS && proc) && proc->parent ? proc->parent->outline: (ls->tree == LSNS_TREE_PARENT) && ns->parentns ? ns->parentns->ns_outline: (ls->tree == LSNS_TREE_OWNER) && ns->ownerns ? ns->ownerns->ns_outline: NULL); @@ -827,10 +827,12 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table, xasprintf(&str, "%ju", (uintmax_t)ns->id); break; case COL_PID: - xasprintf(&str, "%d", (int) proc->pid); + if (proc) + xasprintf(&str, "%d", (int) proc->pid); break; case COL_PPID: - xasprintf(&str, "%d", (int) proc->ppid); + if (proc) + xasprintf(&str, "%d", (int) proc->ppid); break; case COL_TYPE: xasprintf(&str, "%s", ns_names[ns->type]); @@ -839,20 +841,30 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table, xasprintf(&str, "%d", ns->nprocs); break; case COL_COMMAND: + if (!proc) + break; str = proc_get_command(proc->pid); if (!str) str = proc_get_command_name(proc->pid); break; case COL_PATH: + if (!proc) + break; xasprintf(&str, "/proc/%d/ns/%s", (int) proc->pid, ns_names[ns->type]); break; case COL_UID: + if (!proc) + break; xasprintf(&str, "%d", (int) proc->uid); break; case COL_USER: + if (!proc) + break; xasprintf(&str, "%s", get_id(uid_cache, proc->uid)->name); break; case COL_NETNSID: + if (!proc) + break; if (ns->type == LSNS_ID_NET) netnsid_xasputs(&str, proc->netnsid); break; @@ -875,7 +887,7 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table, if (ls->tree == LSNS_TREE_OWNER || ls->tree == LSNS_TREE_PARENT) ns->ns_outline = line; - else + else if (proc) proc->outline = line; } From c67b83c10d6a0aec46c7f14aed4a8f7c5cbf88fc Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Thu, 29 Apr 2021 04:39:13 +0900 Subject: [PATCH 09/26] lsns: reorganize members specifying other namespaces in lsns_namespace This is a preparation change for planed "tree interpolation" patch. parentid, ownerid, parentns, and ownerns were members of lsns_namespace struct. When interpolating missing namespaces for building a unified name space tree, duplicated functions are needed; one is for parentid and parentns members, and another is for ownerid and ownerns members. To avoid the duplication, this change unifies the members as following: parentid and ownerid => related_id [2] parentns and ownerns => related_ns [2] Signed-off-by: Masatake YAMATO --- sys-utils/lsns.c | 54 ++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c index d9b46a528..a09c84dfb 100644 --- a/sys-utils/lsns.c +++ b/sys-utils/lsns.c @@ -142,18 +142,22 @@ static char *ns_names[] = { [LSNS_ID_TIME] = "time" }; +enum { + RELA_PARENT, + RELA_OWNER, + MAX_RELA +}; + struct lsns_namespace { ino_t id; int type; /* LSNS_* */ int nprocs; int netnsid; - ino_t parentid; - ino_t ownerid; + ino_t related_id[MAX_RELA]; struct lsns_process *proc; - struct lsns_namespace *parentns; - struct lsns_namespace *ownerns; + struct lsns_namespace *related_ns[MAX_RELA]; struct libscols_line *ns_outline; struct list_head namespaces; /* lsns->processes member */ @@ -620,8 +624,8 @@ static struct lsns_namespace *add_namespace(struct lsns *ls, int type, ino_t ino ns->type = type; ns->id = ino; - ns->parentid = parent_ino; - ns->ownerid = owner_ino; + ns->related_id[RELA_PARENT] = parent_ino; + ns->related_id[RELA_OWNER] = owner_ino; list_add_tail(&ns->namespaces, &ls->namespaces); return ns; @@ -704,15 +708,15 @@ static int read_namespaces(struct lsns *ls) struct lsns_namespace *pns = list_entry(pp, struct lsns_namespace, namespaces); if (ns->type == LSNS_ID_USER || ns->type == LSNS_ID_PID) { - if (ns->parentid == pns->id) - ns->parentns = pns; - if (ns->ownerid == pns->id) - ns->ownerns = pns; - if (ns->parentns && ns->ownerns) + if (ns->related_id[RELA_PARENT] == pns->id) + ns->related_ns[RELA_PARENT] = pns; + if (ns->related_id[RELA_OWNER] == pns->id) + ns->related_ns[RELA_OWNER] = pns; + if (ns->related_ns[RELA_PARENT] && ns->related_ns[RELA_OWNER]) break; } else { - if (ns->ownerid == pns->id) { - ns->ownerns = pns; + if (ns->related_id[RELA_OWNER] == pns->id) { + ns->related_ns[RELA_OWNER] = pns; break; } } @@ -811,8 +815,8 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table, line = scols_table_new_line(table, (ls->tree == LSNS_TREE_PROCESS && proc) && proc->parent ? proc->parent->outline: - (ls->tree == LSNS_TREE_PARENT) && ns->parentns ? ns->parentns->ns_outline: - (ls->tree == LSNS_TREE_OWNER) && ns->ownerns ? ns->ownerns->ns_outline: + (ls->tree == LSNS_TREE_PARENT) && ns->related_ns[RELA_PARENT] ? ns->related_ns[RELA_PARENT]->ns_outline: + (ls->tree == LSNS_TREE_OWNER) && ns->related_ns[RELA_OWNER] ? ns->related_ns[RELA_OWNER]->ns_outline: NULL); if (!line) { warn(_("failed to add line to output")); @@ -872,10 +876,10 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table, nsfs_xasputs(&str, ns, ls->tab, ls->no_wrap ? ',' : '\n'); break; case COL_PNS: - xasprintf(&str, "%ju", (uintmax_t)ns->parentid); + xasprintf(&str, "%ju", (uintmax_t)ns->related_id[RELA_PARENT]); break; case COL_ONS: - xasprintf(&str, "%ju", (uintmax_t)ns->ownerid); + xasprintf(&str, "%ju", (uintmax_t)ns->related_id[RELA_OWNER]); break; default: break; @@ -956,16 +960,16 @@ static void show_namespace(struct lsns *ls, struct libscols_table *tab, * create a tree from owner->owned and/or parent->child relation */ if (ls->tree == LSNS_TREE_OWNER - && ns->ownerns - && !ns->ownerns->ns_outline) - show_namespace(ls, tab, ns->ownerns, ns->ownerns->proc); + && ns->related_ns[RELA_OWNER] + && !ns->related_ns[RELA_OWNER]->ns_outline) + show_namespace(ls, tab, ns->related_ns[RELA_OWNER], ns->related_ns[RELA_OWNER]->proc); else if (ls->tree == LSNS_TREE_PARENT) { - if (ns->parentns) { - if (!ns->parentns->ns_outline) - show_namespace(ls, tab, ns->parentns, ns->parentns->proc); + if (ns->related_ns[RELA_PARENT]) { + if (!ns->related_ns[RELA_PARENT]->ns_outline) + show_namespace(ls, tab, ns->related_ns[RELA_PARENT], ns->related_ns[RELA_PARENT]->proc); } - else if (ns->ownerns && !ns->ownerns->ns_outline) - show_namespace(ls, tab, ns->ownerns, ns->ownerns->proc); + else if (ns->related_ns[RELA_OWNER] && !ns->related_ns[RELA_OWNER]->ns_outline) + show_namespace(ls, tab, ns->related_ns[RELA_OWNER], ns->related_ns[RELA_OWNER]->proc); } add_scols_line(ls, tab, ns, proc); From de72df79d72fa906e71e2ac922d8745ff22deee5 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Thu, 29 Apr 2021 05:49:33 +0900 Subject: [PATCH 10/26] lsns: interpolate missing namespaces for converting forests to a tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tree of *parent* and *owner* could be forests because *lsns* cannot track a namespace having no process. This change tries interpolating the missing namespaces by calling ioctl(NS_GET_PARENT) and ioctl(NS_GET_USERNS) recursively. The original output for -Tparent: # ./lsns -Tparent NS TYPE NPROCS PID USER COMMAND 4026531837 user 404 1 root /usr/lib/systemd/sy ├─4026532508 user 1 29376 yamato /usr/lib64/firefox/ ... └─4026533513 user 1 24245 yamato /usr/lib64/firefox/ ... 4026533733 user 1 30839 yamato /opt/google/chrome- 4026533734 user 15 10076 yamato /opt/google/chrome- user namespaces 4026533733 and 4026533734 are orphans. lsns could not find their parents. With this change: # ./lsns-with-changes -Tparent NS TYPE NPROCS PID USER COMMAND 4026531837 user 404 1 root /usr/lib/systemd/ ├─4026532508 user 1 29376 yamato /usr/lib64/firefo ... ├─4026532639 user 0 │ ├─4026532637 user 0 │ │ └─4026533733 user 1 30839 yamato /opt/google/chrom │ └─4026533734 user 14 10076 yamato /opt/google/chrom Now user namespaces 4026533733 and 4026533734 are integrated to the tree. lsns interpolates the missing namespace 4026532639 and 4026532637 for the integration. The original output for -Towner: # ./lsns -Towner NS TYPE NPROCS PID USER COMMAND 4026531837 user 405 1 root /usr/lib/systemd/s ├─4026531835 cgroup 431 1 root /usr/lib/systemd/s ... 4026532638 pid 1 30839 yamato /opt/google/chrome 4026532640 pid 2 30837 yamato /opt/google/chrome ... pid namespaces 4026532638 and 4026532640 are orphans. lsns could not find their owners. With this change: # ./lsns-with-changes -Towner NS TYPE NPROCS PID USER COMMAND 4026531837 user 403 1 root /usr/lib/systemd ├─4026531835 cgroup 429 1 root /usr/lib/systemd ... ├─4026532639 user 0 ... │ ├─4026532637 user 0 │ │ ├─4026532638 pid 1 30839 yamato /opt/google/chro │ │ ├─4026533638 net 1 30839 yamato /opt/google/chro │ │ └─4026533733 user 1 30839 yamato /opt/google/chro │ ├─4026532640 pid 2 30837 yamato /opt/google/chro Now pid namespaces 4026532638 and 4026532640 are integrated to the tree. lsns interpolates the missing namespace 4026532639 and 4026532637 for the integration. Signed-off-by: Masatake YAMATO --- sys-utils/lsns.8.adoc | 1 - sys-utils/lsns.c | 141 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 1 deletion(-) diff --git a/sys-utils/lsns.8.adoc b/sys-utils/lsns.8.adoc index 738f87106..651d3fe9e 100644 --- a/sys-utils/lsns.8.adoc +++ b/sys-utils/lsns.8.adoc @@ -69,7 +69,6 @@ If *process* is given as _rel_, print proecss tree(s) in each name space. This i If *parent* is given, print tree(s) constructed by the parent/child relationship. If *owner* is given, print tree(s) constructed by the owner/owned relationship. *owner* is used as default when _rel_ is omitted. -The result of *parent* and *owner* can be forests because *lsns* cannot track a namespace having no process. *-V*, *--version*:: diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c index a09c84dfb..8905a13bd 100644 --- a/sys-utils/lsns.c +++ b/sys-utils/lsns.c @@ -676,9 +676,124 @@ static int netnsid_xasputs(char **str, int netnsid) return 0; } +static int clone_type_to_lsns_type(int clone_type) +{ + switch (clone_type) { + case CLONE_NEWNS: + return LSNS_ID_MNT; + case CLONE_NEWCGROUP: + return LSNS_ID_CGROUP; + case CLONE_NEWUTS: + return LSNS_ID_UTS; + case CLONE_NEWIPC: + return LSNS_ID_IPC; + case CLONE_NEWUSER: + return LSNS_ID_USER; + case CLONE_NEWPID: + return LSNS_ID_PID; + case CLONE_NEWNET: + return LSNS_ID_NET; + default: + return -1; + } +} + +static struct lsns_namespace *add_namespace_for_nsfd(struct lsns *ls, int fd, ino_t ino) +{ + int fd_owner = -1, fd_parent = -1; + struct stat st_owner, st_parent; + ino_t ino_owner = 0, ino_parent = 0; + struct lsns_namespace *ns; + int clone_type, lsns_type; + + clone_type = ioctl(fd, NS_GET_NSTYPE); + if (clone_type < 0) + return NULL; + lsns_type = clone_type_to_lsns_type(clone_type); + if (lsns_type < 0) + return NULL; + + fd_owner = ioctl(fd, NS_GET_USERNS); + if (fd_owner < 0) + goto parent; + if (fstat(fd_owner, &st_owner) < 0) + goto parent; + ino_owner = st_owner.st_ino; + + parent: + fd_parent = ioctl(fd, NS_GET_PARENT); + if (fd_parent < 0) + goto add_ns; + if (fstat(fd_parent, &st_parent) < 0) + goto add_ns; + ino_parent = st_parent.st_ino; + + add_ns: + ns = add_namespace(ls, lsns_type, ino, ino_parent, ino_owner); + + if ((lsns_type == LSNS_ID_USER || lsns_type == LSNS_ID_PID) + && ino_parent != ino && ino_parent != 0) { + ns->related_ns[RELA_PARENT] = get_namespace(ls, ino_parent); + if (!ns->related_ns[RELA_PARENT]) { + ns->related_ns[RELA_PARENT] = add_namespace_for_nsfd(ls, fd_parent, ino_parent); + if (ino_parent == ino_owner) + ns->related_ns[RELA_OWNER] = ns->related_ns[RELA_PARENT]; + } + } + + if (ns->related_ns[RELA_OWNER] == NULL && ino_owner != 0) { + ns->related_ns[RELA_OWNER] = get_namespace(ls, ino_owner); + if (!ns->related_ns[RELA_OWNER]) + ns->related_ns[RELA_OWNER] = add_namespace_for_nsfd(ls, fd_owner, ino_owner); + } + + if (fd_owner >= 0) + close(fd_owner); + if (fd_parent >= 0) + close(fd_parent); + + return ns; +} + +static void interpolate_missing_namespaces (struct lsns *ls, struct lsns_namespace *orphan, int rela) +{ + const int cmd[MAX_RELA] = { + [RELA_PARENT] = NS_GET_PARENT, + [RELA_OWNER] = NS_GET_USERNS + }; + char buf[BUFSIZ]; + int fd_orphan, fd_missing; + struct stat st; + + orphan->related_ns[rela] = get_namespace(ls, orphan->related_id[rela]); + if (orphan->related_ns[rela]) + return; + + snprintf(buf, sizeof(buf), "/proc/%d/ns/%s", orphan->proc->pid, ns_names [orphan->type]); + fd_orphan = open(buf, O_RDONLY); + if (fd_orphan < 0) + return; + + fd_missing = ioctl (fd_orphan, cmd[rela]); + close (fd_orphan); + if (fd_missing < 0) + return; + + if (fstat(fd_missing, &st) < 0 + || st.st_ino != orphan->related_id[rela]) { + close (fd_missing); + return; + } + + orphan->related_ns[rela] = add_namespace_for_nsfd(ls, fd_missing, orphan->related_id[rela]); + close (fd_missing); +} + static int read_namespaces(struct lsns *ls) { struct list_head *p; + struct lsns_namespace *orphan[2] = {NULL, NULL}; + int rela; DBG(NS, ul_debug("reading namespace")); @@ -721,6 +836,32 @@ static int read_namespaces(struct lsns *ls) } } } + + /* lsns scans /proc/[0-9]+ for finding namespaces. + * So if a namespace has no process, lsns cannot + * find it. Here we call it a missing namespace. + * + * If the id for a related namesspce is known but + * namespace for the id is not found, there must + * be orphan namespaces. A missing namespace is an + * owner or a parent of the orphan namespace. + */ + for (rela = 0; rela < MAX_RELA; rela++) { + if (ns->related_id[rela] != 0 + && ns->related_ns[rela] == NULL) { + ns->related_ns[rela] = orphan[rela]; + orphan[rela] = ns; + } + } + } + } + + for (rela = 0; rela < MAX_RELA; rela++) { + while (orphan[rela]) { + struct lsns_namespace *current = orphan[rela]; + orphan[rela] = orphan[rela]->related_ns[rela]; + current->related_ns[rela] = NULL; + interpolate_missing_namespaces (ls, current, rela); } } From 09710a221212a58888c6f50b6a3b09b31778a44e Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Fri, 30 Apr 2021 02:44:12 +0900 Subject: [PATCH 11/26] fixup! lsns: interpolate missing namespaces for converting forests to a tree --- sys-utils/lsns.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c index 8905a13bd..ac31c8fd9 100644 --- a/sys-utils/lsns.c +++ b/sys-utils/lsns.c @@ -755,7 +755,7 @@ static struct lsns_namespace *add_namespace_for_nsfd(struct lsns *ls, int fd, in return ns; } -static void interpolate_missing_namespaces (struct lsns *ls, struct lsns_namespace *orphan, int rela) +static void interpolate_missing_namespaces(struct lsns *ls, struct lsns_namespace *orphan, int rela) { const int cmd[MAX_RELA] = { [RELA_PARENT] = NS_GET_PARENT, @@ -769,24 +769,24 @@ static void interpolate_missing_namespaces (struct lsns *ls, struct lsns_namespa if (orphan->related_ns[rela]) return; - snprintf(buf, sizeof(buf), "/proc/%d/ns/%s", orphan->proc->pid, ns_names [orphan->type]); + snprintf(buf, sizeof(buf), "/proc/%d/ns/%s", orphan->proc->pid, ns_names[orphan->type]); fd_orphan = open(buf, O_RDONLY); if (fd_orphan < 0) return; - fd_missing = ioctl (fd_orphan, cmd[rela]); - close (fd_orphan); + fd_missing = ioctl(fd_orphan, cmd[rela]); + close(fd_orphan); if (fd_missing < 0) return; if (fstat(fd_missing, &st) < 0 || st.st_ino != orphan->related_id[rela]) { - close (fd_missing); + close(fd_missing); return; } orphan->related_ns[rela] = add_namespace_for_nsfd(ls, fd_missing, orphan->related_id[rela]); - close (fd_missing); + close(fd_missing); } static int read_namespaces(struct lsns *ls) @@ -861,7 +861,7 @@ static int read_namespaces(struct lsns *ls) struct lsns_namespace *current = orphan[rela]; orphan[rela] = orphan[rela]->related_ns[rela]; current->related_ns[rela] = NULL; - interpolate_missing_namespaces (ls, current, rela); + interpolate_missing_namespaces(ls, current, rela); } } From f91ffe44dd4da05878c39f555aae357dc2cb972c Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Fri, 30 Apr 2021 22:14:22 +0900 Subject: [PATCH 12/26] lsns: fill UID and USER columns for interpolated namespaces Signed-off-by: Masatake YAMATO --- sys-utils/lsns.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c index ac31c8fd9..614fb8fc5 100644 --- a/sys-utils/lsns.c +++ b/sys-utils/lsns.c @@ -159,6 +159,7 @@ struct lsns_namespace { struct lsns_namespace *related_ns[MAX_RELA]; struct libscols_line *ns_outline; + uid_t uid_fallback; /* refer this member if `proc' is NULL. */ struct list_head namespaces; /* lsns->processes member */ struct list_head processes; /* head of lsns_process *siblings */ @@ -730,6 +731,8 @@ static struct lsns_namespace *add_namespace_for_nsfd(struct lsns *ls, int fd, in add_ns: ns = add_namespace(ls, lsns_type, ino, ino_parent, ino_owner); + ioctl(fd, NS_GET_OWNER_UID, &ns->uid_fallback); + add_uid(uid_cache, ns->uid_fallback); if ((lsns_type == LSNS_ID_USER || lsns_type == LSNS_ID_PID) && ino_parent != ino && ino_parent != 0) { @@ -998,14 +1001,10 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table, xasprintf(&str, "/proc/%d/ns/%s", (int) proc->pid, ns_names[ns->type]); break; case COL_UID: - if (!proc) - break; - xasprintf(&str, "%d", (int) proc->uid); + xasprintf(&str, "%d", proc? (int) proc->uid: (int) ns->uid_fallback); break; case COL_USER: - if (!proc) - break; - xasprintf(&str, "%s", get_id(uid_cache, proc->uid)->name); + xasprintf(&str, "%s", get_id(uid_cache, proc? proc->uid: ns->uid_fallback)->name); break; case COL_NETNSID: if (!proc) From be1a10bb1f555e6ebb541edfd94ddec68401177f Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 3 May 2021 10:51:06 +0200 Subject: [PATCH 13/26] lsns: fix copy & past in man page Signed-off-by: Karel Zak --- sys-utils/lsns.8.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys-utils/lsns.8.adoc b/sys-utils/lsns.8.adoc index 651d3fe9e..4623469dd 100644 --- a/sys-utils/lsns.8.adoc +++ b/sys-utils/lsns.8.adoc @@ -64,7 +64,7 @@ Do not truncate text in columns. Do not use multi-line text in columns. *-T*, *--tree* _rel_:: -Use list output format. +Use tree-like output format. If *process* is given as _rel_, print proecss tree(s) in each name space. This is default when *--tree* is not specified. If *parent* is given, print tree(s) constructed by the parent/child relationship. If *owner* is given, print tree(s) constructed by the owner/owned relationship. From 0f344e24320560792da20567b0128b2faf7d4da0 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 3 May 2021 10:59:45 +0200 Subject: [PATCH 14/26] lsns: fix old error message Signed-off-by: Karel Zak --- sys-utils/lsns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c index 614fb8fc5..80e9d8819 100644 --- a/sys-utils/lsns.c +++ b/sys-utils/lsns.c @@ -1319,7 +1319,7 @@ int main(int argc, char *argv[]) else if (strcmp (optarg, "process") == 0) ls.tree = LSNS_TREE_PROCESS; else if (strcmp (optarg, "owner") != 0) - errx(EXIT_FAILURE, _("unknown nstree type: %s"), optarg); + errx(EXIT_FAILURE, _("unknown tree type: %s"), optarg); } break; From 0d092db5c40b94e1ea9529f3f1c384a74eca19f8 Mon Sep 17 00:00:00 2001 From: Werner Fink Date: Mon, 17 May 2021 17:20:32 +0200 Subject: [PATCH 15/26] sulogin: ignore none-existing console devices and also none-functional console devices. Redirect the error messages to the appropiate console device. Signed-off-by: Werner Fink --- login-utils/sulogin-consoles.h | 1 + login-utils/sulogin.c | 97 ++++++++++++++++++++++++++++------ 2 files changed, 82 insertions(+), 16 deletions(-) diff --git a/login-utils/sulogin-consoles.h b/login-utils/sulogin-consoles.h index 0bfbc3871..12032c997 100644 --- a/login-utils/sulogin-consoles.h +++ b/login-utils/sulogin-consoles.h @@ -40,6 +40,7 @@ struct console { int fd, id; #define CON_SERIAL 0x0001 #define CON_NOTTY 0x0002 +#define CON_EIO 0x0004 pid_t pid; struct chardata cp; struct termios tio; diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c index 6ed63f1a0..8b4e2d108 100644 --- a/login-utils/sulogin.c +++ b/login-utils/sulogin.c @@ -52,6 +52,7 @@ #ifdef __linux__ # include # include +# include #endif #include "c.h" @@ -104,6 +105,9 @@ static void tcinit(struct console *con) int flags = 0, mode = 0; struct termios *tio = &con->tio; const int fd = con->fd; +#if defined(TIOCGSERIAL) + struct serial_struct serinfo; +#endif #ifdef USE_PLYMOUTH_SUPPORT struct termios lock; int i = (plymouth_command(MAGIC_PING)) ? PLYMOUTH_TERMIOS_FLAGS_DELAY : 0; @@ -123,27 +127,72 @@ static void tcinit(struct console *con) } memset(&lock, 0, sizeof(struct termios)); ioctl(fd, TIOCSLCKTRMIOS, &lock); -#endif errno = 0; +#endif + +#if defined(TIOCGSERIAL) + if (ioctl(fd, TIOCGSERIAL, &serinfo) >= 0) + con->flags |= CON_SERIAL; + errno = 0; +#else +# if defined(KDGKBMODE) + if (ioctl(fd, KDGKBMODE, &mode) < 0) + con->flags |= CON_SERIAL; + errno = 0; +# endif +#endif if (tcgetattr(fd, tio) < 0) { - warn(_("tcgetattr failed")); - con->flags |= CON_NOTTY; - return; + int saveno = errno; +#if defined(KDGKBMODE) || defined(TIOCGSERIAL) + if (con->flags & CON_SERIAL) { /* Try to recover this */ + +# if defined(TIOCGSERIAL) + serinfo.flags |= ASYNC_SKIP_TEST; /* Skip test of UART */ + + if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0) + goto tcgeterr; + if (ioctl(fd, TIOCSERCONFIG) < 0) /* Try to autoconfigure */ + goto tcgeterr; + if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) + goto tcgeterr; /* Ouch */ +# endif + if (tcgetattr(fd, tio) < 0) /* Retry to get tty attributes */ + saveno = errno; + } +# if defined(TIOCGSERIAL) + tcgeterr: +# endif + if (saveno) +#endif + { + FILE *fcerr = fdopen(fd, "w"); + if (fcerr) { + fprintf(fcerr, _("tcgetattr failed")); + fclose(fcerr); + } + warn(_("tcgetattr failed")); + + con->flags &= ~CON_SERIAL; + if (saveno != EIO) + con->flags |= CON_NOTTY; + else + con->flags |= CON_EIO; + + errno = 0; + return; + } } /* Handle lines other than virtual consoles here */ -#if defined(KDGKBMODE) - if (ioctl(fd, KDGKBMODE, &mode) < 0) +#if defined(KDGKBMODE) || defined(TIOCGSERIAL) + if (con->flags & CON_SERIAL) #endif { speed_t ispeed, ospeed; struct winsize ws; errno = 0; - /* this is a modem line */ - con->flags |= CON_SERIAL; - /* Flush input and output queues on modem lines */ tcflush(fd, TCIOFLUSH); @@ -220,6 +269,8 @@ static void tcfinal(struct console *con) struct termios *tio = &con->tio; const int fd = con->fd; + if (con->flags & CON_EIO) + return; if ((con->flags & CON_SERIAL) == 0) { xsetenv("TERM", "linux", 1); return; @@ -557,12 +608,16 @@ err: static void setup(struct console *con) { int fd = con->fd; - const pid_t pid = getpid(), pgrp = getpgid(0), ppgrp = - getpgid(getppid()), ttypgrp = tcgetpgrp(fd); + const pid_t pid = getpid(), pgrp = getpgid(0), ppgrp = getpgid(getppid()); + pid_t ttypgrp; if (con->flags & CON_NOTTY) + goto notty; + if (con->flags & CON_EIO) return; + ttypgrp = tcgetpgrp(fd); + /* * Only go through this trouble if the new * tty doesn't fall in this process group. @@ -585,6 +640,7 @@ static void setup(struct console *con) ioctl(fd, TIOCSCTTY, (char *)1); tcsetpgrp(fd, ppgrp); } +notty: dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); @@ -608,20 +664,25 @@ static const char *getpasswd(struct console *con) struct termios tty; static char pass[128], *ptr; struct chardata *cp; - const char *ret = pass; + const char *ret = NULL; unsigned char tc; char c, ascval; int eightbit; const int fd = con->fd; - if (con->flags & CON_NOTTY) + if (con->flags & CON_EIO) goto out; + cp = &con->cp; tty = con->tio; + tc = 0; + ret = pass; tty.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY); tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP|ISIG); - tc = (tcsetattr(fd, TCSAFLUSH, &tty) == 0); + + if ((con->flags & CON_NOTTY) == 0) + tc = (tcsetattr(fd, TCSAFLUSH, &tty) == 0); sigemptyset(&sa.sa_mask); sa.sa_handler = alrm_handler; @@ -647,11 +708,12 @@ static const char *getpasswd(struct console *con) } ret = NULL; switch (errno) { - case 0: case EIO: + con->flags |= CON_EIO; case ESRCH: case EINVAL: case ENOENT: + case 0: break; default: warn(_("cannot read %s"), con->tty); @@ -969,10 +1031,13 @@ int main(int argc, char **argv) con = list_entry(ptr, struct console, entry); if (con->id >= CONMAX) break; + if (con->flags & CON_EIO) + goto next; switch ((con->pid = fork())) { case 0: mask_signal(SIGCHLD, SIG_DFL, NULL); + dup2(con->fd, STDERR_FILENO); nofork: setup(con); while (1) { @@ -1027,7 +1092,7 @@ int main(int argc, char **argv) default: break; } - + next: ptr = ptr->next; } while (ptr != &consoles); From 419861d5bf1704e3d76b1402450fe81a77b08c90 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 18 May 2021 12:58:45 +0200 Subject: [PATCH 16/26] sulogin: fix whitespace error Signed-off-by: Karel Zak --- login-utils/sulogin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c index 8b4e2d108..946c48cb5 100644 --- a/login-utils/sulogin.c +++ b/login-utils/sulogin.c @@ -132,7 +132,7 @@ static void tcinit(struct console *con) #if defined(TIOCGSERIAL) if (ioctl(fd, TIOCGSERIAL, &serinfo) >= 0) - con->flags |= CON_SERIAL; + con->flags |= CON_SERIAL; errno = 0; #else # if defined(KDGKBMODE) From 9b9e4f5d06be55f4b9e1a52b448055933df92c6b Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 24 May 2021 12:24:33 +0200 Subject: [PATCH 17/26] lscpu: add SCALMHZ% and "CPU scaling MHz:" $ lscpu ... Model name: Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz CPU family: 6 Model: 60 Thread(s) per core: 2 Core(s) per socket: 4 Socket(s): 1 Stepping: 3 CPU(s) scaling MHz: 61% CPU max MHz: 4400.0000 CPU min MHz: 800.0000 ... $ lscpu -e=CPU,MAXMHZ,MINMHZ,MHZ,SCALMHZ% CPU MAXMHZ MINMHZ MHZ SCALMHZ% 0 4400.0000 800.0000 2800.000 64% 1 4400.0000 800.0000 4000.146 91% 2 4400.0000 800.0000 2800.000 64% 3 4400.0000 800.0000 2800.000 64% 4 4400.0000 800.0000 2800.000 64% 5 4400.0000 800.0000 4400.000 100% 6 4400.0000 800.0000 800.000 18% 7 4400.0000 800.0000 2800.000 64% Addresses: https://github.com/karelzak/util-linux/issues/1314 Signed-off-by: Karel Zak --- Documentation/TODO | 1 + sys-utils/lscpu-cputype.c | 6 ++++++ sys-utils/lscpu-topology.c | 21 +++++++++++++++++++++ sys-utils/lscpu.c | 9 +++++++++ sys-utils/lscpu.h | 4 +++- 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/Documentation/TODO b/Documentation/TODO index 33ffa189d..e382e4b97 100644 --- a/Documentation/TODO +++ b/Documentation/TODO @@ -53,6 +53,7 @@ cal lscpu ----- + - add --freq output to visualise CPU use, see https://github.com/karelzak/util-linux/issues/1314 - read cpuid and uname information from file if --sysroot is specified, then we can prepare regression tests completely independent on hw and architecture. diff --git a/sys-utils/lscpu-cputype.c b/sys-utils/lscpu-cputype.c index 834e1c663..c2c1dc376 100644 --- a/sys-utils/lscpu-cputype.c +++ b/sys-utils/lscpu-cputype.c @@ -510,6 +510,12 @@ int lscpu_read_cpuinfo(struct lscpu_cxt *cxt) pr->curr_type->static_mhz = xstrdup(value); if (pattern->id == PAT_BOGOMIPS_CPU && pr->curr_type && !pr->curr_type->bogomips) pr->curr_type->bogomips = xstrdup(value); + if (pattern->id == PAT_MHZ && pr->curr_cpu && value) { + errno = 0; + pr->curr_cpu->mhz_cur_freq = strtof(value, NULL); + if (errno) + pr->curr_cpu->mhz_cur_freq = 0; + } break; case CPUINFO_LINE_CPUTYPE: if (pr->curr_type && is_different_cputype(pr->curr_type, pattern->offset, value)) { diff --git a/sys-utils/lscpu-topology.c b/sys-utils/lscpu-topology.c index 485c17485..328ee7cbc 100644 --- a/sys-utils/lscpu-topology.c +++ b/sys-utils/lscpu-topology.c @@ -583,6 +583,27 @@ float lsblk_cputype_get_minmhz(struct lscpu_cxt *cxt, struct lscpu_cputype *ct) return res; } +/* returns scaling (use) of CPUs freq. in percent */ +float lsblk_cputype_get_scalmhz(struct lscpu_cxt *cxt, struct lscpu_cputype *ct) +{ + size_t i; + float fmax = 0, fcur = 0; + + for (i = 0; i < cxt->npossibles; i++) { + struct lscpu_cpu *cpu = cxt->cpus[i]; + + if (!cpu || cpu->type != ct || !is_cpu_present(cxt, cpu)) + continue; + if (cpu->mhz_max_freq <= 0.0 || cpu->mhz_cur_freq <= 0.0) + continue; + fmax += cpu->mhz_max_freq; + fcur += cpu->mhz_cur_freq; + } + if (fcur <= 0.0) + return 0.0; + return fcur / fmax * 100; +} + int lscpu_read_topology(struct lscpu_cxt *cxt) { size_t i; diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c index 29afd9116..5fba08329 100644 --- a/sys-utils/lscpu.c +++ b/sys-utils/lscpu.c @@ -105,6 +105,7 @@ enum { COL_CPU_CONFIGURED, COL_CPU_ONLINE, COL_CPU_MHZ, + COL_CPU_SCALMHZ, COL_CPU_MAXMHZ, COL_CPU_MINMHZ, }; @@ -150,6 +151,7 @@ static struct lscpu_coldesc coldescs_cpu[] = [COL_CPU_CONFIGURED] = { "CONFIGURED", N_("shows if the hypervisor has allocated the CPU") }, [COL_CPU_ONLINE] = { "ONLINE", N_("shows if Linux currently makes use of the CPU"), SCOLS_FL_RIGHT }, [COL_CPU_MHZ] = { "MHZ", N_("shows the currently MHz of the CPU"), SCOLS_FL_RIGHT }, + [COL_CPU_SCALMHZ] = { "SCALMHZ%", N_("shows scaling percentage of the CPU frequency"), SCOLS_FL_RIGHT }, [COL_CPU_MAXMHZ] = { "MAXMHZ", N_("shows the maximum MHz of the CPU"), SCOLS_FL_RIGHT }, [COL_CPU_MINMHZ] = { "MINMHZ", N_("shows the minimum MHz of the CPU"), SCOLS_FL_RIGHT } }; @@ -425,6 +427,10 @@ static char *get_cell_data( if (cpu->mhz) xstrncpy(buf, cpu->mhz, bufsz); break; + case COL_CPU_SCALMHZ: + if (cpu->mhz_cur_freq && cpu->mhz_max_freq) + snprintf(buf, bufsz, "%.0f%%", cpu->mhz_cur_freq / cpu->mhz_max_freq * 100); + break; case COL_CPU_MAXMHZ: if (cpu->mhz_max_freq) snprintf(buf, bufsz, "%.4f", cpu->mhz_max_freq); @@ -890,6 +896,9 @@ print_summary_cputype(struct lscpu_cxt *cxt, add_summary_s(tb, sec, _("CPU static MHz:"), ct->static_mhz); if (ct->has_freq) { + float scal = lsblk_cputype_get_scalmhz(cxt, ct); + if (scal > 0.0) + add_summary_x(tb, sec, _("CPU(s) scaling MHz:"), "%.0f%%", scal); add_summary_x(tb, sec, _("CPU max MHz:"), "%.4f", lsblk_cputype_get_maxmhz(cxt, ct)); add_summary_x(tb, sec, _("CPU min MHz:"), "%.4f", lsblk_cputype_get_minmhz(cxt, ct)); } diff --git a/sys-utils/lscpu.h b/sys-utils/lscpu.h index e52c77c22..62f532581 100644 --- a/sys-utils/lscpu.h +++ b/sys-utils/lscpu.h @@ -127,11 +127,12 @@ struct lscpu_cpu { int logical_id; char *bogomips; /* per-CPU bogomips */ - char *mhz; /* max freq from cpuinfo */ + char *mhz; /* freq from cpuinfo */ char *dynamic_mhz; /* from cpuinf for s390 */ char *static_mhz; /* from cpuinf for s390 */ float mhz_max_freq; /* realtime freq from /sys/.../cpuinfo_max_freq */ float mhz_min_freq; /* realtime freq from /sys/.../cpuinfo_min_freq */ + float mhz_cur_freq; int coreid; int socketid; @@ -280,6 +281,7 @@ void lscpu_cputype_free_topology(struct lscpu_cputype *ct); float lsblk_cputype_get_maxmhz(struct lscpu_cxt *cxt, struct lscpu_cputype *ct); float lsblk_cputype_get_minmhz(struct lscpu_cxt *cxt, struct lscpu_cputype *ct); +float lsblk_cputype_get_scalmhz(struct lscpu_cxt *cxt, struct lscpu_cputype *ct); struct lscpu_arch *lscpu_read_architecture(struct lscpu_cxt *cxt); void lscpu_free_architecture(struct lscpu_arch *ar); From ff6513c74e7fc97e2297b12dddb58d9b6513fcaf Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 24 May 2021 13:19:47 +0200 Subject: [PATCH 18/26] lscpu: use MHZ as number to be locale sensitive Fixes: https://github.com/karelzak/util-linux/issues/1316 Signed-off-by: Karel Zak --- sys-utils/lscpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c index 5fba08329..90bcde5ef 100644 --- a/sys-utils/lscpu.c +++ b/sys-utils/lscpu.c @@ -424,8 +424,8 @@ static char *get_cell_data( is_cpu_online(cxt, cpu) ? _("yes") : _("no")); break; case COL_CPU_MHZ: - if (cpu->mhz) - xstrncpy(buf, cpu->mhz, bufsz); + if (cpu->mhz_cur_freq) + snprintf(buf, bufsz, "%.4f", cpu->mhz_cur_freq); break; case COL_CPU_SCALMHZ: if (cpu->mhz_cur_freq && cpu->mhz_max_freq) From afa7e09e4b77a2049fb0086553d255fbb461f011 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 24 May 2021 13:43:02 +0200 Subject: [PATCH 19/26] tests: update lscpu output Signed-off-by: Karel Zak --- tests/expected/lscpu/lscpu-vbox-win | 1 + tests/expected/lscpu/lscpu-vmware_fpe | 1 + tests/expected/lscpu/lscpu-x86_64-64cpu | 1 + tests/expected/lscpu/lscpu-x86_64-dell_e4310 | 1 + tests/expected/lscpu/lscpu-x86_64-epyc_7451 | 1 + 5 files changed, 5 insertions(+) diff --git a/tests/expected/lscpu/lscpu-vbox-win b/tests/expected/lscpu/lscpu-vbox-win index ab8a25c2c..bc0ed4cb6 100644 --- a/tests/expected/lscpu/lscpu-vbox-win +++ b/tests/expected/lscpu/lscpu-vbox-win @@ -10,6 +10,7 @@ Thread(s) per core: 1 Core(s) per socket: 2 Socket(s): 1 Stepping: 9 +CPU(s) scaling MHz: 42% CPU max MHz: 3800.0000 CPU min MHz: 1600.0000 BogoMIPS: 3355.62 diff --git a/tests/expected/lscpu/lscpu-vmware_fpe b/tests/expected/lscpu/lscpu-vmware_fpe index 363bdd931..469ad3884 100644 --- a/tests/expected/lscpu/lscpu-vmware_fpe +++ b/tests/expected/lscpu/lscpu-vmware_fpe @@ -11,6 +11,7 @@ Core(s) per socket: 4 Socket(s): 2 Stepping: 0 Frequency boost: enabled +CPU(s) scaling MHz: 48% CPU max MHz: 3200.0000 CPU min MHz: 1400.0000 BogoMIPS: 6399.69 diff --git a/tests/expected/lscpu/lscpu-x86_64-64cpu b/tests/expected/lscpu/lscpu-x86_64-64cpu index cd84ad46a..4e35abba1 100644 --- a/tests/expected/lscpu/lscpu-x86_64-64cpu +++ b/tests/expected/lscpu/lscpu-x86_64-64cpu @@ -10,6 +10,7 @@ Thread(s) per core: 2 Core(s) per socket: 8 Socket(s): 4 Stepping: 6 +CPU(s) scaling MHz: 53% CPU max MHz: 1996.0000 CPU min MHz: 1064.0000 BogoMIPS: 3990.31 diff --git a/tests/expected/lscpu/lscpu-x86_64-dell_e4310 b/tests/expected/lscpu/lscpu-x86_64-dell_e4310 index a0a9962c7..1847d5bb1 100644 --- a/tests/expected/lscpu/lscpu-x86_64-dell_e4310 +++ b/tests/expected/lscpu/lscpu-x86_64-dell_e4310 @@ -10,6 +10,7 @@ Thread(s) per core: 2 Core(s) per socket: 2 Socket(s): 1 Stepping: 5 +CPU(s) scaling MHz: 45% CPU max MHz: 2667.0000 CPU min MHz: 1199.0000 BogoMIPS: 5319.92 diff --git a/tests/expected/lscpu/lscpu-x86_64-epyc_7451 b/tests/expected/lscpu/lscpu-x86_64-epyc_7451 index 6e5085e84..c0548f97d 100644 --- a/tests/expected/lscpu/lscpu-x86_64-epyc_7451 +++ b/tests/expected/lscpu/lscpu-x86_64-epyc_7451 @@ -11,6 +11,7 @@ Core(s) per socket: 24 Socket(s): 2 Stepping: 2 Frequency boost: enabled +CPU(s) scaling MHz: 126% CPU max MHz: 2300.0000 CPU min MHz: 1200.0000 BogoMIPS: 4590.83 From 670b10ae363d40fbe7dfd3c2e9c3f8044bf630f1 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 25 May 2021 11:31:08 +0200 Subject: [PATCH 20/26] lib/c_strtod; add locale independent strtod() Signed-off-by: Karel Zak --- configure.ac | 3 ++ include/c_strtod.h | 6 +++ lib/Makemodule.am | 7 ++- lib/c_strtod.c | 105 +++++++++++++++++++++++++++++++++++++++++++++ lib/meson.build | 1 + meson.build | 3 ++ 6 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 include/c_strtod.h create mode 100644 lib/c_strtod.c diff --git a/configure.ac b/configure.ac index 26ec01d76..720e7d0d6 100644 --- a/configure.ac +++ b/configure.ac @@ -540,6 +540,7 @@ AC_CHECK_FUNCS([ \ jrand48 \ lchown \ llseek \ + newlocale \ mempcpy \ mkostemp \ nanosleep \ @@ -565,10 +566,12 @@ AC_CHECK_FUNCS([ \ strnchr \ strndup \ strnlen \ + strtod_l \ sysconf \ sysinfo \ timegm \ usleep \ + uselocale \ utimensat \ vwarnx \ warn \ diff --git a/include/c_strtod.h b/include/c_strtod.h new file mode 100644 index 000000000..eaa801c40 --- /dev/null +++ b/include/c_strtod.h @@ -0,0 +1,6 @@ +#ifndef UTIL_LINUX_C_STRTOD_H +#define UTIL_LINUX_C_STRTOD_H + +extern double c_strtod(char const *str, char **end); + +#endif diff --git a/lib/Makemodule.am b/lib/Makemodule.am index 5d95b37ea..1cdd1b146 100644 --- a/lib/Makemodule.am +++ b/lib/Makemodule.am @@ -18,6 +18,7 @@ libcommon_la_SOURCES = \ lib/color-names.c \ lib/crc32.c \ lib/crc32c.c \ + lib/c_strtod.c \ lib/encode.c \ lib/env.c \ lib/fileutils.c \ @@ -91,7 +92,8 @@ check_PROGRAMS += \ test_remove_env \ test_strutils \ test_ttyutils \ - test_timeutils + test_timeutils \ + test_c_strtod if LINUX @@ -135,6 +137,9 @@ test_mangle_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_MANGLE test_strutils_SOURCES = lib/strutils.c test_strutils_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_STRUTILS +test_c_strtod_SOURCES = lib/c_strtod.c +test_c_strtod_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM + test_colors_SOURCES = lib/colors.c lib/color-names.c test_colors_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_COLORS test_colors_LDADD = $(LDADD) libtcolors.la diff --git a/lib/c_strtod.c b/lib/c_strtod.c new file mode 100644 index 000000000..21b80fd35 --- /dev/null +++ b/lib/c_strtod.c @@ -0,0 +1,105 @@ +/* + * Locale-independent strtod(). + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + * Copyright (C) 2021 Karel Zak + */ +#include "c.h" + +#include +#include +#include + +#include "c_strtod.h" + +#if defined(HAVE_NEWLOCALE) && (defined(HAVE_STRTOD_L) || defined(HAVE_USELOCALE)) +# define USE_CLOCALE +#endif + +#if defined(USE_CLOCALE) +static volatile locale_t c_locale; + +static locale_t get_c_locale(void) +{ + if (!c_locale) + c_locale = newlocale(LC_ALL_MASK, "C", (locale_t) 0); + return c_locale; +} +#endif + + +double c_strtod(char const *str, char **end) +{ + double res; + int errsv; + +#if defined(USE_CLOCALE) + locale_t cl = get_c_locale(); + +#if defined(HAVE_STRTOD_L) + /* + * A) try strtod_l() for "C" locale + */ + if (cl) + return strtod_l(str, end, cl); +#elif defined(HAVE_USELOCALE) + /* + * B) classic strtod(), but switch to "C" locale by uselocal() + */ + if (cl) { + locale_t org_cl = uselocale(locale); + if (!org_cl) + return 0; + + res = strtod(str, end); + errsv = errno; + + uselocale(org_cl); + errno = errsv; + return res; + } +#endif /* HAVE_USELOCALE */ +#endif /* USE_CLOCALE */ + /* + * C) classic strtod(), but switch to "C" locale by setlocale() + */ + char *org_locale = setlocale(LC_NUMERIC, NULL); + + if (org_locale) { + org_locale = strdup(org_locale); + if (!org_locale) + return 0; + + setlocale(LC_NUMERIC, "C"); + } + res = strtod(str, end); + errsv = errno; + + if (org_locale) { + setlocale(LC_NUMERIC, org_locale); + free(org_locale); + } + errno = errsv; + return res; +} + +#ifdef TEST_PROGRAM +int main(int argc, char *argv[]) +{ + double res; + char *end; + + if (argc < 2) { + fprintf(stderr, "usage: %s decimal.number\n", + program_invocation_short_name); + return EXIT_FAILURE; + } + + res = c_strtod(argv[1], &end); + printf("Result: %g, errno: %d, endptr: '%s'\n", res, errno, end); + + return errno ? EXIT_FAILURE : EXIT_SUCCESS; +} +#endif diff --git a/lib/meson.build b/lib/meson.build index af08535d3..dcdbdf07d 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -5,6 +5,7 @@ lib_common_sources = ''' color-names.c crc32.c crc32c.c + c_strtod.c encode.c env.c fileutils.c diff --git a/meson.build b/meson.build index 898c55d72..c53fd36eb 100644 --- a/meson.build +++ b/meson.build @@ -460,6 +460,7 @@ funcs = ''' jrand48 lchown llseek + newlocale mempcpy mkostemp nanosleep @@ -484,6 +485,7 @@ funcs = ''' strnchr strndup strnlen + strtod_l sysconf sysinfo swapon @@ -491,6 +493,7 @@ funcs = ''' timegm unshare usleep + uselocale utimensat vwarnx warn From 0b538002dad7bb5e178740191961bcc69509a80d Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 25 May 2021 11:32:51 +0200 Subject: [PATCH 21/26] lscpu: use locale-independent strtod() when read from kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: Thomas Weißschuh Signed-off-by: Karel Zak --- sys-utils/lscpu-cputype.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys-utils/lscpu-cputype.c b/sys-utils/lscpu-cputype.c index c2c1dc376..023b56ee9 100644 --- a/sys-utils/lscpu-cputype.c +++ b/sys-utils/lscpu-cputype.c @@ -5,6 +5,7 @@ #include "lscpu.h" #include "fileutils.h" +#include "c_strtod.h" /* Lookup a pattern and get the value for format " : " */ @@ -512,7 +513,7 @@ int lscpu_read_cpuinfo(struct lscpu_cxt *cxt) pr->curr_type->bogomips = xstrdup(value); if (pattern->id == PAT_MHZ && pr->curr_cpu && value) { errno = 0; - pr->curr_cpu->mhz_cur_freq = strtof(value, NULL); + pr->curr_cpu->mhz_cur_freq = (float) c_strtod(value, NULL); if (errno) pr->curr_cpu->mhz_cur_freq = 0; } From f2d08d4ddc9bc601107df28dd8e4598cf2e0b420 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 25 May 2021 13:23:39 +0200 Subject: [PATCH 22/26] lscpu: read MHZ from /sys/.../cpufreq/scaling_cur_freq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is more portable and provides more stable results than /proc/cpuinfo. Fixes: https://github.com/karelzak/util-linux/pull/1317 Co-Author: Thomas Weißschuh Signed-off-by: Karel Zak --- sys-utils/lscpu-topology.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sys-utils/lscpu-topology.c b/sys-utils/lscpu-topology.c index 328ee7cbc..987ebff42 100644 --- a/sys-utils/lscpu-topology.c +++ b/sys-utils/lscpu-topology.c @@ -546,6 +546,16 @@ static int read_mhz(struct lscpu_cxt *cxt, struct lscpu_cpu *cpu) if (ul_path_readf_s32(sys, &mhz, "cpu%d/cpufreq/cpuinfo_min_freq", num) == 0) cpu->mhz_min_freq = (float) mhz / 1000; + /* The default current-frequency value comes is from /proc/cpuinfo (if + * available). This /proc value is usually based on MSR registers + * (APERF/APERF) and it changes pretty often. It seems better to read + * frequency from cpufreq subsystem that provides the current frequency + * for the current policy. There is also cpuinfo_cur_freq in sysfs, but + * it's not always available. + */ + if (ul_path_readf_s32(sys, &mhz, "cpu%d/cpufreq/scaling_cur_freq", num) == 0) + cpu->mhz_cur_freq = (float) mhz / 1000; + if (cpu->type && (cpu->mhz_min_freq || cpu->mhz_max_freq)) cpu->type->has_freq = 1; From 96476550dba2276466e312870083db85e159d712 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 25 May 2021 13:29:20 +0200 Subject: [PATCH 23/26] tests: update lscpu outputs --- tests/expected/lscpu/lscpu-armv7 | 1 + tests/expected/lscpu/lscpu-vmware_fpe | 2 +- tests/expected/lscpu/lscpu-x86_64-64cpu | 2 +- tests/expected/lscpu/lscpu-x86_64-dell_e4310 | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/expected/lscpu/lscpu-armv7 b/tests/expected/lscpu/lscpu-armv7 index 7f1c726c1..27deb8099 100644 --- a/tests/expected/lscpu/lscpu-armv7 +++ b/tests/expected/lscpu/lscpu-armv7 @@ -7,6 +7,7 @@ Thread(s) per core: 1 Core(s) per socket: 2 Socket(s): 1 Stepping: r0p4 +CPU(s) scaling MHz: 12% CPU max MHz: 1700.0000 CPU min MHz: 200.0000 BogoMIPS: 1694.10 diff --git a/tests/expected/lscpu/lscpu-vmware_fpe b/tests/expected/lscpu/lscpu-vmware_fpe index 469ad3884..80a51b1ae 100644 --- a/tests/expected/lscpu/lscpu-vmware_fpe +++ b/tests/expected/lscpu/lscpu-vmware_fpe @@ -11,7 +11,7 @@ Core(s) per socket: 4 Socket(s): 2 Stepping: 0 Frequency boost: enabled -CPU(s) scaling MHz: 48% +CPU(s) scaling MHz: 52% CPU max MHz: 3200.0000 CPU min MHz: 1400.0000 BogoMIPS: 6399.69 diff --git a/tests/expected/lscpu/lscpu-x86_64-64cpu b/tests/expected/lscpu/lscpu-x86_64-64cpu index 4e35abba1..b5b6c85c3 100644 --- a/tests/expected/lscpu/lscpu-x86_64-64cpu +++ b/tests/expected/lscpu/lscpu-x86_64-64cpu @@ -10,7 +10,7 @@ Thread(s) per core: 2 Core(s) per socket: 8 Socket(s): 4 Stepping: 6 -CPU(s) scaling MHz: 53% +CPU(s) scaling MHz: 54% CPU max MHz: 1996.0000 CPU min MHz: 1064.0000 BogoMIPS: 3990.31 diff --git a/tests/expected/lscpu/lscpu-x86_64-dell_e4310 b/tests/expected/lscpu/lscpu-x86_64-dell_e4310 index 1847d5bb1..f7f0291c9 100644 --- a/tests/expected/lscpu/lscpu-x86_64-dell_e4310 +++ b/tests/expected/lscpu/lscpu-x86_64-dell_e4310 @@ -10,7 +10,7 @@ Thread(s) per core: 2 Core(s) per socket: 2 Socket(s): 1 Stepping: 5 -CPU(s) scaling MHz: 45% +CPU(s) scaling MHz: 59% CPU max MHz: 2667.0000 CPU min MHz: 1199.0000 BogoMIPS: 5319.92 From 05cbd5aeedfed9521f6797ff4be1676ab0fae1aa Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 25 May 2021 13:45:24 +0200 Subject: [PATCH 24/26] docs: update TODO Signed-off-by: Karel Zak --- Documentation/TODO | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/TODO b/Documentation/TODO index e382e4b97..30939defa 100644 --- a/Documentation/TODO +++ b/Documentation/TODO @@ -53,7 +53,11 @@ cal lscpu ----- + - add "Boost/Turbo: true|false" based on /sys/devices/system/cpu/intel_pstate/no_turbo and + /sys/devices/system/cpu/cpufreq/boost + - add --freq output to visualise CPU use, see https://github.com/karelzak/util-linux/issues/1314 + - read cpuid and uname information from file if --sysroot is specified, then we can prepare regression tests completely independent on hw and architecture. From 647f80e491ab7a7abc3891e6889c70017246e884 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 26 May 2021 13:12:31 +0200 Subject: [PATCH 25/26] meson: add missing header files check Fixes: https://github.com/karelzak/util-linux/issues/1318 Signed-off-by: Karel Zak --- configure.ac | 3 +-- meson.build | 7 +++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 720e7d0d6..53acda000 100644 --- a/configure.ac +++ b/configure.ac @@ -301,6 +301,7 @@ AC_CHECK_HEADERS([ \ inttypes.h \ lastlog.h \ libutil.h \ + linux/blkzoned.h \ linux/btrfs.h \ linux/capability.h \ linux/cdrom.h \ @@ -382,8 +383,6 @@ AC_CHECK_HEADERS([security/pam_misc.h], #endif ]) -AC_CHECK_HEADERS([linux/blkzoned.h]) - AC_CHECK_DECLS([BLK_ZONE_REP_CAPACITY], [], [], [ #include ]) diff --git a/meson.build b/meson.build index c53fd36eb..e0667b66f 100644 --- a/meson.build +++ b/meson.build @@ -4,8 +4,8 @@ project('util-linux', 'c', pkgconfig = import('pkgconfig') -libblkid_version = '1.1.0' libblkid_date = '11-Dec-2019' +libblkid_version = '1.1.0' libuuid_version = '1.3.0' libmount_version = '1.1.0' libsmartcols_version = '1.1.0' @@ -156,8 +156,10 @@ headers = ''' linux/compiler.h linux/falloc.h linux/fd.h - linux/fs.h + linux/fiemap.h + linux/gsmmux.h linux/net_namespace.h + linux/nsfs.h linux/raw.h linux/securebits.h linux/tiocl.h @@ -195,6 +197,7 @@ headers = ''' sys/types.h sys/ucred.h sys/un.h + sys/xattr.h '''.split() lib_m = cc.find_library('m') From 684f921ec2afd9ae4706e281e3a58b61cc16c23b Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 26 May 2021 13:20:21 +0200 Subject: [PATCH 26/26] build-sys: add script to compare config.h from meson and autotools Signed-off-by: Karel Zak --- tools/compare-buildsys.sh | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100755 tools/compare-buildsys.sh diff --git a/tools/compare-buildsys.sh b/tools/compare-buildsys.sh new file mode 100755 index 000000000..e88cbd58f --- /dev/null +++ b/tools/compare-buildsys.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +FILTER="$1" + +MESON_CONFIG_H="build/config.h" +AUTOCONF_CONFIG_H="./config.h" + +if [ ! -f $MESON_CONFIG_H ]; then + echo 'Meson is not ready in the build/ directory (try "meson build")' + exit 1 +fi + +if [ ! -f $AUTOCONF_CONFIG_H ]; then + echo 'Autotools are not ready (try "./autogen.sh; ./configure")' + exit 1 +fi + +TMPFILE_MESON="/tmp/util-linux-meson" +TMPFILE_AUTOCONF="/tmp/util-linux-autoconf" + +GREP_PATTERN="#define " + +if [ "$FILTER" = "headers" ]; then + GREP_PATTERN="#define .*_H[[:blank:]]" +fi + +echo "===MESON===" > $TMPFILE_MESON +grep "$GREP_PATTERN" $MESON_CONFIG_H | sort >> $TMPFILE_MESON + +echo "===AUTOCONF===" > $TMPFILE_AUTOCONF +grep "$GREP_PATTERN" $AUTOCONF_CONFIG_H | sort >> $TMPFILE_AUTOCONF + +diff --side-by-side $TMPFILE_AUTOCONF $TMPFILE_MESON + +rm -rf $TMPFILE_MESON $TMPFILE_AUTOCONF