From 3e122d843b7d6b1da482574c2d5e1b1e8317eb24 Mon Sep 17 00:00:00 2001 From: compudj Date: Thu, 6 Apr 2006 23:10:53 +0000 Subject: [PATCH] add ltt-modules into svn git-svn-id: http://ltt.polymtl.ca/svn@1757 04897980-b3bd-0310-b5e0-8ef037075253 --- ltt-modules/Makefile | 24 +++ ltt-modules/ltt-control.c | 115 ++++++++++++ ltt-modules/ltt-control.h | 26 +++ ltt-modules/ltt-statedump.c | 351 ++++++++++++++++++++++++++++++++++++ scripts/svn-diff | 20 ++ scripts/svn-diff-script | 10 + 6 files changed, 546 insertions(+) create mode 100644 ltt-modules/Makefile create mode 100644 ltt-modules/ltt-control.c create mode 100644 ltt-modules/ltt-control.h create mode 100644 ltt-modules/ltt-statedump.c create mode 100755 scripts/svn-diff create mode 100755 scripts/svn-diff-script diff --git a/ltt-modules/Makefile b/ltt-modules/Makefile new file mode 100644 index 00000000..0c56ebbb --- /dev/null +++ b/ltt-modules/Makefile @@ -0,0 +1,24 @@ +ifneq ($(KERNELRELEASE),) +ifneq ($(CONFIG_LTT),) + obj-m := ltt-control.o ltt-statedump.o +endif + +else + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) + KERNELRELEASE = $(shell cat $(KERNELDIR)/$(KBUILD_OUTPUT)/include/linux/version.h | sed -n 's/.*UTS_RELEASE.*\"\(.*\)\".*/\1/p') +ifneq ($(INSTALL_MOD_PATH),) + DEPMOD_OPT := -b $(INSTALL_MOD_PATH) +endif + +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules + +modules_install: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install + if [ -f $(KERNELDIR)/$(KBUILD_OUTPUT)/System.map ] ; then /sbin/depmod -ae -F $(KERNELDIR)/$(KBUILD_OUTPUT)/System.map $(DEPMOD_OPT) $(KERNELRELEASE) ; fi + + +clean: + $(MAKE) -C $(KERNELDIR) M=$(PWD) clean +endif diff --git a/ltt-modules/ltt-control.c b/ltt-modules/ltt-control.c new file mode 100644 index 00000000..45b44f0f --- /dev/null +++ b/ltt-modules/ltt-control.c @@ -0,0 +1,115 @@ +/* ltt-control.c + * + * LTT control module over a netlink socket. + * + * Inspired from Relay Apps, by Tom Zanussi and iptables + * + * Copyright 2005 - + * Mathieu Desnoyers + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ltt-control.h" + + +#define LTTCTLM_BASE 0x10 +#define LTTCTLM_CONTROL (LTTCTLM_BASE + 1) /* LTT control message */ + +static struct sock *socket; + +void ltt_control_input(struct sock *sk, int len) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh = NULL; + u8 *payload = NULL; + lttctl_peer_msg_t *msg; + int err; + + printk(KERN_ALERT "ltt-control ltt_control_input\n"); + + while ((skb = skb_dequeue(&sk->sk_receive_queue)) + != NULL) { + + nlh = (struct nlmsghdr *)skb->data; + + if(security_netlink_recv(skb)) { + netlink_ack(skb, nlh, EPERM); + kfree_skb(skb); + continue; + } + + /* process netlink message pointed by skb->data */ + err = EINVAL; + payload = NLMSG_DATA(nlh); + /* process netlink message with header pointed by + * nlh and payload pointed by payload + */ + if(nlh->nlmsg_len != sizeof(lttctl_peer_msg_t) + sizeof(struct nlmsghdr)) { + printk(KERN_ALERT "ltt-control bad message length\n"); + netlink_ack(skb, nlh, EINVAL); + kfree_skb(skb); + continue; + } + msg = (lttctl_peer_msg_t*)payload; + + switch(msg->op) { + case OP_CREATE: + err = ltt_control(LTT_CONTROL_CREATE_TRACE, msg->trace_name, + msg->args); + break; + case OP_DESTROY: + err = ltt_control(LTT_CONTROL_DESTROY_TRACE, msg->trace_name, + msg->args); + break; + case OP_START: + err = ltt_control(LTT_CONTROL_START, msg->trace_name, + msg->args); + break; + case OP_STOP: + err = ltt_control(LTT_CONTROL_STOP, msg->trace_name, + msg->args); + break; + default: + err = EBADRQC; + printk(KERN_INFO "ltt-control invalid operation\n"); + } + netlink_ack(skb, nlh, err); + kfree_skb(skb); + } +} + + +static int ltt_control_init(void) +{ + printk(KERN_ALERT "ltt-control init\n"); + + socket = netlink_kernel_create(NETLINK_LTT, 1, + ltt_control_input, THIS_MODULE); + if(socket == NULL) return -EPERM; + else return 0; +} + +static void ltt_control_exit(void) +{ + printk(KERN_ALERT "ltt-control exit\n"); + + sock_release(socket->sk_socket); +} + + +module_init(ltt_control_init) +module_exit(ltt_control_exit) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mathieu Desnoyers"); +MODULE_DESCRIPTION("Linux Trace Toolkit Controller"); + diff --git a/ltt-modules/ltt-control.h b/ltt-modules/ltt-control.h new file mode 100644 index 00000000..430d5d12 --- /dev/null +++ b/ltt-modules/ltt-control.h @@ -0,0 +1,26 @@ +#ifndef _LTT_CONTROL_H +#define _LTT_CONTROL_H + + +//enum trace_mode { +// TRACE_NORMAL, +// TRACE_FLIGHT +//}; + +enum trace_op { + OP_CREATE, + OP_DESTROY, + OP_START, + OP_STOP, + OP_ALIGN, + OP_NONE +}; + +typedef struct lttctl_peer_msg { + char trace_name[NAME_MAX]; + enum trace_op op; + union ltt_control_args args; +} lttctl_peer_msg_t; + +#endif //_LTT_CONTROL_H + diff --git a/ltt-modules/ltt-statedump.c b/ltt-modules/ltt-statedump.c new file mode 100644 index 00000000..3decd195 --- /dev/null +++ b/ltt-modules/ltt-statedump.c @@ -0,0 +1,351 @@ +/* ltt-state-dump.c + * + * Lunix Trace Toolkit Kernel State Dump + * + * Copyright 2005 - + * Jean-Hugues Deschenes + * + * Changes: + * Eric Clement: add listing of network IP interface + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NB_PROC_CHUNK 20 + +#include +#include + +/* in modules.c */ +extern int ltt_enumerate_modules(void); + +static inline int ltt_enumerate_network_ip_interface(void) +{ + struct net_device *list; + struct in_device *in_dev = NULL; + struct in_ifaddr *ifa = NULL; + + read_lock(&dev_base_lock); + for(list=dev_base; list != NULL; list=list->next) { + + if(list->flags & IFF_UP) { + in_dev = in_dev_get(list); + + if(in_dev) { + for (ifa = in_dev->ifa_list; ifa != NULL; ifa = ifa->ifa_next) { + trace_statedump_enumerate_network_ip_interface(list->name, + ifa->ifa_address, + LTTNG_UP); + } + in_dev_put(in_dev); + } + } else { + trace_statedump_enumerate_network_ip_interface(list->name, + 0, + LTTNG_DOWN); + } + } + read_unlock(&dev_base_lock); + + return 0; +} + +static inline int ltt_enumerate_file_descriptors(void) +{ + struct task_struct * t = &init_task; + unsigned int i; + struct file * filp; + char *tmp = (char*)__get_free_page(GFP_KERNEL), *path; + struct fdtable *fdt; + + /* Enumerate active file descriptors */ + + do { + read_lock(&tasklist_lock); + if(t != &init_task) atomic_dec(&t->usage); + t = next_task(t); + atomic_inc(&t->usage); + read_unlock(&tasklist_lock); + + task_lock(t); + if (t->files) { + spin_lock(&t->files->file_lock); + fdt = files_fdtable(t->files); + for (i=0; i < fdt->max_fds; i++) { + filp = fcheck_files(t->files, i); + if (!filp) + continue; + path = d_path(filp->f_dentry, filp->f_vfsmnt, tmp, PAGE_SIZE); + + /* Make sure we give at least some info */ + if(IS_ERR(path)) + trace_statedump_enumerate_file_descriptors(filp->f_dentry->d_name.name, t->pid, i); + else + trace_statedump_enumerate_file_descriptors(path, t->pid, i); + } + spin_unlock(&t->files->file_lock); + } + task_unlock(t); + + } while( t != &init_task ); + + free_page((unsigned long)tmp); + + return 0; +} + +static inline int ltt_enumerate_vm_maps(void) +{ + struct mm_struct *mm; + struct task_struct * t = &init_task; + struct vm_area_struct * map; + unsigned long ino = 0; + + do { + read_lock(&tasklist_lock); + if(t != &init_task) atomic_dec(&t->usage); + t = next_task(t); + atomic_inc(&t->usage); + read_unlock(&tasklist_lock); + + /* get_task_mm does a task_lock... */ + + mm = get_task_mm(t); + + if (mm) + { + map = mm->mmap; + + if(map) + { + down_read(&mm->mmap_sem); + + while (map) { + if (map->vm_file) { + ino = map->vm_file->f_dentry->d_inode->i_ino; + } else { + ino = 0; + } + + trace_statedump_enumerate_vm_maps(t->pid, (void *)map->vm_start, (void *)map->vm_end, map->vm_flags, map->vm_pgoff << PAGE_SHIFT, ino); + map = map->vm_next; + } + + up_read(&mm->mmap_sem); + } + + mmput(mm); + } + + } while( t != &init_task ); + + return 0; +} + +#if defined( CONFIG_ARM ) +/* defined in arch/arm/kernel/irq.c because of dependency on statically-defined lock & irq_desc */ +int ltt_enumerate_interrupts(void); +#else +static inline int ltt_enumerate_interrupts(void) +{ + unsigned int i; + unsigned long flags = 0; + + /* needs irq_desc */ + + for(i = 0; i < NR_IRQS; i++) + { + struct irqaction * action; + + spin_lock_irqsave(&irq_desc[i].lock, flags); + + + for (action=irq_desc[i].action; action; action = action->next) + trace_statedump_enumerate_interrupts( + irq_desc[i].handler->typename, + action->name, + i ); + + spin_unlock_irqrestore(&irq_desc[i].lock, flags); + } + + return 0; +} +#endif + +static inline int ltt_enumerate_process_states(void) +{ + struct task_struct * t = &init_task; + struct task_struct * p = t; + enum lttng_process_status status; + enum lttng_thread_type type; + enum lttng_execution_mode mode; + enum lttng_execution_submode submode; + + do { + mode = LTTNG_MODE_UNKNOWN; + submode = LTTNG_UNKNOWN; + + read_lock(&tasklist_lock); + if(t != &init_task) { + atomic_dec(&t->usage); + t = next_thread(t); + } + if(t == p) { + t = p = next_task(t); + } + atomic_inc(&t->usage); + read_unlock(&tasklist_lock); + + task_lock(t); + + if(t->exit_state == EXIT_ZOMBIE) + status = LTTNG_ZOMBIE; + else if(t->exit_state == EXIT_DEAD) + status = LTTNG_DEAD; + else if(t->state == TASK_RUNNING) + { + /* Is this a forked child that has not run yet? */ + if( list_empty(&t->run_list) ) + { + status = LTTNG_WAIT_FORK; + } + else + { + /* All tasks are considered as wait_cpu; the viewer will sort out if the task was relly running at this time. */ + status = LTTNG_WAIT_CPU; + } + } + else if(t->state & (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)) + { + /* Task is waiting for something to complete */ + status = LTTNG_WAIT; + } + else + status = LTTNG_UNNAMED; + + submode = LTTNG_NONE; + + + /* Verification of t->mm is to filter out kernel threads; + Viewer will further filter out if a user-space thread was in syscall mode or not */ + if(t->mm) + type = LTTNG_USER_THREAD; + else + type = LTTNG_KERNEL_THREAD; + + trace_statedump_enumerate_process_state(t->pid, t->parent->pid, t->comm, + type, mode, submode, status); + + task_unlock(t); + + } while( t != &init_task ); + + return 0; +} + +void ltt_statedump_work_func(void *sem) +{ + /* Our job is just to release the semaphore so + that we are sure that each CPU has been in syscall + mode before the end of ltt_statedump_thread */ + up((struct semaphore *)sem); +} + +int ltt_statedump_thread(void *data) +{ + struct work_struct *cpu_work; + struct semaphore work_sema4; + int cpu, cpu_index=0; + + printk("ltt_statedump_thread\n"); + + /* Start by firing off a work queue on each CPU. Their sole purpose in life + * is to guarantee that each CPU has been in a state where is was in syscall + * mode (i.e. not in a trap, an IRQ or a soft IRQ) */ + sema_init(&work_sema4, 1 - num_online_cpus()); + cpu_work = (struct work_struct *)kmalloc(sizeof(struct work_struct) * + num_online_cpus(), GFP_KERNEL); + for_each_online_cpu(cpu) + { + INIT_WORK(&cpu_work[cpu_index], ltt_statedump_work_func, &work_sema4); + + /* TODO: verify RC */ + schedule_delayed_work_on(cpu,&cpu_work[cpu_index],0); + cpu_index++; + } + + ltt_enumerate_process_states(); + + ltt_enumerate_file_descriptors(); + + ltt_enumerate_modules(); + + ltt_enumerate_vm_maps(); + + ltt_enumerate_interrupts(); + + ltt_enumerate_network_ip_interface(); + + /* Wait for all work queues to have completed */ + down(&work_sema4); + kfree(cpu_work); + + /* Our work is done */ + printk("trace_statedump_statedump_end\n"); + trace_statedump_statedump_end(); + + do_exit(0); + + return 0; +} + +int ltt_statedump_start(struct ltt_trace_struct *trace) +{ + printk("ltt_statedump_start\n"); + + kthread_run( ltt_statedump_thread, + NULL, + "ltt_statedump"); + + return 0; +} + + +/* Dynamic facility. */ + +static int __init statedump_init(void) +{ + int ret; + printk(KERN_INFO "LTT : ltt-facility-statedump init\n"); + + ret = ltt_module_register(LTT_FUNCTION_STATEDUMP, + ltt_statedump_start,THIS_MODULE); + + return ret; +} + +static void __exit statedump_exit(void) +{ + ltt_module_unregister(LTT_FUNCTION_STATEDUMP); +} + +module_init(statedump_init) +module_exit(statedump_exit) + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jean-Hugues Deschenes"); +MODULE_DESCRIPTION("Linux Trace Toolkit Statedump"); + diff --git a/scripts/svn-diff b/scripts/svn-diff new file mode 100755 index 00000000..09add314 --- /dev/null +++ b/scripts/svn-diff @@ -0,0 +1,20 @@ +#! /bin/sh + +# wrapper for svn diff command +# +# svn always call this with: +# $1 = -u +# $2 = -L +# $3 = left file label +# $4 = -L +# $5 = right file label +# $6 = left file name +# $7 = right file name + +OLDDIR=a +NEWDIR=b + +exec /usr/bin/diff -up "$1" "$2" "$3" "$4" "$5" "$6" "$7" | \ + sed -e "s/^--- \([^\/].*\)/--- $OLDDIR\/\1/" | \ + sed -e "s/^+++ \([^\/].*\)/+++ $NEWDIR\/\1/" + diff --git a/scripts/svn-diff-script b/scripts/svn-diff-script new file mode 100755 index 00000000..ca4f1def --- /dev/null +++ b/scripts/svn-diff-script @@ -0,0 +1,10 @@ +#!/bin/sh + +TRUNKDIR=file:///compudj_dir/kernelrep/trunk/kernel/linux-2.6.12-rc4-mm2 +LTTNGDIR=file:///compudj_dir/kernelrep/branches/mathieu/linux-2.6.12-rc4-mm2 +PATCHDIR=/compudj_dir/work/kernelrep/branches/mathieu + + +svn diff --diff-cmd /home/compudj/bin/svn-diff -x -urpN \ +$TRUNKDIR $LTTNGDIR > \ +$PATCHDIR/$1 -- 2.34.1