All of lore.kernel.org
 help / color / mirror / Atom feed
From: Laurent Vivier <laurent@vivier.eu>
To: Richard Henderson <richard.henderson@linaro.org>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH 01/13] util/path: Do not cache all filenames at startup
Date: Thu, 13 Jun 2019 15:40:16 +0200	[thread overview]
Message-ID: <c307ce5c-1eb4-d26b-d9a6-6579b7d6bcf0@vivier.eu> (raw)
In-Reply-To: <20190519201953.20161-2-richard.henderson@linaro.org>

Le 19/05/2019 à 22:19, Richard Henderson a écrit :
> If one uses -L $PATH to point to a full chroot, the startup time
> is significant.  In addition, the existing probing algorithm fails
> to handle symlink loops.
> 
> Instead, probe individual paths on demand.  Cache both positive
> and negative results within $PATH, so that any one filename is
> probed only once.
> 
> Use glib filename functions for clarity.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  util/path.c | 201 ++++++++++++----------------------------------------
>  1 file changed, 47 insertions(+), 154 deletions(-)
> 
> diff --git a/util/path.c b/util/path.c
> index 7f9fc272fb..8e174eb436 100644
> --- a/util/path.c
> +++ b/util/path.c
> @@ -8,170 +8,63 @@
>  #include <dirent.h>
>  #include "qemu/cutils.h"
>  #include "qemu/path.h"
> +#include "qemu/thread.h"
>  
> -struct pathelem
> -{
> -    /* Name of this, eg. lib */
> -    char *name;
> -    /* Full path name, eg. /usr/gnemul/x86-linux/lib. */
> -    char *pathname;
> -    struct pathelem *parent;
> -    /* Children */
> -    unsigned int num_entries;
> -    struct pathelem *entries[0];
> -};
> -
> -static struct pathelem *base;
> -
> -/* First N chars of S1 match S2, and S2 is N chars long. */
> -static int strneq(const char *s1, unsigned int n, const char *s2)
> -{
> -    unsigned int i;
> -
> -    for (i = 0; i < n; i++)
> -        if (s1[i] != s2[i])
> -            return 0;
> -    return s2[i] == 0;
> -}
> -
> -static struct pathelem *add_entry(struct pathelem *root, const char *name,
> -                                  unsigned type);
> -
> -static struct pathelem *new_entry(const char *root,
> -                                  struct pathelem *parent,
> -                                  const char *name)
> -{
> -    struct pathelem *new = g_malloc(sizeof(*new));
> -    new->name = g_strdup(name);
> -    new->pathname = g_strdup_printf("%s/%s", root, name);
> -    new->num_entries = 0;
> -    return new;
> -}
> -
> -#define streq(a,b) (strcmp((a), (b)) == 0)
> -
> -/* Not all systems provide this feature */
> -#if defined(DT_DIR) && defined(DT_UNKNOWN) && defined(DT_LNK)
> -# define dirent_type(dirent) ((dirent)->d_type)
> -# define is_dir_maybe(type) \
> -    ((type) == DT_DIR || (type) == DT_UNKNOWN || (type) == DT_LNK)
> -#else
> -# define dirent_type(dirent) (1)
> -# define is_dir_maybe(type)  (type)
> -#endif
> -
> -static struct pathelem *add_dir_maybe(struct pathelem *path)
> -{
> -    DIR *dir;
> -
> -    if ((dir = opendir(path->pathname)) != NULL) {
> -        struct dirent *dirent;
> -
> -        while ((dirent = readdir(dir)) != NULL) {
> -            if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
> -                path = add_entry(path, dirent->d_name, dirent_type(dirent));
> -            }
> -        }
> -        closedir(dir);
> -    }
> -    return path;
> -}
> -
> -static struct pathelem *add_entry(struct pathelem *root, const char *name,
> -                                  unsigned type)
> -{
> -    struct pathelem **e;
> -
> -    root->num_entries++;
> -
> -    root = g_realloc(root, sizeof(*root)
> -                   + sizeof(root->entries[0])*root->num_entries);
> -    e = &root->entries[root->num_entries-1];
> -
> -    *e = new_entry(root->pathname, root, name);
> -    if (is_dir_maybe(type)) {
> -        *e = add_dir_maybe(*e);
> -    }
> -
> -    return root;
> -}
> -
> -/* This needs to be done after tree is stabilized (ie. no more reallocs!). */
> -static void set_parents(struct pathelem *child, struct pathelem *parent)
> -{
> -    unsigned int i;
> -
> -    child->parent = parent;
> -    for (i = 0; i < child->num_entries; i++)
> -        set_parents(child->entries[i], child);
> -}
> -
> -/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
> -static const char *
> -follow_path(const struct pathelem *cursor, const char *name)
> -{
> -    unsigned int i, namelen;
> -
> -    name += strspn(name, "/");
> -    namelen = strcspn(name, "/");
> -
> -    if (namelen == 0)
> -        return cursor->pathname;
> -
> -    if (strneq(name, namelen, ".."))
> -        return follow_path(cursor->parent, name + namelen);
> -
> -    if (strneq(name, namelen, "."))
> -        return follow_path(cursor, name + namelen);
> -
> -    for (i = 0; i < cursor->num_entries; i++)
> -        if (strneq(name, namelen, cursor->entries[i]->name))
> -            return follow_path(cursor->entries[i], name + namelen);
> -
> -    /* Not found */
> -    return NULL;
> -}
> +static const char *base;
> +static GHashTable *hash;
> +static QemuMutex lock;
>  
>  void init_paths(const char *prefix)
>  {
> -    char pref_buf[PATH_MAX];
> -
> -    if (prefix[0] == '\0' ||
> -        !strcmp(prefix, "/"))
> +    if (prefix[0] == '\0' || !strcmp(prefix, "/")) {
>          return;
> -
> -    if (prefix[0] != '/') {
> -        char *cwd = getcwd(NULL, 0);
> -        size_t pref_buf_len = sizeof(pref_buf);
> -
> -        if (!cwd)
> -            abort();
> -        pstrcpy(pref_buf, sizeof(pref_buf), cwd);
> -        pstrcat(pref_buf, pref_buf_len, "/");
> -        pstrcat(pref_buf, pref_buf_len, prefix);
> -        free(cwd);
> -    } else
> -        pstrcpy(pref_buf, sizeof(pref_buf), prefix + 1);
> -
> -    base = new_entry("", NULL, pref_buf);
> -    base = add_dir_maybe(base);
> -    if (base->num_entries == 0) {
> -        g_free(base->pathname);
> -        g_free(base->name);
> -        g_free(base);
> -        base = NULL;
> -    } else {
> -        set_parents(base, base);
>      }
> +
> +    if (prefix[0] == '/') {
> +        base = g_strdup(prefix);
> +    } else {
> +        char *cwd = g_get_current_dir();
> +        base = g_build_filename(cwd, prefix, NULL);
> +        g_free(cwd);
> +    }
> +
> +    hash = g_hash_table_new(g_str_hash, g_str_equal);
> +    qemu_mutex_init(&lock);
>  }
>  
>  /* Look for path in emulation dir, otherwise return name. */
>  const char *path(const char *name)
>  {
> -    /* Only do absolute paths: quick and dirty, but should mostly be OK.
> -       Could do relative by tracking cwd. */
> -    if (!base || !name || name[0] != '/')
> -        return name;
> +    gpointer key, value;
> +    const char *ret;
>  
> -    return follow_path(base, name) ?: name;
> +    /* Only do absolute paths: quick and dirty, but should mostly be OK.  */
> +    if (!base || !name || name[0] != '/') {
> +        return name;
> +    }
> +
> +    qemu_mutex_lock(&lock);
> +
> +    /* Have we looked up this file before?  */
> +    if (g_hash_table_lookup_extended(hash, name, &key, &value)) {
> +        ret = value ? value : name;
> +    } else {
> +        char *save = g_strdup(name);
> +        char *full = g_build_filename(base, name, NULL);
> +
> +        /* Look for the path; record the result, pass or fail.  */
> +        if (access(full, F_OK) == 0) {
> +            /* Exists.  */
> +            g_hash_table_insert(hash, save, full);
> +            ret = full;
> +        } else {
> +            /* Does not exist.  */
> +            g_free(full);
> +            g_hash_table_insert(hash, save, NULL);
> +            ret = name;
> +        }
> +    }
> +
> +    qemu_mutex_unlock(&lock);
> +    return ret;
>  }
> 

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Tested-by: Laurent Vivier <laurent@vivier.eu>

Thanks,
Laurent


  reply	other threads:[~2019-06-13 15:19 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-19 20:19 [Qemu-devel] [PATCH 00/13] linux-user: path, clone, sparc, shmat fixes Richard Henderson
2019-05-19 20:19 ` [Qemu-devel] [PATCH 01/13] util/path: Do not cache all filenames at startup Richard Henderson
2019-06-13 13:40   ` Laurent Vivier [this message]
2019-05-19 20:19 ` [Qemu-devel] [PATCH 02/13] linux-user: Rename cpu_clone_regs to cpu_clone_regs_child Richard Henderson
2019-06-13 16:25   ` Laurent Vivier
2019-05-19 20:19 ` [Qemu-devel] [PATCH 03/13] linux-user: Introduce cpu_clone_regs_parent Richard Henderson
2019-06-13 16:26   ` Laurent Vivier
2019-06-13 19:10   ` Aleksandar Markovic
2019-05-19 20:19 ` [Qemu-devel] [PATCH 04/13] linux-user/alpha: Set r20 secondary return value Richard Henderson
2019-06-13 16:23   ` Laurent Vivier
2019-05-19 20:19 ` [Qemu-devel] [PATCH 05/13] target/sparc: Define an enumeration for accessing env->regwptr Richard Henderson
2019-05-19 20:19 ` [Qemu-devel] [PATCH 06/13] linux-user/sparc: Use WREG constants in sparc/target_cpu.h Richard Henderson
2019-05-19 20:19 ` [Qemu-devel] [PATCH 07/13] linux-user/sparc: Use WREG constants in sparc/signal.c Richard Henderson
2019-06-13 21:31   ` Laurent Vivier
2019-05-19 20:19 ` [Qemu-devel] [PATCH 08/13] linux-user/sparc: Fix cpu_clone_regs Richard Henderson
2019-05-19 20:19 ` [Qemu-devel] [PATCH 09/13] linux-user/sparc: Flush register windows before clone/fork/vfork Richard Henderson
2019-05-19 20:19 ` [Qemu-devel] [PATCH 10/13] scripts/qemu-binfmt-conf: Update for sparc64 Richard Henderson
2019-06-13 15:22   ` Laurent Vivier
2019-05-19 20:19 ` [Qemu-devel] [PATCH 11/13] tests/tcg/multiarch/linux-test: Fix error check for shmat Richard Henderson
2019-06-13 15:08   ` Laurent Vivier
2019-05-19 20:19 ` [Qemu-devel] [PATCH 12/13] linux-user: Fix shmat emulation by honoring host SHMLBA Richard Henderson
2019-05-22  9:40   ` Laurent Vivier
2019-05-19 20:19 ` [Qemu-devel] [PATCH 13/13] linux-user: Align mmap_find_vma to host page size Richard Henderson
2019-05-22  9:45   ` Laurent Vivier
2019-06-11 20:53 ` [Qemu-devel] [PATCH 00/13] linux-user: path, clone, sparc, shmat fixes Richard Henderson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c307ce5c-1eb4-d26b-d9a6-6579b7d6bcf0@vivier.eu \
    --to=laurent@vivier.eu \
    --cc=qemu-devel@nongnu.org \
    --cc=richard.henderson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.