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

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
...@@ -12,9 +12,9 @@ SYNOPSIS ...@@ -12,9 +12,9 @@ SYNOPSIS
DESCRIPTION DESCRIPTION
----------- -----------
This command manages the build-id cache. It can add and remove files to/from This command manages the build-id cache. It can add, remove, update and purge
the cache. In the future it should as well purge older entries, set upper files to/from the cache. In the future it should as well set upper limits for
limits for the space used by the cache, etc. the space used by the cache, etc.
OPTIONS OPTIONS
------- -------
...@@ -36,7 +36,12 @@ OPTIONS ...@@ -36,7 +36,12 @@ OPTIONS
actually made. actually made.
-r:: -r::
--remove=:: --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:: -M::
--missing=:: --missing=::
List missing build ids in the cache for the specified file. List missing build ids in the cache for the specified file.
......
...@@ -223,6 +223,33 @@ static int build_id_cache__remove_file(const char *filename) ...@@ -223,6 +223,33 @@ static int build_id_cache__remove_file(const char *filename)
return err; 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) static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
{ {
char filename[PATH_MAX]; char filename[PATH_MAX];
...@@ -285,6 +312,7 @@ int cmd_buildid_cache(int argc, const char **argv, ...@@ -285,6 +312,7 @@ int cmd_buildid_cache(int argc, const char **argv,
bool force = false; bool force = false;
char const *add_name_list_str = NULL, char const *add_name_list_str = NULL,
*remove_name_list_str = NULL, *remove_name_list_str = NULL,
*purge_name_list_str = NULL,
*missing_filename = NULL, *missing_filename = NULL,
*update_name_list_str = NULL, *update_name_list_str = NULL,
*kcore_filename = NULL; *kcore_filename = NULL;
...@@ -302,6 +330,8 @@ int cmd_buildid_cache(int argc, const char **argv, ...@@ -302,6 +330,8 @@ int cmd_buildid_cache(int argc, const char **argv,
"file", "kcore file to add"), "file", "kcore file to add"),
OPT_STRING('r', "remove", &remove_name_list_str, "file list", OPT_STRING('r', "remove", &remove_name_list_str, "file list",
"file(s) to remove"), "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", OPT_STRING('M', "missing", &missing_filename, "file",
"to find missing build ids in the cache"), "to find missing build ids in the cache"),
OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
...@@ -368,6 +398,24 @@ int cmd_buildid_cache(int argc, const char **argv, ...@@ -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) if (missing_filename)
ret = build_id_cache__fprintf_missing(session, stdout); ret = build_id_cache__fprintf_missing(session, stdout);
......
...@@ -281,35 +281,93 @@ void disable_buildid_cache(void) ...@@ -281,35 +281,93 @@ void disable_buildid_cache(void)
no_buildid_cache = true; 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, int build_id_cache__add_s(const char *sbuild_id, const char *name,
bool is_kallsyms, bool is_vdso) bool is_kallsyms, bool is_vdso)
{ {
const size_t size = PATH_MAX; const size_t size = PATH_MAX;
char *realname, *filename = zalloc(size), char *realname = NULL, *filename = NULL, *dir_name = NULL,
*linkname = zalloc(size), *targetname, *tmp; *linkname = zalloc(size), *targetname, *tmp;
int len, err = -1; int err = -1;
bool slash = is_kallsyms || is_vdso;
if (is_kallsyms) { if (!is_kallsyms) {
if (symbol_conf.kptr_restrict) { realname = realpath(name, NULL);
pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); if (!realname)
err = 0;
goto out_free; 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; goto out_free;
len = scnprintf(filename, size, "%s%s%s", if (mkdir_p(dir_name, 0755))
buildid_dir, slash ? "/" : "",
is_vdso ? DSO__NAME_VDSO : realname);
if (mkdir_p(filename, 0755))
goto out_free; 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 (access(filename, F_OK)) {
if (is_kallsyms) { if (is_kallsyms) {
...@@ -337,6 +395,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, ...@@ -337,6 +395,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
if (!is_kallsyms) if (!is_kallsyms)
free(realname); free(realname);
free(filename); free(filename);
free(dir_name);
free(linkname); free(linkname);
return err; return err;
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#define BUILD_ID_SIZE 20 #define BUILD_ID_SIZE 20
#include "tool.h" #include "tool.h"
#include "strlist.h"
#include <linux/types.h> #include <linux/types.h>
extern struct perf_tool build_id__mark_dso_hit_ops; 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); ...@@ -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__write_buildid_table(struct perf_session *session, int fd);
int perf_session__cache_build_ids(struct perf_session *session); 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); bool build_id_cache__cached(const char *sbuild_id);
int build_id_cache__add_s(const char *sbuild_id, int build_id_cache__add_s(const char *sbuild_id,
const char *name, bool is_kallsyms, bool is_vdso); const char *name, bool is_kallsyms, bool is_vdso);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment