perf buildid-cache: Add --purge FILE to remove all caches of FILE
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Fri, 27 Feb 2015 04:50:26 +0000 (13:50 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 27 Feb 2015 18:52:33 +0000 (15:52 -0300)
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: Masami 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: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/Documentation/perf-buildid-cache.txt
tools/perf/builtin-buildid-cache.c
tools/perf/util/build-id.c
tools/perf/util/build-id.h

index cec6b57e8be668b47bfd96467fbf6310d8c8a9cc..dd07b55f58d8e9990e6f625ab3ebce2bf6bd6bbc 100644 (file)
@@ -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.
index e7568f5844ad45b0e2cd6411d43c0ed93670dcf2..86f9d78195a4499cd127162be18420e55b349714 100644 (file)
@@ -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);
 
index 0bc33be5a78ccca79bc2d09ff6299e2f048ef233..ffdc338df9256a8a805b0cdd5e8422264f512552 100644 (file)
@@ -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;
-                       goto out_free;
-               }
-               realname = (char *) name;
-       } else
+       if (!is_kallsyms) {
                realname = realpath(name, NULL);
+               if (!realname)
+                       goto out_free;
+       }
 
-       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 @@ out_free:
        if (!is_kallsyms)
                free(realname);
        free(filename);
+       free(dir_name);
        free(linkname);
        return err;
 }
index 2a094982f9545311350630396219915b373daea7..85011222cc14a68f05d2b3451ef381263d293efc 100644 (file)
@@ -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);