statedump: introduce file_table_address
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 10 Mar 2020 19:00:29 +0000 (15:00 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 10 Mar 2020 19:12:08 +0000 (15:12 -0400)
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 <mathieu.desnoyers@efficios.com>
instrumentation/events/lttng-module/lttng-statedump.h
lttng-statedump-impl.c

index 59f3efdef278d13ce63e874a1d4e4f2839de78be..5ba7df20d49bd6b786bda24021ec97d9d3998018 100644 (file)
@@ -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)
index f3ae1937b1faa5da94683d891311bc1013eb1bb8..b60531d507020bdbf26e8f7cac1b95f48d101663 100644 (file)
@@ -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;
        /*
This page took 0.028554 seconds and 4 git commands to generate.