From e7a0ca7205fd4be7c829d171baa8823fe4784c90 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 10 Mar 2020 15:00:29 -0400 Subject: [PATCH] statedump: introduce file_table_address Currently the LTTng-modules statedump simply iterates over all processes in the system and assumes all threads share the same file descriptor table, which is only true if threads were created with clone CLONE_FILES. Directly invoking clone without the CLONE_FILES creates threads which belong to the same process, but have their own file descriptor table. Therefore, model-wise, we cannot assume that all threads in a process have the same fd table content. Add a new "file_table_address" field to the lttng_statedump_process_state event, which dumps the address of the thread's struct files_struct pointer. This pointer is guaranteed to never be re-used while we hold the RCU read-side lock (so for the entire iteration over processes/threads). For the lttng_statedump_file_descriptor event, remove the "pid" field (which is semantically inaccurate) and add a "file_table_address" field, which contains the struct files_struct address of the file table containing the file descriptor. An optimization is performed to eliminate most duplcated file table content by skipping file table dump if the same file table address is encountered consecutively while iterating over a process' threads. This introduces a semantic change to the statedump fields, and will therefore be introduced in lttng-modules 2.12 onwards, not backported as a fix. Fixes: #1245 Signed-off-by: Mathieu Desnoyers --- .../events/lttng-module/lttng-statedump.h | 13 ++-- lttng-statedump-impl.c | 73 +++++++++---------- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/instrumentation/events/lttng-module/lttng-statedump.h b/instrumentation/events/lttng-module/lttng-statedump.h index 59f3efde..5ba7df20 100644 --- a/instrumentation/events/lttng-module/lttng-statedump.h +++ b/instrumentation/events/lttng-module/lttng-statedump.h @@ -40,8 +40,9 @@ LTTNG_TRACEPOINT_EVENT(lttng_statedump_end, LTTNG_TRACEPOINT_EVENT(lttng_statedump_process_state, TP_PROTO(struct lttng_session *session, struct task_struct *p, - int type, int mode, int submode, int status), - TP_ARGS(session, p, type, mode, submode, status), + int type, int mode, int submode, int status, + struct files_struct *files), + TP_ARGS(session, p, type, mode, submode, status, files), TP_FIELDS( ctf_integer(pid_t, tid, p->pid) ctf_integer(pid_t, pid, p->tgid) @@ -60,6 +61,7 @@ LTTNG_TRACEPOINT_EVENT(lttng_statedump_process_state, ctf_integer(int, submode, submode) ctf_integer(int, status, status) ctf_integer(unsigned int, cpu, task_cpu(p)) + ctf_integer_hex(struct files_struct *, file_table_address, files) ) ) @@ -179,11 +181,12 @@ LTTNG_TRACEPOINT_EVENT(lttng_statedump_process_uts_ns, LTTNG_TRACEPOINT_EVENT(lttng_statedump_file_descriptor, TP_PROTO(struct lttng_session *session, - struct task_struct *p, int fd, const char *filename, + struct files_struct *files, + int fd, const char *filename, unsigned int flags, fmode_t fmode), - TP_ARGS(session, p, fd, filename, flags, fmode), + TP_ARGS(session, files, fd, filename, flags, fmode), TP_FIELDS( - ctf_integer(pid_t, pid, p->tgid) + ctf_integer_hex(struct files_struct *, file_table_address, files) ctf_integer(int, fd, fd) ctf_integer_oct(unsigned int, flags, flags) ctf_integer_hex(fmode_t, fmode, fmode) diff --git a/lttng-statedump-impl.c b/lttng-statedump-impl.c index f3ae1937..b60531d5 100644 --- a/lttng-statedump-impl.c +++ b/lttng-statedump-impl.c @@ -80,7 +80,6 @@ DEFINE_TRACE(lttng_statedump_cpu_topology); struct lttng_fd_ctx { char *page; struct lttng_session *session; - struct task_struct *p; struct files_struct *files; }; @@ -245,51 +244,27 @@ 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); -} - -static -int lttng_enumerate_file_descriptors(struct lttng_session *session) -{ - struct task_struct *p; - char *tmp; - - tmp = (char *) __get_free_page(GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - /* 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; } #ifdef LTTNG_HAVE_STATEDUMP_CPU_TOPOLOGY @@ -484,9 +459,16 @@ 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 = @@ -495,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) @@ -529,16 +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); + 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; } @@ -557,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; /* -- 2.34.1