X-Git-Url: http://git.lttng.org/?p=lttng-modules.git;a=blobdiff_plain;f=lttng-statedump-impl.c;h=1a2a12ba7f650ceb9a633b2cd7f79729aeadec32;hp=ecec4f0bc42bb12f84ce5a9ac1fa33c62edbf3df;hb=cd4486798c2b046ea93b89439cd705e93c40b349;hpb=9f36eaed6f91d5897924b551b44d1edd8cee00e2 diff --git a/lttng-statedump-impl.c b/lttng-statedump-impl.c index ecec4f0b..1a2a12ba 100644 --- a/lttng-statedump-impl.c +++ b/lttng-statedump-impl.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: (GPL-2.0 or LGPL-2.1) +/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only) * * lttng-statedump.c * @@ -28,22 +28,21 @@ #include #include #include -#include #include #include #include #include -#include -#include +#include +#include #include -#include #include +#include #include #include #include #include -#include +#include #ifdef CONFIG_LTTNG_HAS_LIST_IRQ #include @@ -51,10 +50,10 @@ /* Define the tracepoints, but do not build the probes */ #define CREATE_TRACE_POINTS -#define TRACE_INCLUDE_PATH instrumentation/events/lttng-module +#define TRACE_INCLUDE_PATH instrumentation/events #define TRACE_INCLUDE_FILE lttng-statedump #define LTTNG_INSTRUMENTATION -#include +#include DEFINE_TRACE(lttng_statedump_block_device); DEFINE_TRACE(lttng_statedump_end); @@ -62,12 +61,25 @@ DEFINE_TRACE(lttng_statedump_interrupt); DEFINE_TRACE(lttng_statedump_file_descriptor); DEFINE_TRACE(lttng_statedump_start); DEFINE_TRACE(lttng_statedump_process_state); +DEFINE_TRACE(lttng_statedump_process_pid_ns); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0)) +DEFINE_TRACE(lttng_statedump_process_cgroup_ns); +#endif +DEFINE_TRACE(lttng_statedump_process_ipc_ns); +#ifndef LTTNG_MNT_NS_MISSING_HEADER +DEFINE_TRACE(lttng_statedump_process_mnt_ns); +#endif +DEFINE_TRACE(lttng_statedump_process_net_ns); +DEFINE_TRACE(lttng_statedump_process_user_ns); +DEFINE_TRACE(lttng_statedump_process_uts_ns); DEFINE_TRACE(lttng_statedump_network_interface); +#ifdef LTTNG_HAVE_STATEDUMP_CPU_TOPOLOGY +DEFINE_TRACE(lttng_statedump_cpu_topology); +#endif struct lttng_fd_ctx { char *page; struct lttng_session *session; - struct task_struct *p; struct files_struct *files; }; @@ -232,52 +244,50 @@ int lttng_dump_one_fd(const void *p, struct file *file, unsigned int fd) /* Make sure we give at least some info */ spin_lock(&dentry->d_lock); - trace_lttng_statedump_file_descriptor(ctx->session, ctx->p, fd, - dentry->d_name.name, flags, file->f_mode); + trace_lttng_statedump_file_descriptor(ctx->session, + ctx->files, fd, dentry->d_name.name, flags, + file->f_mode); spin_unlock(&dentry->d_lock); goto end; } - trace_lttng_statedump_file_descriptor(ctx->session, ctx->p, fd, s, - flags, file->f_mode); + trace_lttng_statedump_file_descriptor(ctx->session, + ctx->files, fd, s, flags, file->f_mode); end: return 0; } +/* Called with task lock held. */ static -void lttng_enumerate_task_fd(struct lttng_session *session, - struct task_struct *p, char *tmp) +void lttng_enumerate_files(struct lttng_session *session, + struct files_struct *files, + char *tmp) { - struct lttng_fd_ctx ctx = { .page = tmp, .session = session, .p = p }; - struct files_struct *files; + struct lttng_fd_ctx ctx = { .page = tmp, .session = session, .files = files, }; - task_lock(p); - files = p->files; - if (!files) - goto end; - ctx.files = files; lttng_iterate_fd(files, 0, lttng_dump_one_fd, &ctx); -end: - task_unlock(p); } +#ifdef LTTNG_HAVE_STATEDUMP_CPU_TOPOLOGY static -int lttng_enumerate_file_descriptors(struct lttng_session *session) +int lttng_enumerate_cpu_topology(struct lttng_session *session) { - struct task_struct *p; - char *tmp; + int cpu; + const cpumask_t *cpumask = cpu_possible_mask; - tmp = (char *) __get_free_page(GFP_KERNEL); - if (!tmp) - return -ENOMEM; + for (cpu = cpumask_first(cpumask); cpu < nr_cpu_ids; + cpu = cpumask_next(cpu, cpumask)) { + trace_lttng_statedump_cpu_topology(session, &cpu_data(cpu)); + } - /* Enumerate active file descriptors */ - rcu_read_lock(); - for_each_process(p) - lttng_enumerate_task_fd(session, p, tmp); - rcu_read_unlock(); - free_page((unsigned long) tmp); return 0; } +#else +static +int lttng_enumerate_cpu_topology(struct lttng_session *session) +{ + return 0; +} +#endif #if 0 /* @@ -329,10 +339,6 @@ int lttng_enumerate_vm_maps(struct lttng_session *session) #ifdef CONFIG_LTTNG_HAS_LIST_IRQ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)) -#define irq_desc_get_chip(desc) get_irq_desc_chip(desc) -#endif - static int lttng_list_interrupts(struct lttng_session *session) { @@ -348,12 +354,12 @@ int lttng_list_interrupts(struct lttng_session *session) irq_desc_get_chip(desc)->name ? : "unnamed_irq_chip"; local_irq_save(flags); - wrapper_desc_spin_lock(&desc->lock); + raw_spin_lock(&desc->lock); for (action = desc->action; action; action = action->next) { trace_lttng_statedump_interrupt(session, irq, irq_chip_name, action); } - wrapper_desc_spin_unlock(&desc->lock); + raw_spin_unlock(&desc->lock); local_irq_restore(flags); } return 0; @@ -368,6 +374,10 @@ int lttng_list_interrupts(struct lttng_session *session) #endif /* + * Statedump the task's namespaces using the proc filesystem inode number as + * the unique identifier. The user and pid ns are nested and will be dumped + * recursively. + * * Called with task lock held. */ static @@ -378,23 +388,87 @@ void lttng_statedump_process_ns(struct lttng_session *session, enum lttng_execution_submode submode, enum lttng_process_status status) { + struct nsproxy *proxy; struct pid_namespace *pid_ns; + struct user_namespace *user_ns; + /* + * The pid and user namespaces are special, they are nested and + * accessed with specific functions instead of the nsproxy struct + * like the other namespaces. + */ pid_ns = task_active_pid_ns(p); do { - trace_lttng_statedump_process_state(session, - p, type, mode, submode, status, pid_ns); - pid_ns = pid_ns->parent; + trace_lttng_statedump_process_pid_ns(session, p, pid_ns); + pid_ns = pid_ns ? pid_ns->parent : NULL; } while (pid_ns); + + + user_ns = task_cred_xxx(p, user_ns); + do { + trace_lttng_statedump_process_user_ns(session, p, user_ns); + /* + * trace_lttng_statedump_process_user_ns() internally + * checks whether user_ns is NULL. While this does not + * appear to be a possible return value for + * task_cred_xxx(), err on the safe side and check + * for NULL here as well to be consistent with the + * paranoid behavior of + * trace_lttng_statedump_process_user_ns(). + */ + user_ns = user_ns ? user_ns->lttng_user_ns_parent : NULL; + } while (user_ns); + + /* + * Back and forth on locking strategy within Linux upstream for nsproxy. + * See Linux upstream commit 728dba3a39c66b3d8ac889ddbe38b5b1c264aec3 + * "namespaces: Use task_lock and not rcu to protect nsproxy" + * for details. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) || \ + LTTNG_UBUNTU_KERNEL_RANGE(3,13,11,36, 3,14,0,0) || \ + LTTNG_UBUNTU_KERNEL_RANGE(3,16,1,11, 3,17,0,0) || \ + LTTNG_RHEL_KERNEL_RANGE(3,10,0,229,13,0, 3,11,0,0,0,0)) + proxy = p->nsproxy; +#else + rcu_read_lock(); + proxy = task_nsproxy(p); +#endif + if (proxy) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0)) + trace_lttng_statedump_process_cgroup_ns(session, p, proxy->cgroup_ns); +#endif + trace_lttng_statedump_process_ipc_ns(session, p, proxy->ipc_ns); +#ifndef LTTNG_MNT_NS_MISSING_HEADER + trace_lttng_statedump_process_mnt_ns(session, p, proxy->mnt_ns); +#endif + trace_lttng_statedump_process_net_ns(session, p, proxy->net_ns); + trace_lttng_statedump_process_uts_ns(session, p, proxy->uts_ns); + } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) || \ + LTTNG_UBUNTU_KERNEL_RANGE(3,13,11,36, 3,14,0,0) || \ + LTTNG_UBUNTU_KERNEL_RANGE(3,16,1,11, 3,17,0,0) || \ + LTTNG_RHEL_KERNEL_RANGE(3,10,0,229,13,0, 3,11,0,0,0,0)) + /* (nothing) */ +#else + rcu_read_unlock(); +#endif } static int lttng_enumerate_process_states(struct lttng_session *session) { struct task_struct *g, *p; + char *tmp; + + tmp = (char *) __get_free_page(GFP_KERNEL); + if (!tmp) + return -ENOMEM; rcu_read_lock(); for_each_process(g) { + struct files_struct *prev_files = NULL; + p = g; do { enum lttng_execution_mode mode = @@ -403,6 +477,7 @@ int lttng_enumerate_process_states(struct lttng_session *session) LTTNG_UNKNOWN; enum lttng_process_status status; enum lttng_thread_type type; + struct files_struct *files; task_lock(p); if (p->exit_state == EXIT_ZOMBIE) @@ -437,13 +512,31 @@ int lttng_enumerate_process_states(struct lttng_session *session) type = LTTNG_USER_THREAD; else type = LTTNG_KERNEL_THREAD; + files = p->files; + + trace_lttng_statedump_process_state(session, + p, type, mode, submode, status, files); lttng_statedump_process_ns(session, p, type, mode, submode, status); + /* + * As an optimisation for the common case, do not + * repeat information for the same files_struct in + * two consecutive threads. This is the common case + * for threads sharing the same fd table. RCU guarantees + * that the same files_struct pointer is not re-used + * throughout processes/threads iteration. + */ + if (files && files != prev_files) { + lttng_enumerate_files(session, files, tmp); + prev_files = files; + } task_unlock(p); } while_each_thread(g, p); } rcu_read_unlock(); + free_page((unsigned long) tmp); + return 0; } @@ -462,9 +555,6 @@ int do_lttng_statedump(struct lttng_session *session) trace_lttng_statedump_start(session); ret = lttng_enumerate_process_states(session); - if (ret) - return ret; - ret = lttng_enumerate_file_descriptors(session); if (ret) return ret; /* @@ -489,6 +579,9 @@ int do_lttng_statedump(struct lttng_session *session) default: return ret; } + ret = lttng_enumerate_cpu_topology(session); + if (ret) + return ret; /* TODO lttng_dump_idt_table(session); */ /* TODO lttng_dump_softirq_vec(session); */