Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d8c8e4c authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Arnaldo Carvalho de Melo
Browse files

perf buildid-cache: Add --purge FILE to remove all caches of FILE



Add --purge FILE to remove all caches of FILE.

Since the current --remove FILE removes a cache which has
same build-id of given FILE. Since the command takes a
FILE path, it can confuse user who tries to remove cache
about FILE path.

  -----
  # ./perf buildid-cache -v --add ./perf
  Adding 133b7b5486d987a5ab5c3ebf4ea14941f45d4d4f ./perf: Ok
  # (update the ./perf binary)
  # ./perf buildid-cache -v --remove ./perf
  Removing 305bbd1be68f66eca7e2d78db294653031edfa79 ./perf: FAIL
  ./perf wasn't in the cache
  -----
Actually, the --remove's FAIL is not shown, it just silently fails.

So, this patch adds --purge FILE action for such usecase.

perf buildid-cache --purge FILE removes all caches which has same FILE
path.

In other words, it removes all caches including old binaries.

  -----
  # ./perf buildid-cache -v --add ./perf
  Adding 133b7b5486d987a5ab5c3ebf4ea14941f45d4d4f ./perf: Ok
  # (update the ./perf binary)
  # ./perf buildid-cache -v --purge ./perf
  Removing 133b7b5486d987a5ab5c3ebf4ea14941f45d4d4f ./perf: Ok
  -----

BTW, if you want to purge all the caches, remove ~/.debug/* .

Signed-off-by: default avatarMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20150227045026.1999.64084.stgit@localhost.localdomain


[ s/dirname/dir_name/g to fix build on fedora14, where dirname is a global ]
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 7335399a
Loading
Loading
Loading
Loading
+9 −4
Original line number Diff line number Diff line
@@ -12,9 +12,9 @@ SYNOPSIS

DESCRIPTION
-----------
This command manages the build-id cache. It can add and remove files to/from
the cache. In the future it should as well purge older entries, set upper
limits for the space used by the cache, etc.
This command manages the build-id cache. It can add, remove, update and purge
files to/from the cache. In the future it should as well set upper limits for
the space used by the cache, etc.

OPTIONS
-------
@@ -36,7 +36,12 @@ OPTIONS
        actually made.
-r::
--remove=::
        Remove specified file from the cache.
        Remove a cached binary which has same build-id of specified file
        from the cache.
-p::
--purge=::
        Purge all cached binaries including older caches which have specified
	path from the cache.
-M::
--missing=::
	List missing build ids in the cache for the specified file.
+48 −0
Original line number Diff line number Diff line
@@ -223,6 +223,33 @@ static int build_id_cache__remove_file(const char *filename)
	return err;
}

static int build_id_cache__purge_path(const char *pathname)
{
	struct strlist *list;
	struct str_node *pos;
	int err;

	err = build_id_cache__list_build_ids(pathname, &list);
	if (err)
		goto out;

	strlist__for_each(pos, list) {
		err = build_id_cache__remove_s(pos->s);
		if (verbose)
			pr_info("Removing %s %s: %s\n", pos->s, pathname,
				err ? "FAIL" : "Ok");
		if (err)
			break;
	}
	strlist__delete(list);

out:
	if (verbose)
		pr_info("Purging %s: %s\n", pathname, err ? "FAIL" : "Ok");

	return err;
}

static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
{
	char filename[PATH_MAX];
@@ -285,6 +312,7 @@ int cmd_buildid_cache(int argc, const char **argv,
	bool force = false;
	char const *add_name_list_str = NULL,
		   *remove_name_list_str = NULL,
		   *purge_name_list_str = NULL,
		   *missing_filename = NULL,
		   *update_name_list_str = NULL,
		   *kcore_filename = NULL;
@@ -302,6 +330,8 @@ int cmd_buildid_cache(int argc, const char **argv,
		   "file", "kcore file to add"),
	OPT_STRING('r', "remove", &remove_name_list_str, "file list",
		    "file(s) to remove"),
	OPT_STRING('p', "purge", &purge_name_list_str, "path list",
		    "path(s) to remove (remove old caches too)"),
	OPT_STRING('M', "missing", &missing_filename, "file",
		   "to find missing build ids in the cache"),
	OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
@@ -368,6 +398,24 @@ int cmd_buildid_cache(int argc, const char **argv,
		}
	}

	if (purge_name_list_str) {
		list = strlist__new(true, purge_name_list_str);
		if (list) {
			strlist__for_each(pos, list)
				if (build_id_cache__purge_path(pos->s)) {
					if (errno == ENOENT) {
						pr_debug("%s wasn't in the cache\n",
							 pos->s);
						continue;
					}
					pr_warning("Couldn't remove %s: %s\n",
						   pos->s, strerror_r(errno, sbuf, sizeof(sbuf)));
				}

			strlist__delete(list);
		}
	}

	if (missing_filename)
		ret = build_id_cache__fprintf_missing(session, stdout);

+76 −17
Original line number Diff line number Diff line
@@ -281,35 +281,93 @@ void disable_buildid_cache(void)
	no_buildid_cache = true;
}

static char *build_id_cache__dirname_from_path(const char *name,
					       bool is_kallsyms, bool is_vdso)
{
	char *realname = (char *)name, *filename;
	bool slash = is_kallsyms || is_vdso;

	if (!slash) {
		realname = realpath(name, NULL);
		if (!realname)
			return NULL;
	}

	if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "",
		     is_vdso ? DSO__NAME_VDSO : realname) < 0)
		filename = NULL;

	if (!slash)
		free(realname);

	return filename;
}

int build_id_cache__list_build_ids(const char *pathname,
				   struct strlist **result)
{
	struct strlist *list;
	char *dir_name;
	DIR *dir;
	struct dirent *d;
	int ret = 0;

	list = strlist__new(true, NULL);
	dir_name = build_id_cache__dirname_from_path(pathname, false, false);
	if (!list || !dir_name) {
		ret = -ENOMEM;
		goto out;
	}

	/* List up all dirents */
	dir = opendir(dir_name);
	if (!dir) {
		ret = -errno;
		goto out;
	}

	while ((d = readdir(dir)) != NULL) {
		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
			continue;
		strlist__add(list, d->d_name);
	}
	closedir(dir);

out:
	free(dir_name);
	if (ret)
		strlist__delete(list);
	else
		*result = list;

	return ret;
}

int build_id_cache__add_s(const char *sbuild_id, const char *name,
			  bool is_kallsyms, bool is_vdso)
{
	const size_t size = PATH_MAX;
	char *realname, *filename = zalloc(size),
	char *realname = NULL, *filename = NULL, *dir_name = NULL,
	     *linkname = zalloc(size), *targetname, *tmp;
	int len, err = -1;
	bool slash = is_kallsyms || is_vdso;
	int err = -1;

	if (is_kallsyms) {
		if (symbol_conf.kptr_restrict) {
			pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
			err = 0;
	if (!is_kallsyms) {
		realname = realpath(name, NULL);
		if (!realname)
			goto out_free;
	}
		realname = (char *) name;
	} else
		realname = realpath(name, NULL);

	if (realname == NULL || filename == NULL || linkname == NULL)
	dir_name = build_id_cache__dirname_from_path(name, is_kallsyms, is_vdso);
	if (!dir_name)
		goto out_free;

	len = scnprintf(filename, size, "%s%s%s",
		       buildid_dir, slash ? "/" : "",
		       is_vdso ? DSO__NAME_VDSO : realname);
	if (mkdir_p(filename, 0755))
	if (mkdir_p(dir_name, 0755))
		goto out_free;

	snprintf(filename + len, size - len, "/%s", sbuild_id);
	if (asprintf(&filename, "%s/%s", dir_name, sbuild_id) < 0) {
		filename = NULL;
		goto out_free;
	}

	if (access(filename, F_OK)) {
		if (is_kallsyms) {
@@ -337,6 +395,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
	if (!is_kallsyms)
		free(realname);
	free(filename);
	free(dir_name);
	free(linkname);
	return err;
}
+3 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
#define BUILD_ID_SIZE 20

#include "tool.h"
#include "strlist.h"
#include <linux/types.h>

extern struct perf_tool build_id__mark_dso_hit_ops;
@@ -22,6 +23,8 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);
int perf_session__write_buildid_table(struct perf_session *session, int fd);
int perf_session__cache_build_ids(struct perf_session *session);

int build_id_cache__list_build_ids(const char *pathname,
				   struct strlist **result);
bool build_id_cache__cached(const char *sbuild_id);
int build_id_cache__add_s(const char *sbuild_id,
			  const char *name, bool is_kallsyms, bool is_vdso);