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
1112 1112
1113extern void perf_event_exec(void);1113extern void perf_event_exec(void);
1114extern void perf_event_comm(struct task_struct *tsk, bool exec);1114extern void perf_event_comm(struct task_struct *tsk, bool exec);
1115extern void perf_event_namespaces(struct task_struct *tsk);
1115extern void perf_event_fork(struct task_struct *tsk);1116extern void perf_event_fork(struct task_struct *tsk);
1116 1117
1117/* Callchains */1118/* Callchains */
@@ -1315,6 +1316,7 @@ static inline int perf_unregister_guest_info_callbacks · 197 unmodified lines
1315static inline void perf_event_mmap(struct vm_area_struct *vma) { }1316static inline void perf_event_mmap(struct vm_area_struct *vma) { }
1316static inline void perf_event_exec(void) { }1317static inline void perf_event_exec(void) { }
1317static inline void perf_event_comm(struct task_struct *tsk, bool exec) { }1318static inline void perf_event_comm(struct task_struct *tsk, bool exec) { }
1319static inline void perf_event_namespaces(struct task_struct *tsk) { }
1318static inline void perf_event_fork(struct task_struct *tsk) { }1320static inline void perf_event_fork(struct task_struct *tsk) { }
1319static inline void perf_event_init(void) { }1321static inline void perf_event_init(void) { }
1320static inline int perf_swevent_get_recursion_context(void) { return -1; }1322static 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
344 use_clockid : 1, /* use @clockid for time fields */344 use_clockid : 1, /* use @clockid for time fields */
345 context_switch : 1, /* context switch data */345 context_switch : 1, /* context switch data */
346 write_backward : 1, /* Write ring buffer from end to beginning */346 write_backward : 1, /* Write ring buffer from end to beginning */
347 __reserved_1 : 36;347 namespaces : 1, /* include namespaces data */
348 __reserved_1 : 35;
348 349
349 union {350 union {
350 __u32 wakeup_events; /* wakeup every n events */351 __u32 wakeup_events; /* wakeup every n events */
@@ -610,6 +611,23 @@ struct perf_event_header { · 259 unmodified lines
610 __u16 size;611 __u16 size;
611};612};
612 613
614struct perf_ns_link_info {
615 __u64 dev;
616 __u64 ino;
617};
618
619enum {
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
613enum perf_event_type {631enum perf_event_type {
614 632
615 /*633 /*
@@ -862,6 +880,18 @@ enum perf_event_type { · 246 unmodified lines
862 */880 */
863 PERF_RECORD_SWITCH_CPU_WIDE = 15,881 PERF_RECORD_SWITCH_CPU_WIDE = 15,
864 882
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
865 PERF_RECORD_MAX, /* non-ABI */895 PERF_RECORD_MAX, /* non-ABI */
866};896};
867 897
kernel/events/core.c+139−0
@@ -48,6 +48,8 @@ · 47 unmodified lines
48#include <linux/parser.h>48#include <linux/parser.h>
49#include <linux/sched/clock.h>49#include <linux/sched/clock.h>
50#include <linux/sched/mm.h>50#include <linux/sched/mm.h>
51#include <linux/proc_ns.h>
52#include <linux/mount.h>
51 53
52#include "internal.h"54#include "internal.h"
53 55
@@ -379,6 +381,7 @@ static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events); · 325 unmodified lines
379 381
380static atomic_t nr_mmap_events __read_mostly;382static atomic_t nr_mmap_events __read_mostly;
381static atomic_t nr_comm_events __read_mostly;383static atomic_t nr_comm_events __read_mostly;
384static atomic_t nr_namespaces_events __read_mostly;
382static atomic_t nr_task_events __read_mostly;385static atomic_t nr_task_events __read_mostly;
383static atomic_t nr_freq_events __read_mostly;386static atomic_t nr_freq_events __read_mostly;
384static atomic_t nr_switch_events __read_mostly;387static atomic_t nr_switch_events __read_mostly;
@@ -3991,6 +3994,8 @@ static void unaccount_event(struct perf_event *event) · 3606 unmodified lines
3991 atomic_dec(&nr_mmap_events);3994 atomic_dec(&nr_mmap_events);
3992 if (event->attr.comm)3995 if (event->attr.comm)
3993 atomic_dec(&nr_comm_events);3996 atomic_dec(&nr_comm_events);
3997 if (event->attr.namespaces)
3998 atomic_dec(&nr_namespaces_events);
3994 if (event->attr.task)3999 if (event->attr.task)
3995 atomic_dec(&nr_task_events);4000 atomic_dec(&nr_task_events);
3996 if (event->attr.freq)4001 if (event->attr.freq)
@@ -6491,6 +6496,7 @@ static void perf_event_task(struct task_struct *task, · 2494 unmodified lines
6491void perf_event_fork(struct task_struct *task)6496void perf_event_fork(struct task_struct *task)
6492{6497{
6493 perf_event_task(task, NULL, 1);6498 perf_event_task(task, NULL, 1);
6499 perf_event_namespaces(task);
6494}6500}
6495 6501
6496/*6502/*
@@ -6592,6 +6598,132 @@ void perf_event_comm(struct task_struct *task, bool exec) · 95 unmodified lines
6592 perf_event_comm_event(&comm_event);6598 perf_event_comm_event(&comm_event);
6593}6599}
6594 6600
6601/*
6602 * namespaces tracking
6603 */
6604
6605struct 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
6618static int perf_event_namespaces_match(struct perf_event *event)
6619{
6620 return event->attr.namespaces;
6621}
6622
6623static 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
6653static 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
6669void 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
6595/*6727/*
6596 * mmap tracking6728 * mmap tracking
6597 */6729 */
@@ -9146,6 +9278,8 @@ static void account_event(struct perf_event *event) · 2548 unmodified lines
9146 atomic_inc(&nr_mmap_events);9278 atomic_inc(&nr_mmap_events);
9147 if (event->attr.comm)9279 if (event->attr.comm)
9148 atomic_inc(&nr_comm_events);9280 atomic_inc(&nr_comm_events);
9281 if (event->attr.namespaces)
9282 atomic_inc(&nr_namespaces_events);
9149 if (event->attr.task)9283 if (event->attr.task)
9150 atomic_inc(&nr_task_events);9284 atomic_inc(&nr_task_events);
9151 if (event->attr.freq)9285 if (event->attr.freq)
@@ -9691,6 +9825,11 @@ SYSCALL_DEFINE5(perf_event_open, · 539 unmodified lines
9691 return -EACCES;9825 return -EACCES;
9692 }9826 }
9693 9827
9828 if (attr.namespaces) {
9829 if (!capable(CAP_SYS_ADMIN))
9830 return -EACCES;
9831 }
9832
9694 if (attr.freq) {9833 if (attr.freq) {
9695 if (attr.sample_freq > sysctl_perf_event_sample_rate)9834 if (attr.sample_freq > sysctl_perf_event_sample_rate)
9696 return -EINVAL;9835 return -EINVAL;
kernel/fork.c+2−0
@@ -2352,6 +2352,8 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) · 2351 unmodified lines
2352 }2352 }
2353 }2353 }
2354 2354
2355 perf_event_namespaces(current);
2356
2355bad_unshare_cleanup_cred:2357bad_unshare_cleanup_cred:
2356 if (new_cred)2358 if (new_cred)
2357 put_cred(new_cred);2359 put_cred(new_cred);
kernel/nsproxy.c+3−0
@@ -26,6 +26,7 @@ · 25 unmodified lines
26#include <linux/file.h>26#include <linux/file.h>
27#include <linux/syscalls.h>27#include <linux/syscalls.h>
28#include <linux/cgroup.h>28#include <linux/cgroup.h>
29#include <linux/perf_event.h>
29 30
30static struct kmem_cache *nsproxy_cachep;31static struct kmem_cache *nsproxy_cachep;
31 32
@@ -262,6 +263,8 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) · 230 unmodified lines
262 goto out;263 goto out;
263 }264 }
264 switch_task_namespaces(tsk, new_nsproxy);265 switch_task_namespaces(tsk, new_nsproxy);
266
267 perf_event_namespaces(tsk);
265out:268out:
266 fput(file);269 fput(file);
267 return err;270 return err;