History

perf: Add PERF_RECORD_NAMESPACES to include namespaces related info

With the advert of container technologies like docker, that depend on namespaces for isolation, there is a need for tracing support for namespaces. This patch introduces new PERF_RECORD_NAMESPACES event for recording namespaces related info. By recording info for every namespace, it is left to userspace to take a call on the definition of a container and trace containers by updating perf tool accordingly. Each namespace has a combination of device and inode numbers. Though every namespace has the same device number currently, that may change in future to avoid the need for a namespace of namespaces. Considering such possibility, record both device and inode numbers separately for each namespace.

Hari Bathini committed 9 years ago

Commit e4222671 parent 3ef5b405 files · +177 −1Browse files

Unified · Split

5 files
  1. include/linux/perf_event.h +2 −0
  2. include/uapi/linux/perf_event.h +31 −1
  3. kernel/events/core.c +139 −0
  4. kernel/fork.c +2 −0
  5. kernel/nsproxy.c +3 −0
include/linux/perf_event.h+2−0
@@ -1112,6 +1112,7 @@ extern int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks · 1111 unmodified lines
11121112
11131113 extern void perf_event_exec(void);
11141114 extern void perf_event_comm(struct task_struct *tsk, bool exec);
1115+extern void perf_event_namespaces(struct task_struct *tsk);
11151116 extern void perf_event_fork(struct task_struct *tsk);
11161117
11171118 /* Callchains */
@@ -1315,6 +1316,7 @@ static inline int perf_unregister_guest_info_callbacks · 197 unmodified lines
13151316 static inline void perf_event_mmap(struct vm_area_struct *vma) { }
13161317 static inline void perf_event_exec(void) { }
13171318 static inline void perf_event_comm(struct task_struct *tsk, bool exec) { }
1319+static inline void perf_event_namespaces(struct task_struct *tsk) { }
13181320 static inline void perf_event_fork(struct task_struct *tsk) { }
13191321 static inline void perf_event_init(void) { }
13201322 static inline int perf_swevent_get_recursion_context(void) { return -1; }
include/uapi/linux/perf_event.h+31−1
@@ -344,7 +344,8 @@ struct perf_event_attr { · 343 unmodified lines
344344 use_clockid : 1, /* use @clockid for time fields */
345345 context_switch : 1, /* context switch data */
346346 write_backward : 1, /* Write ring buffer from end to beginning */
347− __reserved_1 : 36;
347+ namespaces : 1, /* include namespaces data */
348+ __reserved_1 : 35;
348349
349350 union {
350351 __u32 wakeup_events; /* wakeup every n events */
@@ -610,6 +611,23 @@ struct perf_event_header { · 259 unmodified lines
610611 __u16 size;
611612 };
612613
614+struct perf_ns_link_info {
615+ __u64 dev;
616+ __u64 ino;
617+};
618+
619+enum {
620+ NET_NS_INDEX = 0,
621+ UTS_NS_INDEX = 1,
622+ IPC_NS_INDEX = 2,
623+ PID_NS_INDEX = 3,
624+ USER_NS_INDEX = 4,
625+ MNT_NS_INDEX = 5,
626+ CGROUP_NS_INDEX = 6,
627+
628+ NR_NAMESPACES, /* number of available namespaces */
629+};
630+
613631 enum perf_event_type {
614632
615633 /*
@@ -862,6 +880,18 @@ enum perf_event_type { · 246 unmodified lines
862880 */
863881 PERF_RECORD_SWITCH_CPU_WIDE = 15,
864882
883+ /*
884+ * struct {
885+ * struct perf_event_header header;
886+ * u32 pid;
887+ * u32 tid;
888+ * u64 nr_namespaces;
889+ * { u64 dev, inode; } [nr_namespaces];
890+ * struct sample_id sample_id;
891+ * };
892+ */
893+ PERF_RECORD_NAMESPACES = 16,
894+
865895 PERF_RECORD_MAX, /* non-ABI */
866896 };
867897
kernel/events/core.c+139−0
@@ -48,6 +48,8 @@ · 47 unmodified lines
4848 #include <linux/parser.h>
4949 #include <linux/sched/clock.h>
5050 #include <linux/sched/mm.h>
51+#include <linux/proc_ns.h>
52+#include <linux/mount.h>
5153
5254 #include "internal.h"
5355
@@ -379,6 +381,7 @@ static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events); · 325 unmodified lines
379381
380382 static atomic_t nr_mmap_events __read_mostly;
381383 static atomic_t nr_comm_events __read_mostly;
384+static atomic_t nr_namespaces_events __read_mostly;
382385 static atomic_t nr_task_events __read_mostly;
383386 static atomic_t nr_freq_events __read_mostly;
384387 static atomic_t nr_switch_events __read_mostly;
@@ -3991,6 +3994,8 @@ static void unaccount_event(struct perf_event *event) · 3606 unmodified lines
39913994 atomic_dec(&nr_mmap_events);
39923995 if (event->attr.comm)
39933996 atomic_dec(&nr_comm_events);
3997+ if (event->attr.namespaces)
3998+ atomic_dec(&nr_namespaces_events);
39943999 if (event->attr.task)
39954000 atomic_dec(&nr_task_events);
39964001 if (event->attr.freq)
@@ -6491,6 +6496,7 @@ static void perf_event_task(struct task_struct *task, · 2494 unmodified lines
64916496 void perf_event_fork(struct task_struct *task)
64926497 {
64936498 perf_event_task(task, NULL, 1);
6499+ perf_event_namespaces(task);
64946500 }
64956501
64966502 /*
@@ -6592,6 +6598,132 @@ void perf_event_comm(struct task_struct *task, bool exec) · 95 unmodified lines
65926598 perf_event_comm_event(&comm_event);
65936599 }
65946600
6601+/*
6602+ * namespaces tracking
6603+ */
6604+
6605+struct perf_namespaces_event {
6606+ struct task_struct *task;
6607+
6608+ struct {
6609+ struct perf_event_header header;
6610+
6611+ u32 pid;
6612+ u32 tid;
6613+ u64 nr_namespaces;
6614+ struct perf_ns_link_info link_info[NR_NAMESPACES];
6615+ } event_id;
6616+};
6617+
6618+static int perf_event_namespaces_match(struct perf_event *event)
6619+{
6620+ return event->attr.namespaces;
6621+}
6622+
6623+static void perf_event_namespaces_output(struct perf_event *event,
6624+ void *data)
6625+{
6626+ struct perf_namespaces_event *namespaces_event = data;
6627+ struct perf_output_handle handle;
6628+ struct perf_sample_data sample;
6629+ int ret;
6630+
6631+ if (!perf_event_namespaces_match(event))
6632+ return;
6633+
6634+ perf_event_header__init_id(&namespaces_event->event_id.header,
6635+ &sample, event);
6636+ ret = perf_output_begin(&handle, event,
6637+ namespaces_event->event_id.header.size);
6638+ if (ret)
6639+ return;
6640+
6641+ namespaces_event->event_id.pid = perf_event_pid(event,
6642+ namespaces_event->task);
6643+ namespaces_event->event_id.tid = perf_event_tid(event,
6644+ namespaces_event->task);
6645+
6646+ perf_output_put(&handle, namespaces_event->event_id);
6647+
6648+ perf_event__output_id_sample(event, &handle, &sample);
6649+
6650+ perf_output_end(&handle);
6651+}
6652+
6653+static void perf_fill_ns_link_info(struct perf_ns_link_info *ns_link_info,
6654+ struct task_struct *task,
6655+ const struct proc_ns_operations *ns_ops)
6656+{
6657+ struct path ns_path;
6658+ struct inode *ns_inode;
6659+ void *error;
6660+
6661+ error = ns_get_path(&ns_path, task, ns_ops);
6662+ if (!error) {
6663+ ns_inode = ns_path.dentry->d_inode;
6664+ ns_link_info->dev = new_encode_dev(ns_inode->i_sb->s_dev);
6665+ ns_link_info->ino = ns_inode->i_ino;
6666+ }
6667+}
6668+
6669+void perf_event_namespaces(struct task_struct *task)
6670+{
6671+ struct perf_namespaces_event namespaces_event;
6672+ struct perf_ns_link_info *ns_link_info;
6673+
6674+ if (!atomic_read(&nr_namespaces_events))
6675+ return;
6676+
6677+ namespaces_event = (struct perf_namespaces_event){
6678+ .task = task,
6679+ .event_id = {
6680+ .header = {
6681+ .type = PERF_RECORD_NAMESPACES,
6682+ .misc = 0,
6683+ .size = sizeof(namespaces_event.event_id),
6684+ },
6685+ /* .pid */
6686+ /* .tid */
6687+ .nr_namespaces = NR_NAMESPACES,
6688+ /* .link_info[NR_NAMESPACES] */
6689+ },
6690+ };
6691+
6692+ ns_link_info = namespaces_event.event_id.link_info;
6693+
6694+ perf_fill_ns_link_info(&ns_link_info[MNT_NS_INDEX],
6695+ task, &mntns_operations);
6696+
6697+#ifdef CONFIG_USER_NS
6698+ perf_fill_ns_link_info(&ns_link_info[USER_NS_INDEX],
6699+ task, &userns_operations);
6700+#endif
6701+#ifdef CONFIG_NET_NS
6702+ perf_fill_ns_link_info(&ns_link_info[NET_NS_INDEX],
6703+ task, &netns_operations);
6704+#endif
6705+#ifdef CONFIG_UTS_NS
6706+ perf_fill_ns_link_info(&ns_link_info[UTS_NS_INDEX],
6707+ task, &utsns_operations);
6708+#endif
6709+#ifdef CONFIG_IPC_NS
6710+ perf_fill_ns_link_info(&ns_link_info[IPC_NS_INDEX],
6711+ task, &ipcns_operations);
6712+#endif
6713+#ifdef CONFIG_PID_NS
6714+ perf_fill_ns_link_info(&ns_link_info[PID_NS_INDEX],
6715+ task, &pidns_operations);
6716+#endif
6717+#ifdef CONFIG_CGROUPS
6718+ perf_fill_ns_link_info(&ns_link_info[CGROUP_NS_INDEX],
6719+ task, &cgroupns_operations);
6720+#endif
6721+
6722+ perf_iterate_sb(perf_event_namespaces_output,
6723+ &namespaces_event,
6724+ NULL);
6725+}
6726+
65956727 /*
65966728 * mmap tracking
65976729 */
@@ -9146,6 +9278,8 @@ static void account_event(struct perf_event *event) · 2548 unmodified lines
91469278 atomic_inc(&nr_mmap_events);
91479279 if (event->attr.comm)
91489280 atomic_inc(&nr_comm_events);
9281+ if (event->attr.namespaces)
9282+ atomic_inc(&nr_namespaces_events);
91499283 if (event->attr.task)
91509284 atomic_inc(&nr_task_events);
91519285 if (event->attr.freq)
@@ -9691,6 +9825,11 @@ SYSCALL_DEFINE5(perf_event_open, · 539 unmodified lines
96919825 return -EACCES;
96929826 }
96939827
9828+ if (attr.namespaces) {
9829+ if (!capable(CAP_SYS_ADMIN))
9830+ return -EACCES;
9831+ }
9832+
96949833 if (attr.freq) {
96959834 if (attr.sample_freq > sysctl_perf_event_sample_rate)
96969835 return -EINVAL;
kernel/fork.c+2−0
@@ -2352,6 +2352,8 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) · 2351 unmodified lines
23522352 }
23532353 }
23542354
2355+ perf_event_namespaces(current);
2356+
23552357 bad_unshare_cleanup_cred:
23562358 if (new_cred)
23572359 put_cred(new_cred);
kernel/nsproxy.c+3−0
@@ -26,6 +26,7 @@ · 25 unmodified lines
2626 #include <linux/file.h>
2727 #include <linux/syscalls.h>
2828 #include <linux/cgroup.h>
29+#include <linux/perf_event.h>
2930
3031 static struct kmem_cache *nsproxy_cachep;
3132
@@ -262,6 +263,8 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) · 230 unmodified lines
262263 goto out;
263264 }
264265 switch_task_namespaces(tsk, new_nsproxy);
266+
267+ perf_event_namespaces(tsk);
265268 out:
266269 fput(file);
267270 return err;