From patchwork Sun May 19 20:19:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 164479 Delivered-To: patch@linaro.org Received: by 2002:a92:9e1a:0:0:0:0:0 with SMTP id q26csp4768647ili; Sun, 19 May 2019 13:23:00 -0700 (PDT) X-Google-Smtp-Source: APXvYqzafgckhGEFrJB+XTQJMbWkGBEYyXkOoFlBRXWbCN/XbBgfqmZwDfqTq8mBxoOPZ4/OjBbZ X-Received: by 2002:a50:9785:: with SMTP id e5mr70707296edb.94.1558297380658; Sun, 19 May 2019 13:23:00 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1558297380; cv=none; d=google.com; s=arc-20160816; b=pIm3cXPTvCgXw154rth9GNcD3Yb5IyW25wthlptENwXWINS2th5TF22b7dkUD663UE Z00rhTrrXlazALcZrHYlsbAuANX0zb0u1u1pxb4FvMlqIjppR98SPxkHe3DEn5Vxw9Oj 2+C3SS4EGK8WLDuYy9D/djgtddGcXSgBYQW6Ce5ZMgMXWpyrrTesC+zpAf4im+6PW5Nr UCsIFpfmwizpsscSLZaUA3b2tYl3xEZRXX6VSP1orHwwQftYQ5kUX1sx9zCmMgbJsFYF Px4rT1a6dTmWz6m4suwWFuv/rcEVCA0Xrzizxh0XUp0MOi1uCMs9M37t8YpHn3CdaYAW MrDw== 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=Sg9dOluYZNIkG+DTvwSoOLgmBynr9NEQ/o58vtsuFZHSswHyhpz1lGrwBjaeSs9AmE L/Y/72Ormcp4JhqWsD4Drq6d2N48naEVlqIQtBpgPJYGxLIjlKD3g/MDWP2u3Qne/m4o ESd+2WPo7tQFfb6EG2kVkq2TN0VimA99m3JSvvSvEyprgjhjiPn3iftfTcd6lq7ulc0D gogtw4sID08f7eYuSoAaq7qjReJix3QYNtbEJ1RbLqF5jgoVhdx366jTHDqSo9KU098A 6oTqvJKXtHR0Ww2ep/KBZD8I0RBmYlF7YQKZJlf7VlTnaG26U5mbM1cf+HECoJFXgEn3 ApNA== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=LNoyolei; 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 dv25si279722ejb.383.2019.05.19.13.23.00 for (version=TLS1 cipher=AES128-SHA bits=128/128); Sun, 19 May 2019 13:23:00 -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=LNoyolei; 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]:52874 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hSSKh-0008Ba-FE for patch@linaro.org; Sun, 19 May 2019 16:22:59 -0400 Received: from eggs.gnu.org ([209.51.188.92]:46435) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hSSHo-0005PI-Ft for qemu-devel@nongnu.org; Sun, 19 May 2019 16:20:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hSSHn-0007I9-6z for qemu-devel@nongnu.org; Sun, 19 May 2019 16:20:00 -0400 Received: from mail-pf1-x443.google.com ([2607:f8b0:4864:20::443]:43788) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hSSHn-0007HV-0m for qemu-devel@nongnu.org; Sun, 19 May 2019 16:19:59 -0400 Received: by mail-pf1-x443.google.com with SMTP id c6so6140816pfa.10 for ; Sun, 19 May 2019 13:19:58 -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=LNoyoleiOmWy0+b5gqhq8DClyyS7FdElq0Iyolo/4h3pAWSQOECoXCfuj6RQ8Fd3yo RqZOpo3P9VyQKhkETAtVf/1MhSofklJRjqtm4ZdmyqVu86sf7VStdm+C1ldRqT7bFZZf McXkW0M/tQ8SHgNu487ySJUA1x40uJZRmYoCZHAO5u+B8cUFLUiHaIz+RA6uBNOmZed7 8TkwyIeZhaJNE/+/EzYjLru742oJAL43oEl3nv1zVvWaCgxhrLygcsqLi8/v6BJY5t0r z71BEx/7b1Pw08/dtu/WPt4pYR4Itu720vbE1moZINx9+7XAUQ74OpZfYyRhUF3aRTVM MXQA== 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=TXcytjB5kN1GHt5qUgwLMjo/8R7WKp7YoH2FDD7bnguMA8o76Y25uNrQ5Ek7QcdIQr cH0ok141Vz32ajLq7/ImV+yKQSkaqwC/tKnwxj8QQpJauSxyF5nbhfw71/jm6hKUS77M xyeu/rWmwBJ4XsA3YzyahcHpaUHNXVCDBkUsp0bBOsSzmkS9B+ISpgnshlBQZmECFLf2 wYe/AOOzm0/4gGVvhlnQ5Lt8pB87NzgGPxeW0LtYOWLfEteLJMeK0N2WXqze7EBopW8p w6V/XOMVDdFryF624e2JwhstkUFEVHu54jQQSNcx/8qETQjMCtPqVlx3qm58M4rX20gZ 0Jhg== X-Gm-Message-State: APjAAAVJqzL5DnY3xO/hneECmiLMin24s9lHKQ1H3ewQfGCuaekYPL4w dXyRao1T5WO7Lj/LoyAsm/MTVOuCuiM= X-Received: by 2002:a63:144e:: with SMTP id 14mr53861332pgu.304.1558297197610; Sun, 19 May 2019 13:19:57 -0700 (PDT) Received: from localhost.localdomain (97-113-13-231.tukw.qwest.net. [97.113.13.231]) by smtp.gmail.com with ESMTPSA id e14sm18166264pff.60.2019.05.19.13.19.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 19 May 2019 13:19:56 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Date: Sun, 19 May 2019 13:19:41 -0700 Message-Id: <20190519201953.20161-2-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190519201953.20161-1-richard.henderson@linaro.org> References: <20190519201953.20161-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::443 Subject: [Qemu-devel] [PATCH 01/13] 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: 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 Reviewed-by: Laurent Vivier Tested-by: Laurent Vivier 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; }