From patchwork Wed Apr 24 19:07:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 162811 Delivered-To: patch@linaro.org Received: by 2002:a02:c6d8:0:0:0:0:0 with SMTP id r24csp1037395jan; Wed, 24 Apr 2019 12:20:46 -0700 (PDT) X-Google-Smtp-Source: APXvYqxpfBcKve9/YsZk3K+jN5tJlE18To5hTN14aLKI4GBPOqCOI0gA5PYhIBH5CjGxxKkKB37e X-Received: by 2002:adf:f8d0:: with SMTP id f16mr22745702wrq.198.1556133646835; Wed, 24 Apr 2019 12:20:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1556133646; cv=none; d=google.com; s=arc-20160816; b=yT9nQrk1UgMq9kaEcMPKAJ6J49B8rz8qKGjDuyLbplC097NVmQU5qV8JWVXN4zYa3J 1w/IjOpy1G19nZCcA3CAvaahwTXmBzs3QMFG1X40S/SmvPDydk1alGmD1EDzPTYQll9c G5LDAjITEnkEJyYRcff6bpKRphqtfInglX1welE+mjrRjfHc1q/8J5GjouKUdiUpxU3j QPxt7Mtg9YBJRPdM3nsyrmcwnWEXBqMomGVpA8QdVfO7+bUHi4sNX4ztyxH3a+hLlFoj GRtPkBgD/+7bwSgV2pSu6uFHhngpNrIRUqLT1BlS/e1Fo56S6QBqVZxZE486MWObzQVk bB1w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:to:from:dkim-signature; bh=F6v6DXx3p/jSQwESHeV1J+7APHSrqQWGEt14uQc8gHo=; b=YRgccDK+RTQG1OvD5zwU6nOijyyZTanvjIZVN6fYBI9WfUPaxvupoFlJTFdI6IkKWx 2GzhMCU3lv1zN6iG22ERAqEIr/PTHeuAVP8i99PIZJhgcXml4JSLWJy5SrDURVx+FrN3 LWmhCd8jK0Gkm77lzhKdaDAtDl4Z4ceNiD1j/zwMjUPh/8FdYh8/pAVhUudBg1aVmyt1 aAYQxo+zC6YDeRJ9K8BkMT5rnU9ILxVxz9cDDVZP+Ir96OY/ZiXjsSQsFrdUglzQI9QY vspgVYCyIT1ddBvrQtwKI8ls4ySXQ2Yys4g/PCxIGkNfKsagTdbJde033dvKJ+zM9VGm ACOQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=MUArAqtA; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id b74si13873466wmd.104.2019.04.24.12.20.46 for (version=TLS1 cipher=AES128-SHA bits=128/128); Wed, 24 Apr 2019 12:20:46 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=MUArAqtA; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1]:46107 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hJNRl-0004jd-NC for patch@linaro.org; Wed, 24 Apr 2019 15:20:45 -0400 Received: from eggs.gnu.org ([209.51.188.92]:48794) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hJNEe-0001jV-Ho for qemu-devel@nongnu.org; Wed, 24 Apr 2019 15:07:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hJNEc-0001kE-RN for qemu-devel@nongnu.org; Wed, 24 Apr 2019 15:07:12 -0400 Received: from mail-pg1-x542.google.com ([2607:f8b0:4864:20::542]:46242) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hJNEc-0001im-KI for qemu-devel@nongnu.org; Wed, 24 Apr 2019 15:07:10 -0400 Received: by mail-pg1-x542.google.com with SMTP id n2so707132pgg.13 for ; Wed, 24 Apr 2019 12:07:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=F6v6DXx3p/jSQwESHeV1J+7APHSrqQWGEt14uQc8gHo=; b=MUArAqtATCpj1CphSYsiSR9lJz9gDkgu6nfUYh1vwSJKwQly4LdxBGEjzqTBU9Zwgp h9/RJFpB6ouaVfxY/lQRLnMr42bbWhQt34nLGy2lAyOuMxO4ay0/h8gjyJigL8jKnAvc 0NrHKpFkxxJtk7qsSB0y7jhJDp7sKGwtqZvtV/giAx8mvueWDzvEa91JonrdDFa7zaaV 1Ppb1NyDG+0QkdMzfQbzeHaM5v76FN4kcPwCPeMFIAQziOBfLm53F9bZ3Zch2OYklYjF Q2lg2ljjxk0PSCd96yPIdEsyKKdsj7aKHXv3UUFLaf87MDiVpAsZgyx0y4JCk/+5QJms xASg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=F6v6DXx3p/jSQwESHeV1J+7APHSrqQWGEt14uQc8gHo=; b=FKqNdssA4zap380wcep06f6/yzIiUPaXYo/+S/ufF1cvT53SV1ITuOOAJc3Ft2zhxx TptY8Gb4AriVh9hyk0/MVx/rVHSpCF+bKamHiCusrzN+J4UkcsTJBLvQvjV4QuJ6WIek /gG5pOc+z3I0dmJ77wqDO2jMjCw/PZCXs6JtSxIElIefk8v4haft8r3D9zgJbJA6tcmv ZmgEgRVjdFjM2vESTLK30z8/HI2X5X+9CyEFX5oVr2oD+DbwnvfJaUHQtRf/ypSzKzmt MFOTH3CjGDKkwOSyKxkHFwAlv0Ruj8ybMEEv6Nq4SCsxCfAWKgjxtQiS7KC3d07ulBsF yjJQ== X-Gm-Message-State: APjAAAW8wY9MQD+C5x/2x2KMeXNB+4IbqUs/+R3bqIl8ys3DRb43io1v q0qKQ6nJLfG1nZ2St7KFWU7Y4ntNznI= X-Received: by 2002:a65:648f:: with SMTP id e15mr32536614pgv.414.1556132829196; Wed, 24 Apr 2019 12:07:09 -0700 (PDT) Received: from localhost.localdomain (97-113-179-147.tukw.qwest.net. [97.113.179.147]) by smtp.gmail.com with ESMTPSA id 8sm30761011pfs.50.2019.04.24.12.07.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 24 Apr 2019 12:07:08 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Date: Wed, 24 Apr 2019 12:07:05 -0700 Message-Id: <20190424190705.12392-2-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190424190705.12392-1-richard.henderson@linaro.org> References: <20190424190705.12392-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::542 Subject: [Qemu-devel] [PATCH v2 1/1] util/path: Do not cache all filenames at startup X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: philmd@redhat.com, laurent@vivier.eu Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" 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 --- util/path.c | 201 ++++++++++++---------------------------------------- 1 file changed, 47 insertions(+), 154 deletions(-) -- 2.17.1 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 #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; }