From: Karel Zak Date: Wed, 6 Oct 2021 11:36:42 +0000 (+0200) Subject: lsns: optimize mountinfo use X-Git-Tag: v2.38-rc1~144^2~57 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a7f70ce17a925f1085bfa4b292427f8741d7e2a2;p=thirdparty%2Futil-linux.git lsns: optimize mountinfo use Let's parse mountinfo only for unknown namespaces or when namespace Id is not accessible (unprivileged users). Signed-off-by: Karel Zak --- diff --git a/misc-utils/lsfd.c b/misc-utils/lsfd.c index 259640d94d..223d008aad 100644 --- a/misc-utils/lsfd.c +++ b/misc-utils/lsfd.c @@ -174,6 +174,9 @@ static const int default_threads_columns[] = { static int columns[ARRAY_SIZE(infos) * 2] = {-1}; static size_t ncolumns; +static ino_t *mnt_namespaces; +static size_t nspaces; + struct lsfd_control { struct libscols_table *tb; /* output */ struct list_head procs; /* list of all processes */ @@ -254,6 +257,31 @@ static struct libscols_column *add_column_by_id_cb(struct libscols_table *tb, in return cl; } +static int has_mnt_ns(ino_t id) +{ + size_t i; + + for (i = 0; i < nspaces; i++) { + if (mnt_namespaces[i] == id) + return 1; + } + return 0; +} + +static void add_mnt_ns(ino_t id) +{ + size_t nmax = 0; + + if (nspaces) + nmax = (nspaces + 16) / 16 * 16; + if (nmax <= nspaces + 1) { + nmax += 16; + mnt_namespaces = xrealloc(mnt_namespaces, + sizeof(ino_t) * nmax); + } + mnt_namespaces[nspaces++] = id; +} + static const struct file_class *stat2class(struct stat *sb) { assert(sb); @@ -417,6 +445,8 @@ static struct file *collect_file_symlink(struct path_cxt *pc, if (is_association(f, EXE)) proc->uid = sb.st_uid; + if (is_association(f, NS_MNT)) + proc->ns_mnt = sb.st_ino; else if (assoc >= 0) { /* file-descriptor based association */ @@ -621,6 +651,8 @@ static void finalize_nodevs(void) { for (int i = 0; i < NODEV_TABLE_SIZE; i++) list_free(&nodev_table.tables[i], struct nodev, nodevs, free_nodev); + + free(mnt_namespaces); } const char *get_nodev_filesystem(unsigned long minor) @@ -818,7 +850,6 @@ static void read_process(struct lsfd_control *ctl, struct path_cxt *pc, { char buf[BUFSIZ]; struct proc *proc; - FILE *mnt; if (procfs_process_init_path(pc, pid) != 0) return; @@ -835,14 +866,14 @@ static void read_process(struct lsfd_control *ctl, struct path_cxt *pc, collect_namespace_files(pc, proc); - /* TODO: parse mountinfo only when process uses not-yet-known - * mount namespace. Parse mountinfo for each process is - * extremly expensive. - */ - mnt = ul_path_fopen(pc, "r", "mountinfo"); - if (mnt) { - add_nodevs(mnt); - fclose(mnt); + if (proc->ns_mnt == 0 || !has_mnt_ns(proc->ns_mnt)) { + FILE *mnt = ul_path_fopen(pc, "r", "mountinfo"); + if (mnt) { + add_nodevs(mnt); + if (proc->ns_mnt) + add_mnt_ns(proc->ns_mnt); + fclose(mnt); + } } /* If kcmp is not available, diff --git a/misc-utils/lsfd.h b/misc-utils/lsfd.h index f9f8bb9097..368b5be28b 100644 --- a/misc-utils/lsfd.h +++ b/misc-utils/lsfd.h @@ -98,6 +98,7 @@ struct proc { struct proc * leader; char *command; uid_t uid; + ino_t ns_mnt; struct list_head procs; struct list_head files; };