Add support for kvm x86 specific tracepoints
[lttng-modules.git] / lttng-statedump-impl.c
index eccf1de2dc405c9305619adef3a09e2cc89cd9b1..04acf6eff3409beb78944fad9476d44c74098cec 100644 (file)
@@ -1,15 +1,29 @@
 /*
+ * lttng-statedump.c
+ *
  * Linux Trace Toolkit Next Generation Kernel State Dump
  *
  * Copyright 2005 Jean-Hugues Deschenes <jean-hugues.deschenes@polymtl.ca>
  * Copyright 2006-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
  *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; only
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
  * Changes:
  *     Eric Clement:                   Add listing of network IP interface
  *     2006, 2007 Mathieu Desnoyers    Fix kernel threads
  *                                     Various updates
- *
- * Dual LGPL v2.1/GPL v2 license.
  */
 
 #include <linux/init.h>
@@ -34,6 +48,8 @@
 
 #include "lttng-events.h"
 #include "wrapper/irqdesc.h"
+#include "wrapper/spinlock.h"
+#include "wrapper/fdtable.h"
 
 #ifdef CONFIG_GENERIC_HARDIRQS
 #include <linux/irq.h>
 #define TRACE_INCLUDE_FILE lttng-statedump
 #include "instrumentation/events/lttng-module/lttng-statedump.h"
 
+struct lttng_fd_ctx {
+       char *page;
+       struct lttng_session *session;
+       struct task_struct *p;
+};
+
 /*
  * Protected by the trace lock.
  */
@@ -126,34 +148,35 @@ int lttng_enumerate_network_ip_interface(struct lttng_session *session)
 }
 #endif /* CONFIG_INET */
 
+static
+int lttng_dump_one_fd(const void *p, struct file *file, unsigned int fd)
+{
+       const struct lttng_fd_ctx *ctx = p;
+       const char *s = d_path(&file->f_path, ctx->page, PAGE_SIZE);
+
+       if (IS_ERR(s)) {
+               struct dentry *dentry = file->f_path.dentry;
+
+               /* 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);
+               spin_unlock(&dentry->d_lock);
+               goto end;
+       }
+       trace_lttng_statedump_file_descriptor(ctx->session, ctx->p, fd, s);
+end:
+       return 0;
+}
 
 static
 void lttng_enumerate_task_fd(struct lttng_session *session,
                struct task_struct *p, char *tmp)
 {
-       struct fdtable *fdt;
-       struct file *filp;
-       unsigned int i;
-       const unsigned char *path;
+       struct lttng_fd_ctx ctx = { .page = tmp, .session = session, .p = p };
 
        task_lock(p);
-       if (!p->files)
-               goto unlock_task;
-       spin_lock(&p->files->file_lock);
-       fdt = files_fdtable(p->files);
-       for (i = 0; i < fdt->max_fds; i++) {
-               filp = fcheck_files(p->files, i);
-               if (!filp)
-                       continue;
-               path = d_path(&filp->f_path, tmp, PAGE_SIZE);
-               /* Make sure we give at least some info */
-               trace_lttng_statedump_file_descriptor(session, p, i,
-                       IS_ERR(path) ?
-                               filp->f_dentry->d_name.name :
-                               path);
-       }
-       spin_unlock(&p->files->file_lock);
-unlock_task:
+       lttng_iterate_fd(p->files, 0, lttng_dump_one_fd, &ctx);
        task_unlock(p);
 }
 
@@ -172,6 +195,12 @@ int lttng_enumerate_file_descriptors(struct lttng_session *session)
        return 0;
 }
 
+#if 0
+/*
+ * FIXME: we cannot take a mmap_sem while in a RCU read-side critical section
+ * (scheduling in atomic). Normally, the tasklist lock protects this kind of
+ * iteration, but it is not exported to modules.
+ */
 static
 void lttng_enumerate_task_vm_maps(struct lttng_session *session,
                struct task_struct *p)
@@ -212,6 +241,7 @@ int lttng_enumerate_vm_maps(struct lttng_session *session)
        rcu_read_unlock();
        return 0;
 }
+#endif
 
 #ifdef CONFIG_GENERIC_HARDIRQS
 
@@ -234,12 +264,12 @@ void lttng_list_interrupts(struct lttng_session *session)
                        irq_desc_get_chip(desc)->name ? : "unnamed_irq_chip";
 
                local_irq_save(flags);
-               raw_spin_lock(&desc->lock);
+               wrapper_desc_spin_lock(&desc->lock);
                for (action = desc->action; action; action = action->next) {
                        trace_lttng_statedump_interrupt(session,
                                irq, irq_chip_name, action);
                }
-               raw_spin_unlock(&desc->lock);
+               wrapper_desc_spin_unlock(&desc->lock);
                local_irq_restore(flags);
        }
 #undef irq_to_desc
@@ -251,6 +281,33 @@ void list_interrupts(struct lttng_session *session)
 }
 #endif
 
+static
+void lttng_statedump_process_ns(struct lttng_session *session,
+               struct task_struct *p,
+               enum lttng_thread_type type,
+               enum lttng_execution_mode mode,
+               enum lttng_execution_submode submode,
+               enum lttng_process_status status)
+{
+       struct nsproxy *proxy;
+       struct pid_namespace *pid_ns;
+
+       rcu_read_lock();
+       proxy = task_nsproxy(p);
+       if (proxy) {
+               pid_ns = proxy->pid_ns;
+               do {
+                       trace_lttng_statedump_process_state(session,
+                               p, type, mode, submode, status, pid_ns);
+                       pid_ns = pid_ns->parent;
+               } while (pid_ns);
+       } else {
+               trace_lttng_statedump_process_state(session,
+                       p, type, mode, submode, status, NULL);
+       }
+       rcu_read_unlock();
+}
+
 static
 int lttng_enumerate_process_states(struct lttng_session *session)
 {
@@ -300,7 +357,7 @@ int lttng_enumerate_process_states(struct lttng_session *session)
                                type = LTTNG_USER_THREAD;
                        else
                                type = LTTNG_KERNEL_THREAD;
-                       trace_lttng_statedump_process_state(session,
+                       lttng_statedump_process_ns(session,
                                p, type, mode, submode, status);
                        task_unlock(p);
                } while_each_thread(g, p);
@@ -327,7 +384,7 @@ int do_lttng_statedump(struct lttng_session *session)
        trace_lttng_statedump_start(session);
        lttng_enumerate_process_states(session);
        lttng_enumerate_file_descriptors(session);
-       lttng_enumerate_vm_maps(session);
+       /* FIXME lttng_enumerate_vm_maps(session); */
        lttng_list_interrupts(session);
        lttng_enumerate_network_ip_interface(session);
 
@@ -348,7 +405,7 @@ int do_lttng_statedump(struct lttng_session *session)
                schedule_delayed_work_on(cpu, &cpu_work[cpu], 0);
        }
        /* Wait for all threads to run */
-       __wait_event(statedump_wq, (atomic_read(&kernel_threads_to_run) != 0));
+       __wait_event(statedump_wq, (atomic_read(&kernel_threads_to_run) == 0));
        put_online_cpus();
        /* Our work is done */
        printk(KERN_DEBUG "LTT state dump end\n");
This page took 0.025632 seconds and 4 git commands to generate.