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

Commit 843ff37b authored by Krister Johansen's avatar Krister Johansen Committed by Arnaldo Carvalho de Melo
Browse files

perf symbols: Find symbols in different mount namespace



Teach perf how to resolve symbols from binaries that are in a different
mount namespace from the tool.  This allows perf to generate meaningful
stack traces even if the binary resides in a different mount namespace
from the tool.

Signed-off-by: default avatarKrister Johansen <kjlx@templeofstupid.com>
Tested-by: default avatarBrendan Gregg <brendan.d.gregg@gmail.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas-Mich Richter <tmricht@linux.vnet.ibm.com>
Link: http://lkml.kernel.org/r/1499305693-1599-2-git-send-email-kjlx@templeofstupid.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 86bcdb5a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1236,6 +1236,7 @@ void dso__delete(struct dso *dso)
	dso_cache__free(dso);
	dso__free_a2l(dso);
	zfree(&dso->symsrc_filename);
	nsinfo__zput(dso->nsinfo);
	pthread_mutex_destroy(&dso->lock);
	free(dso);
}
+2 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/types.h>
#include <linux/bitops.h>
#include "map.h"
#include "namespaces.h"
#include "build-id.h"

enum dso_binary_type {
@@ -187,6 +188,7 @@ struct dso {
		void	 *priv;
		u64	 db_id;
	};
	struct nsinfo	*nsinfo;
	refcount_t	 refcnt;
	char		 name[0];
};
+2 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include "machine.h"
#include <linux/string.h>
#include "srcline.h"
#include "namespaces.h"
#include "unwind.h"

static void __maps__insert(struct maps *maps, struct map *map);
@@ -200,6 +201,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
			if (type != MAP__FUNCTION)
				dso__set_loaded(dso, map->type);
		}
		dso->nsinfo = nsinfo__get(thread->nsinfo);
		dso__put(dso);
	}
	return map;
+127 −0
Original line number Diff line number Diff line
@@ -9,9 +9,13 @@
#include "namespaces.h"
#include "util.h"
#include "event.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sched.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

struct namespaces *namespaces__new(struct namespaces_event *event)
{
@@ -35,3 +39,126 @@ void namespaces__free(struct namespaces *namespaces)
{
	free(namespaces);
}

void nsinfo__init(struct nsinfo *nsi)
{
	char oldns[PATH_MAX];
	char *newns = NULL;
	struct stat old_stat;
	struct stat new_stat;

	if (snprintf(oldns, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
		return;

	if (asprintf(&newns, "/proc/%d/ns/mnt", nsi->pid) == -1)
		return;

	if (stat(oldns, &old_stat) < 0)
		goto out;

	if (stat(newns, &new_stat) < 0)
		goto out;

	/* Check if the mount namespaces differ, if so then indicate that we
	 * want to switch as part of looking up dso/map data.
	 */
	if (old_stat.st_ino != new_stat.st_ino) {
		nsi->need_setns = true;
		nsi->mntns_path = newns;
		newns = NULL;
	}

out:
	free(newns);
}

struct nsinfo *nsinfo__new(pid_t pid)
{
	struct nsinfo *nsi = calloc(1, sizeof(*nsi));

	if (nsi != NULL) {
		nsi->pid = pid;
		nsi->need_setns = false;
		nsinfo__init(nsi);
		refcount_set(&nsi->refcnt, 1);
	}

	return nsi;
}

void nsinfo__delete(struct nsinfo *nsi)
{
	zfree(&nsi->mntns_path);
	free(nsi);
}

struct nsinfo *nsinfo__get(struct nsinfo *nsi)
{
	if (nsi)
		refcount_inc(&nsi->refcnt);
	return nsi;
}

void nsinfo__put(struct nsinfo *nsi)
{
	if (nsi && refcount_dec_and_test(&nsi->refcnt))
		nsinfo__delete(nsi);
}

void nsinfo__mountns_enter(struct nsinfo *nsi, struct nscookie *nc)
{
	char curpath[PATH_MAX];
	int oldns = -1;
	int newns = -1;

	if (nc == NULL)
		return;

	nc->oldns = -1;
	nc->newns = -1;

	if (!nsi || !nsi->need_setns)
		return;

	if (snprintf(curpath, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
		return;

	oldns = open(curpath, O_RDONLY);
	if (oldns < 0)
		return;

	newns = open(nsi->mntns_path, O_RDONLY);
	if (newns < 0)
		goto errout;

	if (setns(newns, CLONE_NEWNS) < 0)
		goto errout;

	nc->oldns = oldns;
	nc->newns = newns;
	return;

errout:
	if (oldns > -1)
		close(oldns);
	if (newns > -1)
		close(newns);
}

void nsinfo__mountns_exit(struct nscookie *nc)
{
	if (nc == NULL || nc->oldns == -1 || nc->newns == -1)
		return;

	setns(nc->oldns, CLONE_NEWNS);

	if (nc->oldns > -1) {
		close(nc->oldns);
		nc->oldns = -1;
	}

	if (nc->newns > -1) {
		close(nc->newns);
		nc->newns = -1;
	}
}
+33 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@

#include "../perf.h"
#include <linux/list.h>
#include <linux/refcount.h>

struct namespaces_event;

@@ -23,4 +24,36 @@ struct namespaces {
struct namespaces *namespaces__new(struct namespaces_event *event);
void namespaces__free(struct namespaces *namespaces);

struct nsinfo {
	pid_t			pid;
	bool			need_setns;
	char			*mntns_path;
	refcount_t		refcnt;
};

struct nscookie {
	int			oldns;
	int			newns;
};

void nsinfo__init(struct nsinfo *nsi);
struct nsinfo *nsinfo__new(pid_t pid);
void nsinfo__delete(struct nsinfo *nsi);

struct nsinfo *nsinfo__get(struct nsinfo *nsi);
void nsinfo__put(struct nsinfo *nsi);

void nsinfo__mountns_enter(struct nsinfo *nsi, struct nscookie *nc);
void nsinfo__mountns_exit(struct nscookie *nc);

static inline void __nsinfo__zput(struct nsinfo **nsip)
{
	if (nsip) {
		nsinfo__put(*nsip);
		*nsip = NULL;
	}
}

#define nsinfo__zput(nsi) __nsinfo__zput(&nsi)

#endif  /* __PERF_NAMESPACES_H */
Loading