]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: Reuse the guessed root device
authorViktor Rosendahl (BMW) <viktor.rosendahl@gmail.com>
Mon, 24 Oct 2022 09:36:03 +0000 (11:36 +0200)
committerKarel Zak <kzak@redhat.com>
Wed, 26 Oct 2022 08:46:58 +0000 (10:46 +0200)
Inside a container, the file /proc/self/mountinfo may contain many lines
with /dev/root. It is also quite likely that /dev/root is not visible
inside the container. This may cause mnt_guess_system_root() to try to use
libblkid before giving up, through mnt_resolve_spec() and
mnt_resolve_tag(), which calls blkid_evaluate_tag(). The call to
blkid_evaluate_tag() may trigger a scan of all block devices, which is
expensive.

For this reason, it doesn't make any sense for kernel_fs_postparse()
to call mnt_guess_system_root() more than once for every call to
mnt_table_parse_stream. Instead, save the result from the first call and
reuse it for all subsequent calls to kernel_fs_postparse(), so that there
is at most one call to mnt_guess_system_root() for every call
to mnt_table_parse_stream().

[kzak@redhat.com: - use sysroot_ prefix for the cached variables
  - simplify code logic in kernel_fs_postparse()
  - add free() to parser_cleanup()]

Signed-off-by: Viktor Rosendahl (BMW) <viktor.rosendahl@gmail.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/src/tab_parse.c

index 294771dd4e49e5792566c614ae23fb8c81b3276d..75f8e406bb42ad4e1d5724096fec344ed4620ffe 100644 (file)
@@ -19,6 +19,8 @@
 #include <limits.h>
 #include <dirent.h>
 #include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/stat.h>
 
 #include "fileutils.h"
@@ -33,6 +35,8 @@ struct libmnt_parser {
        char    *buf;           /* buffer (the current line content) */
        size_t  bufsiz;         /* size of the buffer */
        size_t  line;           /* current line */
+       int     sysroot_rc;     /* rc from mnt_guess_system_root() */
+       char    *sysroot;       /* guess from mmnt_guess_system_root() */
 };
 
 static void parser_cleanup(struct libmnt_parser *pa)
@@ -40,6 +44,7 @@ static void parser_cleanup(struct libmnt_parser *pa)
        if (!pa)
                return;
        free(pa->buf);
+       free(pa->sysroot);
        memset(pa, 0, sizeof(*pa));
 }
 
@@ -652,9 +657,9 @@ done:
        return tid;
 }
 
-static int kernel_fs_postparse(struct libmnt_table *tb,
-                              struct libmnt_fs *fs, pid_t *tid,
-                              const char *filename)
+static int kernel_fs_postparse(struct libmnt_parser *pa,
+                              struct libmnt_table *tb,
+                              struct libmnt_fs *fs, pid_t *tid)
 {
        int rc = 0;
        const char *src = mnt_fs_get_srcpath(fs);
@@ -662,8 +667,8 @@ static int kernel_fs_postparse(struct libmnt_table *tb,
        /* This is a filesystem description from /proc, so we're in some process
         * namespace. Let's remember the process PID.
         */
-       if (filename && *tid == -1)
-               *tid = path_to_tid(filename);
+       if (pa->filename && *tid == -1)
+               *tid = path_to_tid(pa->filename);
 
        fs->tid = *tid;
 
@@ -671,13 +676,28 @@ static int kernel_fs_postparse(struct libmnt_table *tb,
         * Convert obscure /dev/root to something more usable
         */
        if (src && strcmp(src, "/dev/root") == 0) {
-               char *real = NULL;
 
-               rc = mnt_guess_system_root(fs->devno, tb->cache, &real);
+               /* We will only call mnt_guess_system_root() if it has not
+                * been called before. Inside a container, mountinfo can contain
+                * many lines with /dev/root.
+                */
+               if (pa->sysroot_rc == 0 && pa->sysroot == NULL)
+                       pa->sysroot_rc = mnt_guess_system_root(fs->devno,
+                                               tb->cache, &pa->sysroot);
+
+               rc = pa->sysroot_rc;
                if (rc < 0)
                        return rc;
 
-               if (rc == 0 && real) {
+               /* This means that we already have run the mnt_guess_system_root()
+                * and that we want to reuse the result.
+                */
+               if (rc == 0 && pa->sysroot != NULL) {
+                       char *real = strdup(pa->sysroot);
+
+                       if (!real)
+                               return -ENOMEM;
+
                        DBG(TAB, ul_debugobj(tb, "canonical root FS: %s", real));
                        rc = __mnt_fs_set_source_ptr(fs, real);
 
@@ -748,7 +768,7 @@ int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filenam
                        fs->flags |= flags;
 
                        if (rc == 0 && tb->fmt == MNT_FMT_MOUNTINFO) {
-                               rc = kernel_fs_postparse(tb, fs, &tid, filename);
+                               rc = kernel_fs_postparse(&pa, tb, fs, &tid);
                                if (rc)
                                        mnt_table_remove_fs(tb, fs);
                        }